Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/native/sun/java2d/opengl/OGLContext.c
38918 views
/*1* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#ifndef HEADLESS2627#include <stdlib.h>28#include <string.h>2930#include "sun_java2d_SunGraphics2D.h"3132#include "jlong.h"33#include "jni_util.h"34#include "OGLContext.h"35#include "OGLRenderQueue.h"36#include "OGLSurfaceData.h"37#include "GraphicsPrimitiveMgr.h"38#include "Region.h"3940/**41* The following methods are implemented in the windowing system (i.e. GLX42* and WGL) source files.43*/44extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo);45extern OGLContext *OGLSD_MakeOGLContextCurrent(JNIEnv *env,46OGLSDOps *srcOps,47OGLSDOps *dstOps);4849/**50* This table contains the standard blending rules (or Porter-Duff compositing51* factors) used in glBlendFunc(), indexed by the rule constants from the52* AlphaComposite class.53*/54OGLBlendRule StdBlendRules[] = {55{ GL_ZERO, GL_ZERO }, /* 0 - Nothing */56{ GL_ZERO, GL_ZERO }, /* 1 - RULE_Clear */57{ GL_ONE, GL_ZERO }, /* 2 - RULE_Src */58{ GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* 3 - RULE_SrcOver */59{ GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* 4 - RULE_DstOver */60{ GL_DST_ALPHA, GL_ZERO }, /* 5 - RULE_SrcIn */61{ GL_ZERO, GL_SRC_ALPHA }, /* 6 - RULE_DstIn */62{ GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* 7 - RULE_SrcOut */63{ GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* 8 - RULE_DstOut */64{ GL_ZERO, GL_ONE }, /* 9 - RULE_Dst */65{ GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*10 - RULE_SrcAtop */66{ GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /*11 - RULE_DstAtop */67{ GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*12 - RULE_AlphaXor*/68};6970/** Evaluates to "front" or "back", depending on the value of buf. */71#define OGLC_ACTIVE_BUFFER_NAME(buf) \72(buf == GL_FRONT || buf == GL_COLOR_ATTACHMENT0_EXT) ? "front" : "back"7374/**75* Initializes the viewport and projection matrix, effectively positioning76* the origin at the top-left corner of the surface. This allows Java 2D77* coordinates to be passed directly to OpenGL, which is typically based on78* a bottom-right coordinate system. This method also sets the appropriate79* read and draw buffers.80*/81static void82OGLContext_SetViewport(OGLSDOps *srcOps, OGLSDOps *dstOps)83{84jint width = dstOps->width;85jint height = dstOps->height;8687J2dTraceLn4(J2D_TRACE_INFO,88"OGLContext_SetViewport: w=%d h=%d read=%s draw=%s",89width, height,90OGLC_ACTIVE_BUFFER_NAME(srcOps->activeBuffer),91OGLC_ACTIVE_BUFFER_NAME(dstOps->activeBuffer));9293// set the viewport and projection matrix94j2d_glViewport(dstOps->xOffset, dstOps->yOffset,95(GLsizei)width, (GLsizei)height);96j2d_glMatrixMode(GL_PROJECTION);97j2d_glLoadIdentity();98j2d_glOrtho(0.0, (GLdouble)width, (GLdouble)height, 0.0, -1.0, 1.0);99100// set the active read and draw buffers101j2d_glReadBuffer(srcOps->activeBuffer);102j2d_glDrawBuffer(dstOps->activeBuffer);103104// set the color mask to enable alpha channel only when necessary105j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);106}107108/**109* Initializes the alpha channel of the current surface so that it contains110* fully opaque alpha values.111*/112static void113OGLContext_InitAlphaChannel()114{115GLboolean scissorEnabled;116117J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitAlphaChannel");118119// it is possible for the scissor test to be enabled at this point;120// if it is, disable it temporarily since it can affect the glClear() op121scissorEnabled = j2d_glIsEnabled(GL_SCISSOR_TEST);122if (scissorEnabled) {123j2d_glDisable(GL_SCISSOR_TEST);124}125126// set the color mask so that we only affect the alpha channel127j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);128129// clear the color buffer so that the alpha channel is fully opaque130j2d_glClearColor(0.0f, 0.0f, 0.0f, 1.0f);131j2d_glClear(GL_COLOR_BUFFER_BIT);132133// restore the color mask (as it was set in OGLContext_SetViewport())134j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);135136// re-enable scissor test, only if it was enabled earlier137if (scissorEnabled) {138j2d_glEnable(GL_SCISSOR_TEST);139}140}141142/**143* Fetches the OGLContext associated with the given destination surface,144* makes the context current for those surfaces, updates the destination145* viewport, and then returns a pointer to the OGLContext.146*/147OGLContext *148OGLContext_SetSurfaces(JNIEnv *env, jlong pSrc, jlong pDst)149{150OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrc);151OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDst);152OGLContext *oglc = NULL;153154J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetSurfaces");155156if (srcOps == NULL || dstOps == NULL) {157J2dRlsTraceLn(J2D_TRACE_ERROR,158"OGLContext_SetSurfaces: ops are null");159return NULL;160}161162J2dTraceLn2(J2D_TRACE_VERBOSE, " srctype=%d dsttype=%d",163srcOps->drawableType, dstOps->drawableType);164165if (dstOps->drawableType == OGLSD_TEXTURE) {166J2dRlsTraceLn(J2D_TRACE_ERROR,167"OGLContext_SetSurfaces: texture cannot be used as destination");168return NULL;169}170171if (dstOps->drawableType == OGLSD_UNDEFINED) {172// initialize the surface as an OGLSD_WINDOW173if (!OGLSD_InitOGLWindow(env, dstOps)) {174J2dRlsTraceLn(J2D_TRACE_ERROR,175"OGLContext_SetSurfaces: could not init OGL window");176return NULL;177}178}179180// make the context current181oglc = OGLSD_MakeOGLContextCurrent(env, srcOps, dstOps);182if (oglc == NULL) {183J2dRlsTraceLn(J2D_TRACE_ERROR,184"OGLContext_SetSurfaces: could not make context current");185return NULL;186}187188// update the viewport189OGLContext_SetViewport(srcOps, dstOps);190191// perform additional one-time initialization, if necessary192if (dstOps->needsInit) {193if (dstOps->isOpaque) {194// in this case we are treating the destination as opaque, but195// to do so, first we need to ensure that the alpha channel196// is filled with fully opaque values (see 6319663)197OGLContext_InitAlphaChannel();198}199dstOps->needsInit = JNI_FALSE;200}201202return oglc;203}204205/**206* Resets the current clip state (disables both scissor and depth tests).207*/208void209OGLContext_ResetClip(OGLContext *oglc)210{211J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetClip");212213RETURN_IF_NULL(oglc);214CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);215216j2d_glDisable(GL_SCISSOR_TEST);217j2d_glDisable(GL_DEPTH_TEST);218}219220/**221* Sets the OpenGL scissor bounds to the provided rectangular clip bounds.222*/223void224OGLContext_SetRectClip(OGLContext *oglc, OGLSDOps *dstOps,225jint x1, jint y1, jint x2, jint y2)226{227jint width = x2 - x1;228jint height = y2 - y1;229230J2dTraceLn4(J2D_TRACE_INFO,231"OGLContext_SetRectClip: x=%d y=%d w=%d h=%d",232x1, y1, width, height);233234RETURN_IF_NULL(dstOps);235RETURN_IF_NULL(oglc);236CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);237238if ((width < 0) || (height < 0)) {239// use an empty scissor rectangle when the region is empty240width = 0;241height = 0;242}243244j2d_glDisable(GL_DEPTH_TEST);245j2d_glEnable(GL_SCISSOR_TEST);246247// the scissor rectangle is specified using the lower-left248// origin of the clip region (in the framebuffer's coordinate249// space), so we must account for the x/y offsets of the250// destination surface251j2d_glScissor(dstOps->xOffset + x1,252dstOps->yOffset + dstOps->height - (y1 + height),253width, height);254}255256/**257* Sets up a complex (shape) clip using the OpenGL depth buffer. This258* method prepares the depth buffer so that the clip Region spans can259* be "rendered" into it. The depth buffer is first cleared, then the260* depth func is setup so that when we render the clip spans,261* nothing is rendered into the color buffer, but for each pixel that would262* be rendered, a non-zero value is placed into that location in the depth263* buffer. With depth test enabled, pixels will only be rendered into the264* color buffer if the corresponding value at that (x,y) location in the265* depth buffer differs from the incoming depth value.266*/267void268OGLContext_BeginShapeClip(OGLContext *oglc)269{270J2dTraceLn(J2D_TRACE_INFO, "OGLContext_BeginShapeClip");271272RETURN_IF_NULL(oglc);273RESET_PREVIOUS_OP();274275j2d_glDisable(GL_SCISSOR_TEST);276277// enable depth test and clear depth buffer so that depth values are at278// their maximum; also set the depth func to GL_ALWAYS so that the279// depth values of the clip spans are forced into the depth buffer280j2d_glEnable(GL_DEPTH_TEST);281j2d_glClearDepth(1.0);282j2d_glClear(GL_DEPTH_BUFFER_BIT);283j2d_glDepthFunc(GL_ALWAYS);284285// disable writes into the color buffer while we set up the clip286j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);287288// save current transform289j2d_glMatrixMode(GL_MODELVIEW);290j2d_glPushMatrix();291292// use identity transform plus slight translation in the z-axis when293// setting the clip spans; this will push the clip spans (which would294// normally be at z=0) to the z=1 plane to give them some depth295j2d_glLoadIdentity();296j2d_glTranslatef(0.0f, 0.0f, 1.0f);297}298299/**300* Finishes setting up the shape clip by resetting the depth func301* so that future rendering operations will once again be written into the302* color buffer (while respecting the clip set up in the depth buffer).303*/304void305OGLContext_EndShapeClip(OGLContext *oglc, OGLSDOps *dstOps)306{307J2dTraceLn(J2D_TRACE_INFO, "OGLContext_EndShapeClip");308309RETURN_IF_NULL(dstOps);310RETURN_IF_NULL(oglc);311RESET_PREVIOUS_OP();312313// restore transform314j2d_glPopMatrix();315316// re-enable writes into the color buffer317j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);318319// enable the depth test so that only fragments within the clip region320// (i.e. those fragments whose z-values are >= the values currently321// stored in the depth buffer) are rendered322j2d_glDepthFunc(GL_GEQUAL);323}324325/**326* Initializes the OpenGL state responsible for applying extra alpha. This327* step is only necessary for any operation that uses glDrawPixels() or328* glCopyPixels() with a non-1.0f extra alpha value. Since the source is329* always premultiplied, we apply the extra alpha value to both alpha and330* color components using GL_*_SCALE.331*/332void333OGLContext_SetExtraAlpha(jfloat ea)334{335J2dTraceLn1(J2D_TRACE_INFO, "OGLContext_SetExtraAlpha: ea=%f", ea);336337j2d_glPixelTransferf(GL_ALPHA_SCALE, ea);338j2d_glPixelTransferf(GL_RED_SCALE, ea);339j2d_glPixelTransferf(GL_GREEN_SCALE, ea);340j2d_glPixelTransferf(GL_BLUE_SCALE, ea);341}342343/**344* Resets all OpenGL compositing state (disables blending and logic345* operations).346*/347void348OGLContext_ResetComposite(OGLContext *oglc)349{350J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetComposite");351352RETURN_IF_NULL(oglc);353CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);354355// disable blending and XOR mode356if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {357j2d_glDisable(GL_BLEND);358} else if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {359j2d_glDisable(GL_COLOR_LOGIC_OP);360j2d_glDisable(GL_ALPHA_TEST);361}362363// set state to default values364oglc->compState = sun_java2d_SunGraphics2D_COMP_ISCOPY;365oglc->extraAlpha = 1.0f;366}367368/**369* Initializes the OpenGL blending state. XOR mode is disabled and the370* appropriate blend functions are setup based on the AlphaComposite rule371* constant.372*/373void374OGLContext_SetAlphaComposite(OGLContext *oglc,375jint rule, jfloat extraAlpha, jint flags)376{377J2dTraceLn1(J2D_TRACE_INFO,378"OGLContext_SetAlphaComposite: flags=%d", flags);379380RETURN_IF_NULL(oglc);381CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);382383// disable XOR mode384if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {385j2d_glDisable(GL_COLOR_LOGIC_OP);386j2d_glDisable(GL_ALPHA_TEST);387}388389// we can safely disable blending when:390// - comp is SrcNoEa or SrcOverNoEa, and391// - the source is opaque392// (turning off blending can have a large positive impact on393// performance)394if ((rule == RULE_Src || rule == RULE_SrcOver) &&395(extraAlpha == 1.0f) &&396(flags & OGLC_SRC_IS_OPAQUE))397{398J2dTraceLn1(J2D_TRACE_VERBOSE,399" disabling alpha comp: rule=%d ea=1.0 src=opq", rule);400j2d_glDisable(GL_BLEND);401} else {402J2dTraceLn2(J2D_TRACE_VERBOSE,403" enabling alpha comp: rule=%d ea=%f", rule, extraAlpha);404j2d_glEnable(GL_BLEND);405j2d_glBlendFunc(StdBlendRules[rule].src, StdBlendRules[rule].dst);406}407408// update state409oglc->compState = sun_java2d_SunGraphics2D_COMP_ALPHA;410oglc->extraAlpha = extraAlpha;411}412413/**414* Initializes the OpenGL logic op state to XOR mode. Blending is disabled415* before enabling logic op mode. The XOR pixel value will be applied416* later in the OGLContext_SetColor() method.417*/418void419OGLContext_SetXorComposite(OGLContext *oglc, jint xorPixel)420{421J2dTraceLn1(J2D_TRACE_INFO,422"OGLContext_SetXorComposite: xorPixel=%08x", xorPixel);423424RETURN_IF_NULL(oglc);425CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);426427// disable blending mode428if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {429j2d_glDisable(GL_BLEND);430}431432// enable XOR mode433j2d_glEnable(GL_COLOR_LOGIC_OP);434j2d_glLogicOp(GL_XOR);435436// set up the alpha test so that we discard transparent fragments (this437// is primarily useful for rendering text in XOR mode)438j2d_glEnable(GL_ALPHA_TEST);439j2d_glAlphaFunc(GL_NOTEQUAL, 0.0f);440441// update state442oglc->compState = sun_java2d_SunGraphics2D_COMP_XOR;443oglc->xorPixel = xorPixel;444oglc->extraAlpha = 1.0f;445}446447/**448* Resets the OpenGL transform state back to the identity matrix.449*/450void451OGLContext_ResetTransform(OGLContext *oglc)452{453J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetTransform");454455RETURN_IF_NULL(oglc);456CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);457458j2d_glMatrixMode(GL_MODELVIEW);459j2d_glLoadIdentity();460}461462/**463* Initializes the OpenGL transform state by setting the modelview transform464* using the given matrix parameters.465*466* REMIND: it may be worthwhile to add serial id to AffineTransform, so we467* could do a quick check to see if the xform has changed since468* last time... a simple object compare won't suffice...469*/470void471OGLContext_SetTransform(OGLContext *oglc,472jdouble m00, jdouble m10,473jdouble m01, jdouble m11,474jdouble m02, jdouble m12)475{476J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetTransform");477478RETURN_IF_NULL(oglc);479CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);480481if (oglc->xformMatrix == NULL) {482size_t arrsize = 16 * sizeof(GLdouble);483oglc->xformMatrix = (GLdouble *)malloc(arrsize);484memset(oglc->xformMatrix, 0, arrsize);485oglc->xformMatrix[10] = 1.0;486oglc->xformMatrix[15] = 1.0;487}488489// copy values from AffineTransform object into native matrix array490oglc->xformMatrix[0] = m00;491oglc->xformMatrix[1] = m10;492oglc->xformMatrix[4] = m01;493oglc->xformMatrix[5] = m11;494oglc->xformMatrix[12] = m02;495oglc->xformMatrix[13] = m12;496497J2dTraceLn3(J2D_TRACE_VERBOSE, " [%lf %lf %lf]",498oglc->xformMatrix[0], oglc->xformMatrix[4],499oglc->xformMatrix[12]);500J2dTraceLn3(J2D_TRACE_VERBOSE, " [%lf %lf %lf]",501oglc->xformMatrix[1], oglc->xformMatrix[5],502oglc->xformMatrix[13]);503504j2d_glMatrixMode(GL_MODELVIEW);505j2d_glLoadMatrixd(oglc->xformMatrix);506}507508/**509* Creates a 2D texture of the given format and dimensions and returns the510* texture object identifier. This method is typically used to create a511* temporary texture for intermediate work, such as in the512* OGLContext_InitBlitTileTexture() method below.513*/514GLuint515OGLContext_CreateBlitTexture(GLenum internalFormat, GLenum pixelFormat,516GLuint width, GLuint height)517{518GLuint texID;519GLint sp, sr, rl, align;520GLclampf priority = 1.0f;521522J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateBlitTexture");523524j2d_glGenTextures(1, &texID);525j2d_glBindTexture(GL_TEXTURE_2D, texID);526j2d_glPrioritizeTextures(1, &texID, &priority);527j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);528j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);529OGLSD_RESET_TEXTURE_WRAP(GL_TEXTURE_2D);530531// save pixel store parameters (since this method could be invoked after532// the caller has already set up its pixel store parameters)533j2d_glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &sp);534j2d_glGetIntegerv(GL_UNPACK_SKIP_ROWS, &sr);535j2d_glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rl);536j2d_glGetIntegerv(GL_UNPACK_ALIGNMENT, &align);537538// set pixel store parameters to default values539j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);540j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);541j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);542j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);543544j2d_glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,545width, height, 0,546pixelFormat, GL_UNSIGNED_BYTE, NULL);547548// restore pixel store parameters549j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sp);550j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sr);551j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, rl);552j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, align);553554return texID;555}556557/**558* Initializes a small texture tile for use with tiled blit operations (see559* OGLBlitLoops.c and OGLMaskBlit.c for usage examples). The texture ID for560* the tile is stored in the given OGLContext. The tile is initially filled561* with garbage values, but the tile is updated as needed (via562* glTexSubImage2D()) with real RGBA values used in tiled blit situations.563* The internal format for the texture is GL_RGBA8, which should be sufficient564* for storing system memory surfaces of any known format (see PixelFormats565* for a list of compatible surface formats).566*/567jboolean568OGLContext_InitBlitTileTexture(OGLContext *oglc)569{570J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitBlitTileTexture");571572oglc->blitTextureID =573OGLContext_CreateBlitTexture(GL_RGBA8, GL_RGBA,574OGLC_BLIT_TILE_SIZE,575OGLC_BLIT_TILE_SIZE);576577return JNI_TRUE;578}579580/**581* Destroys the OpenGL resources associated with the given OGLContext.582* It is required that the native context associated with the OGLContext583* be made current prior to calling this method.584*/585void586OGLContext_DestroyContextResources(OGLContext *oglc)587{588J2dTraceLn(J2D_TRACE_INFO, "OGLContext_DestroyContextResources");589590if (oglc->xformMatrix != NULL) {591free(oglc->xformMatrix);592}593594if (oglc->blitTextureID != 0) {595j2d_glDeleteTextures(1, &oglc->blitTextureID);596}597}598599/**600* Returns JNI_TRUE if the given extension name is available for the current601* GraphicsConfig; JNI_FALSE otherwise. An extension is considered available602* if its identifier string is found amongst the space-delimited GL_EXTENSIONS603* string.604*605* Adapted from the OpenGL Red Book, pg. 506.606*/607jboolean608OGLContext_IsExtensionAvailable(const char *extString, char *extName)609{610jboolean ret = JNI_FALSE;611char *p = (char *)extString;612char *end;613614if (extString == NULL) {615J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsExtensionAvailable");616J2dRlsTraceLn(J2D_TRACE_ERROR,617"OGLContext_IsExtensionAvailable: extension string is null");618return JNI_FALSE;619}620621end = p + strlen(p);622623while (p < end) {624size_t n = strcspn(p, " ");625626if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0)) {627ret = JNI_TRUE;628break;629}630631p += (n + 1);632}633634J2dRlsTraceLn2(J2D_TRACE_INFO,635"OGLContext_IsExtensionAvailable: %s=%s",636extName, ret ? "true" : "false");637638return ret;639}640641/**642* Returns JNI_TRUE only if all of the following conditions are met:643* - the GL_EXT_framebuffer_object extension is available644* - FBO support has been enabled via the system property645* - we can successfully create an FBO with depth capabilities646*/647static jboolean648OGLContext_IsFBObjectExtensionAvailable(JNIEnv *env,649const char *extString)650{651jboolean isFBObjectEnabled = JNI_FALSE;652GLuint fbobjectID, textureID, depthID;653jint width = 1, height = 1;654655J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsFBObjectExtensionAvailable");656657// first see if the fbobject extension is available658if (!OGLContext_IsExtensionAvailable(extString,659"GL_EXT_framebuffer_object"))660{661return JNI_FALSE;662}663664// next see if the depth texture extension is available665if (!OGLContext_IsExtensionAvailable(extString,666"GL_ARB_depth_texture"))667{668return JNI_FALSE;669}670671// next see if the fbobject system property has been enabled672isFBObjectEnabled =673JNU_GetStaticFieldByName(env, NULL,674"sun/java2d/opengl/OGLSurfaceData",675"isFBObjectEnabled", "Z").z;676if (!isFBObjectEnabled) {677J2dRlsTraceLn(J2D_TRACE_INFO,678"OGLContext_IsFBObjectExtensionAvailable: disabled via flag");679return JNI_FALSE;680}681682// finally, create a dummy fbobject with depth capabilities to see683// if this configuration is supported by the drivers/hardware684// (first we initialize a color texture object that will be used to685// construct the dummy fbobject)686j2d_glGenTextures(1, &textureID);687j2d_glBindTexture(GL_TEXTURE_2D, textureID);688j2d_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,689width, height, 0,690GL_RGB, GL_UNSIGNED_BYTE, NULL);691j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);692j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);693694// initialize framebuffer object using color texture created above695if (!OGLSD_InitFBObject(&fbobjectID, &depthID,696textureID, GL_TEXTURE_2D,697width, height))698{699J2dRlsTraceLn(J2D_TRACE_INFO,700"OGLContext_IsFBObjectExtensionAvailable: fbobject unsupported");701j2d_glDeleteTextures(1, &textureID);702return JNI_FALSE;703}704705// delete the temporary resources706j2d_glDeleteTextures(1, &textureID);707j2d_glDeleteRenderbuffersEXT(1, &depthID);708j2d_glDeleteFramebuffersEXT(1, &fbobjectID);709710J2dRlsTraceLn(J2D_TRACE_INFO,711"OGLContext_IsFBObjectExtensionAvailable: fbobject supported");712713return JNI_TRUE;714}715716/**717* Returns JNI_TRUE only if all of the following conditions are met:718* - the GL_ARB_fragment_shader extension is available719* - the LCD text shader codepath has been enabled via the system property720* - the hardware supports the minimum number of texture units721*/722static jboolean723OGLContext_IsLCDShaderSupportAvailable(JNIEnv *env,724jboolean fragShaderAvailable)725{726jboolean isLCDShaderEnabled = JNI_FALSE;727GLint maxTexUnits;728729J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsLCDShaderSupportAvailable");730731// first see if the fragment shader extension is available732if (!fragShaderAvailable) {733return JNI_FALSE;734}735736// next see if the lcdshader system property has been enabled737isLCDShaderEnabled =738JNU_GetStaticFieldByName(env, NULL,739"sun/java2d/opengl/OGLSurfaceData",740"isLCDShaderEnabled", "Z").z;741if (!isLCDShaderEnabled) {742J2dRlsTraceLn(J2D_TRACE_INFO,743"OGLContext_IsLCDShaderSupportAvailable: disabled via flag");744return JNI_FALSE;745}746747// finally, check to see if the hardware supports the required number748// of texture units749j2d_glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &maxTexUnits);750if (maxTexUnits < 2) {751J2dRlsTraceLn1(J2D_TRACE_INFO,752"OGLContext_IsLCDShaderSupportAvailable: not enough tex units (%d)",753maxTexUnits);754}755756J2dRlsTraceLn(J2D_TRACE_INFO,757"OGLContext_IsLCDShaderSupportAvailable: LCD text shader supported");758759return JNI_TRUE;760}761762/**763* Returns JNI_TRUE only if all of the following conditions are met:764* - the GL_ARB_fragment_shader extension is available765* - the BufferedImageOp shader codepath has been enabled via the766* system property767*/768static jboolean769OGLContext_IsBIOpShaderSupportAvailable(JNIEnv *env,770jboolean fragShaderAvailable)771{772jboolean isBIOpShaderEnabled = JNI_FALSE;773774J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsBIOpShaderSupportAvailable");775776// first see if the fragment shader extension is available777if (!fragShaderAvailable) {778return JNI_FALSE;779}780781// next see if the biopshader system property has been enabled782isBIOpShaderEnabled =783JNU_GetStaticFieldByName(env, NULL,784"sun/java2d/opengl/OGLSurfaceData",785"isBIOpShaderEnabled", "Z").z;786if (!isBIOpShaderEnabled) {787J2dRlsTraceLn(J2D_TRACE_INFO,788"OGLContext_IsBIOpShaderSupportAvailable: disabled via flag");789return JNI_FALSE;790}791792/*793* Note: In theory we should probably do some other checks here, like794* linking a sample shader to see if the hardware truly supports our795* shader programs. However, our current BufferedImageOp shaders were796* designed to support first-generation shader-level hardware, so the797* assumption is that if our shaders work on those GPUs, then they'll798* work on newer ones as well. Also, linking a fragment program can799* cost valuable CPU cycles, which is another reason to avoid these800* checks at startup.801*/802803J2dRlsTraceLn(J2D_TRACE_INFO,804"OGLContext_IsBIOpShaderSupportAvailable: BufferedImageOp shader supported");805806return JNI_TRUE;807}808809/**810* Returns JNI_TRUE only if all of the following conditions are met:811* - the GL_ARB_fragment_shader extension is available812* - the Linear/RadialGradientPaint shader codepath has been enabled via the813* system property814*/815static jboolean816OGLContext_IsGradShaderSupportAvailable(JNIEnv *env,817jboolean fragShaderAvailable)818{819jboolean isGradShaderEnabled = JNI_FALSE;820821J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsGradShaderSupportAvailable");822823// first see if the fragment shader extension is available824if (!fragShaderAvailable) {825return JNI_FALSE;826}827828// next see if the gradshader system property has been enabled829isGradShaderEnabled =830JNU_GetStaticFieldByName(env, NULL,831"sun/java2d/opengl/OGLSurfaceData",832"isGradShaderEnabled", "Z").z;833if (!isGradShaderEnabled) {834J2dRlsTraceLn(J2D_TRACE_INFO,835"OGLContext_IsGradShaderSupportAvailable: disabled via flag");836return JNI_FALSE;837}838839J2dRlsTraceLn(J2D_TRACE_INFO,840"OGLContext_IsGradShaderSupportAvailable: Linear/RadialGradientPaint shader supported");841842return JNI_TRUE;843}844845/**846* Checks for the presence of the optional extensions used by847* the Java 2D OpenGL pipeline. The given caps bitfield is updated848* to reflect the availability of these extensions.849*/850void851OGLContext_GetExtensionInfo(JNIEnv *env, jint *caps)852{853jint vcap = OGLC_VENDOR_OTHER;854const char *vendor = (char *)j2d_glGetString(GL_VENDOR);855const char *e = (char *)j2d_glGetString(GL_EXTENSIONS);856jboolean fragShaderAvail =857OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_shader");858859J2dTraceLn(J2D_TRACE_INFO, "OGLContext_GetExtensionInfo");860861*caps |= CAPS_TEXNONSQUARE;862if (OGLContext_IsExtensionAvailable(e, "GL_ARB_multitexture")) {863*caps |= CAPS_MULTITEXTURE;864}865if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_non_power_of_two")){866*caps |= CAPS_TEXNONPOW2;867}868// 6656574: Use of the GL_ARB_texture_rectangle extension by Java 2D869// complicates any third-party libraries that try to interact with870// the OGL pipeline (and we've run into driver bugs in the past related871// to this extension), so for now we will disable its use by default (unless872// forced). We will still make use of the GL_ARB_texture_non_power_of_two873// extension when available, which is the better choice going forward874// anyway.875if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_rectangle") &&876getenv("J2D_OGL_TEXRECT") != NULL)877{878*caps |= CAPS_EXT_TEXRECT;879}880if (OGLContext_IsFBObjectExtensionAvailable(env, e)) {881*caps |= CAPS_EXT_FBOBJECT;882}883if (OGLContext_IsLCDShaderSupportAvailable(env, fragShaderAvail)) {884*caps |= CAPS_EXT_LCD_SHADER | CAPS_PS20;885}886if (OGLContext_IsBIOpShaderSupportAvailable(env, fragShaderAvail)) {887*caps |= CAPS_EXT_BIOP_SHADER | CAPS_PS20;888}889if (OGLContext_IsGradShaderSupportAvailable(env, fragShaderAvail)) {890*caps |= CAPS_EXT_GRAD_SHADER | CAPS_PS20;891}892if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program")) {893// this is an Nvidia board, at least PS 2.0, but we can't894// use the "max instructions" heuristic since GeForce FX895// boards report 1024 even though they're only PS 2.0,896// so we'll check the following, which does imply PS 3.0897if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program2")) {898*caps |= CAPS_PS30;899}900} else {901// for all other boards, we look at the "max instructions"902// count reported by the GL_ARB_fragment_program extension903// as a heuristic for detecting PS 3.0 compatible hardware904if (OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_program")) {905GLint instr;906j2d_glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,907GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &instr);908if (instr > 512) {909*caps |= CAPS_PS30;910}911}912}913if (OGLContext_IsExtensionAvailable(e, "GL_NV_texture_barrier")) {914*caps |= CAPS_EXT_TEXBARRIER;915}916917// stuff vendor descriptor in the upper bits of the caps918if (vendor != NULL) {919if (strncmp(vendor, "ATI", 3) == 0) {920vcap = OGLC_VENDOR_ATI;921} else if (strncmp(vendor, "NVIDIA", 6) == 0) {922vcap = OGLC_VENDOR_NVIDIA;923} else if (strncmp(vendor, "Intel", 5) == 0) {924vcap = OGLC_VENDOR_INTEL;925}926// REMIND: new in 7 - check if needs fixing927*caps |= ((vcap & OGLC_VCAP_MASK) << OGLC_VCAP_OFFSET);928}929930}931932/**933* Returns JNI_TRUE if the given GL_VERSION string meets the minimum934* requirements (>= 1.2); JNI_FALSE otherwise.935*/936jboolean937OGLContext_IsVersionSupported(const unsigned char *versionstr)938{939J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsVersionSupported");940941if (versionstr == NULL) {942J2dRlsTraceLn(J2D_TRACE_ERROR,943"OGLContext_IsVersionSupported: version string is null");944return JNI_FALSE;945}946947// note that this check allows for OpenGL 2.x948return ((versionstr[0] == '1' && versionstr[2] >= '2') ||949(versionstr[0] >= '2'));950}951952/**953* Compiles and links the given fragment shader program. If954* successful, this function returns a handle to the newly created shader955* program; otherwise returns 0.956*/957GLhandleARB958OGLContext_CreateFragmentProgram(const char *fragmentShaderSource)959{960GLhandleARB fragmentShader, fragmentProgram;961GLint success;962int infoLogLength = 0;963964J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateFragmentProgram");965966// create the shader object and compile the shader source code967fragmentShader = j2d_glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);968j2d_glShaderSourceARB(fragmentShader, 1, &fragmentShaderSource, NULL);969j2d_glCompileShaderARB(fragmentShader);970j2d_glGetObjectParameterivARB(fragmentShader,971GL_OBJECT_COMPILE_STATUS_ARB,972&success);973974// print the compiler messages, if necessary975j2d_glGetObjectParameterivARB(fragmentShader,976GL_OBJECT_INFO_LOG_LENGTH_ARB,977&infoLogLength);978if (infoLogLength > 1) {979char infoLog[1024];980j2d_glGetInfoLogARB(fragmentShader, 1024, NULL, infoLog);981J2dRlsTraceLn2(J2D_TRACE_WARNING,982"OGLContext_CreateFragmentProgram: compiler msg (%d):\n%s",983infoLogLength, infoLog);984}985986if (!success) {987J2dRlsTraceLn(J2D_TRACE_ERROR,988"OGLContext_CreateFragmentProgram: error compiling shader");989j2d_glDeleteObjectARB(fragmentShader);990return 0;991}992993// create the program object and attach it to the shader994fragmentProgram = j2d_glCreateProgramObjectARB();995j2d_glAttachObjectARB(fragmentProgram, fragmentShader);996997// it is now safe to delete the shader object998j2d_glDeleteObjectARB(fragmentShader);9991000// link the program1001j2d_glLinkProgramARB(fragmentProgram);1002j2d_glGetObjectParameterivARB(fragmentProgram,1003GL_OBJECT_LINK_STATUS_ARB,1004&success);10051006// print the linker messages, if necessary1007j2d_glGetObjectParameterivARB(fragmentProgram,1008GL_OBJECT_INFO_LOG_LENGTH_ARB,1009&infoLogLength);1010if (infoLogLength > 1) {1011char infoLog[1024];1012j2d_glGetInfoLogARB(fragmentProgram, 1024, NULL, infoLog);1013J2dRlsTraceLn2(J2D_TRACE_WARNING,1014"OGLContext_CreateFragmentProgram: linker msg (%d):\n%s",1015infoLogLength, infoLog);1016}10171018if (!success) {1019J2dRlsTraceLn(J2D_TRACE_ERROR,1020"OGLContext_CreateFragmentProgram: error linking shader");1021j2d_glDeleteObjectARB(fragmentProgram);1022return 0;1023}10241025return fragmentProgram;1026}10271028/*1029* Class: sun_java2d_opengl_OGLContext1030* Method: getOGLIdString1031* Signature: ()Ljava/lang/String;1032*/1033JNIEXPORT jstring JNICALL Java_sun_java2d_opengl_OGLContext_getOGLIdString1034(JNIEnv *env, jclass oglcc)1035{1036char *vendor, *renderer, *version;1037char *pAdapterId;1038jobject ret = NULL;1039int len;10401041J2dTraceLn(J2D_TRACE_INFO, "OGLContext_getOGLIdString");10421043vendor = (char*)j2d_glGetString(GL_VENDOR);1044if (vendor == NULL) {1045vendor = "Unknown Vendor";1046}1047renderer = (char*)j2d_glGetString(GL_RENDERER);1048if (renderer == NULL) {1049renderer = "Unknown Renderer";1050}1051version = (char*)j2d_glGetString(GL_VERSION);1052if (version == NULL) {1053version = "unknown version";1054}10551056// 'vendor renderer (version)0'1057len = strlen(vendor) + 1 + strlen(renderer) + 1 + 1+strlen(version)+1 + 1;1058pAdapterId = malloc(len);1059if (pAdapterId != NULL) {10601061jio_snprintf(pAdapterId, len, "%s %s (%s)", vendor, renderer, version);10621063J2dTraceLn1(J2D_TRACE_VERBOSE, " id=%s", pAdapterId);10641065ret = JNU_NewStringPlatform(env, pAdapterId);10661067free(pAdapterId);1068}10691070return ret;1071}10721073#endif /* !HEADLESS */107410751076