Path: blob/master/src/java.desktop/share/native/common/java2d/opengl/OGLContext.c
41159 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#include "jvm.h"4142/**43* The following methods are implemented in the windowing system (i.e. GLX44* and WGL) source files.45*/46extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo);47extern OGLContext *OGLSD_MakeOGLContextCurrent(JNIEnv *env,48OGLSDOps *srcOps,49OGLSDOps *dstOps);5051/**52* This table contains the standard blending rules (or Porter-Duff compositing53* factors) used in glBlendFunc(), indexed by the rule constants from the54* AlphaComposite class.55*/56OGLBlendRule StdBlendRules[] = {57{ GL_ZERO, GL_ZERO }, /* 0 - Nothing */58{ GL_ZERO, GL_ZERO }, /* 1 - RULE_Clear */59{ GL_ONE, GL_ZERO }, /* 2 - RULE_Src */60{ GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* 3 - RULE_SrcOver */61{ GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* 4 - RULE_DstOver */62{ GL_DST_ALPHA, GL_ZERO }, /* 5 - RULE_SrcIn */63{ GL_ZERO, GL_SRC_ALPHA }, /* 6 - RULE_DstIn */64{ GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* 7 - RULE_SrcOut */65{ GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* 8 - RULE_DstOut */66{ GL_ZERO, GL_ONE }, /* 9 - RULE_Dst */67{ GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*10 - RULE_SrcAtop */68{ GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /*11 - RULE_DstAtop */69{ GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*12 - RULE_AlphaXor*/70};7172/** Evaluates to "front" or "back", depending on the value of buf. */73#define OGLC_ACTIVE_BUFFER_NAME(buf) \74(buf == GL_FRONT || buf == GL_COLOR_ATTACHMENT0_EXT) ? "front" : "back"7576/**77* Initializes the viewport and projection matrix, effectively positioning78* the origin at the top-left corner of the surface. This allows Java 2D79* coordinates to be passed directly to OpenGL, which is typically based on80* a bottom-right coordinate system. This method also sets the appropriate81* read and draw buffers.82*/83static void84OGLContext_SetViewport(OGLSDOps *srcOps, OGLSDOps *dstOps)85{86jint width = dstOps->width;87jint height = dstOps->height;8889J2dTraceLn4(J2D_TRACE_INFO,90"OGLContext_SetViewport: w=%d h=%d read=%s draw=%s",91width, height,92OGLC_ACTIVE_BUFFER_NAME(srcOps->activeBuffer),93OGLC_ACTIVE_BUFFER_NAME(dstOps->activeBuffer));9495// set the viewport and projection matrix96j2d_glViewport(dstOps->xOffset, dstOps->yOffset,97(GLsizei)width, (GLsizei)height);98j2d_glMatrixMode(GL_PROJECTION);99j2d_glLoadIdentity();100j2d_glOrtho(0.0, (GLdouble)width, (GLdouble)height, 0.0, -1.0, 1.0);101102// set the active read and draw buffers103j2d_glReadBuffer(srcOps->activeBuffer);104j2d_glDrawBuffer(dstOps->activeBuffer);105106// set the color mask to enable alpha channel only when necessary107j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);108}109110/**111* Initializes the alpha channel of the current surface so that it contains112* fully opaque alpha values.113*/114static void115OGLContext_InitAlphaChannel()116{117GLboolean scissorEnabled;118119J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitAlphaChannel");120121// it is possible for the scissor test to be enabled at this point;122// if it is, disable it temporarily since it can affect the glClear() op123scissorEnabled = j2d_glIsEnabled(GL_SCISSOR_TEST);124if (scissorEnabled) {125j2d_glDisable(GL_SCISSOR_TEST);126}127128// set the color mask so that we only affect the alpha channel129j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);130131// clear the color buffer so that the alpha channel is fully opaque132j2d_glClearColor(0.0f, 0.0f, 0.0f, 1.0f);133j2d_glClear(GL_COLOR_BUFFER_BIT);134135// restore the color mask (as it was set in OGLContext_SetViewport())136j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);137138// re-enable scissor test, only if it was enabled earlier139if (scissorEnabled) {140j2d_glEnable(GL_SCISSOR_TEST);141}142}143144/**145* Fetches the OGLContext associated with the given destination surface,146* makes the context current for those surfaces, updates the destination147* viewport, and then returns a pointer to the OGLContext.148*/149OGLContext *150OGLContext_SetSurfaces(JNIEnv *env, jlong pSrc, jlong pDst)151{152OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrc);153OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDst);154OGLContext *oglc = NULL;155156J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetSurfaces");157158if (srcOps == NULL || dstOps == NULL) {159J2dRlsTraceLn(J2D_TRACE_ERROR,160"OGLContext_SetSurfaces: ops are null");161return NULL;162}163164J2dTraceLn2(J2D_TRACE_VERBOSE, " srctype=%d dsttype=%d",165srcOps->drawableType, dstOps->drawableType);166167if (dstOps->drawableType == OGLSD_TEXTURE) {168J2dRlsTraceLn(J2D_TRACE_ERROR,169"OGLContext_SetSurfaces: texture cannot be used as destination");170return NULL;171}172173if (dstOps->drawableType == OGLSD_UNDEFINED) {174// initialize the surface as an OGLSD_WINDOW175if (!OGLSD_InitOGLWindow(env, dstOps)) {176J2dRlsTraceLn(J2D_TRACE_ERROR,177"OGLContext_SetSurfaces: could not init OGL window");178return NULL;179}180}181182// make the context current183oglc = OGLSD_MakeOGLContextCurrent(env, srcOps, dstOps);184if (oglc == NULL) {185J2dRlsTraceLn(J2D_TRACE_ERROR,186"OGLContext_SetSurfaces: could not make context current");187return NULL;188}189190// update the viewport191OGLContext_SetViewport(srcOps, dstOps);192193// perform additional one-time initialization, if necessary194if (dstOps->needsInit) {195if (dstOps->isOpaque) {196// in this case we are treating the destination as opaque, but197// to do so, first we need to ensure that the alpha channel198// is filled with fully opaque values (see 6319663)199OGLContext_InitAlphaChannel();200}201dstOps->needsInit = JNI_FALSE;202}203204return oglc;205}206207/**208* Resets the current clip state (disables both scissor and depth tests).209*/210void211OGLContext_ResetClip(OGLContext *oglc)212{213J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetClip");214215RETURN_IF_NULL(oglc);216CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);217218j2d_glDisable(GL_SCISSOR_TEST);219j2d_glDisable(GL_DEPTH_TEST);220}221222/**223* Sets the OpenGL scissor bounds to the provided rectangular clip bounds.224*/225void226OGLContext_SetRectClip(OGLContext *oglc, OGLSDOps *dstOps,227jint x1, jint y1, jint x2, jint y2)228{229jint width = x2 - x1;230jint height = y2 - y1;231232J2dTraceLn4(J2D_TRACE_INFO,233"OGLContext_SetRectClip: x=%d y=%d w=%d h=%d",234x1, y1, width, height);235236RETURN_IF_NULL(dstOps);237RETURN_IF_NULL(oglc);238CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);239240if ((width < 0) || (height < 0)) {241// use an empty scissor rectangle when the region is empty242width = 0;243height = 0;244}245246j2d_glDisable(GL_DEPTH_TEST);247j2d_glEnable(GL_SCISSOR_TEST);248249// the scissor rectangle is specified using the lower-left250// origin of the clip region (in the framebuffer's coordinate251// space), so we must account for the x/y offsets of the252// destination surface253j2d_glScissor(dstOps->xOffset + x1,254dstOps->yOffset + dstOps->height - (y1 + height),255width, height);256}257258/**259* Sets up a complex (shape) clip using the OpenGL depth buffer. This260* method prepares the depth buffer so that the clip Region spans can261* be "rendered" into it. The depth buffer is first cleared, then the262* depth func is setup so that when we render the clip spans,263* nothing is rendered into the color buffer, but for each pixel that would264* be rendered, a non-zero value is placed into that location in the depth265* buffer. With depth test enabled, pixels will only be rendered into the266* color buffer if the corresponding value at that (x,y) location in the267* depth buffer differs from the incoming depth value.268*/269void270OGLContext_BeginShapeClip(OGLContext *oglc)271{272J2dTraceLn(J2D_TRACE_INFO, "OGLContext_BeginShapeClip");273274RETURN_IF_NULL(oglc);275RESET_PREVIOUS_OP();276277j2d_glDisable(GL_SCISSOR_TEST);278279// enable depth test and clear depth buffer so that depth values are at280// their maximum; also set the depth func to GL_ALWAYS so that the281// depth values of the clip spans are forced into the depth buffer282j2d_glEnable(GL_DEPTH_TEST);283j2d_glClearDepth(1.0);284j2d_glClear(GL_DEPTH_BUFFER_BIT);285j2d_glDepthFunc(GL_ALWAYS);286287// disable writes into the color buffer while we set up the clip288j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);289290// save current transform291j2d_glMatrixMode(GL_MODELVIEW);292j2d_glPushMatrix();293294// use identity transform plus slight translation in the z-axis when295// setting the clip spans; this will push the clip spans (which would296// normally be at z=0) to the z=1 plane to give them some depth297j2d_glLoadIdentity();298j2d_glTranslatef(0.0f, 0.0f, 1.0f);299}300301/**302* Finishes setting up the shape clip by resetting the depth func303* so that future rendering operations will once again be written into the304* color buffer (while respecting the clip set up in the depth buffer).305*/306void307OGLContext_EndShapeClip(OGLContext *oglc, OGLSDOps *dstOps)308{309J2dTraceLn(J2D_TRACE_INFO, "OGLContext_EndShapeClip");310311RETURN_IF_NULL(dstOps);312RETURN_IF_NULL(oglc);313RESET_PREVIOUS_OP();314315// restore transform316j2d_glPopMatrix();317318// re-enable writes into the color buffer319j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);320321// enable the depth test so that only fragments within the clip region322// (i.e. those fragments whose z-values are >= the values currently323// stored in the depth buffer) are rendered324j2d_glDepthFunc(GL_GEQUAL);325}326327/**328* Initializes the OpenGL state responsible for applying extra alpha. This329* step is only necessary for any operation that uses glDrawPixels() or330* glCopyPixels() with a non-1.0f extra alpha value. Since the source is331* always premultiplied, we apply the extra alpha value to both alpha and332* color components using GL_*_SCALE.333*/334void335OGLContext_SetExtraAlpha(jfloat ea)336{337J2dTraceLn1(J2D_TRACE_INFO, "OGLContext_SetExtraAlpha: ea=%f", ea);338339j2d_glPixelTransferf(GL_ALPHA_SCALE, ea);340j2d_glPixelTransferf(GL_RED_SCALE, ea);341j2d_glPixelTransferf(GL_GREEN_SCALE, ea);342j2d_glPixelTransferf(GL_BLUE_SCALE, ea);343}344345/**346* Resets all OpenGL compositing state (disables blending and logic347* operations).348*/349void350OGLContext_ResetComposite(OGLContext *oglc)351{352J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetComposite");353354RETURN_IF_NULL(oglc);355CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);356357// disable blending and XOR mode358if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {359j2d_glDisable(GL_BLEND);360} else if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {361j2d_glDisable(GL_COLOR_LOGIC_OP);362j2d_glDisable(GL_ALPHA_TEST);363}364365// set state to default values366oglc->compState = sun_java2d_SunGraphics2D_COMP_ISCOPY;367oglc->extraAlpha = 1.0f;368}369370/**371* Initializes the OpenGL blending state. XOR mode is disabled and the372* appropriate blend functions are setup based on the AlphaComposite rule373* constant.374*/375void376OGLContext_SetAlphaComposite(OGLContext *oglc,377jint rule, jfloat extraAlpha, jint flags)378{379J2dTraceLn1(J2D_TRACE_INFO,380"OGLContext_SetAlphaComposite: flags=%d", flags);381382RETURN_IF_NULL(oglc);383CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);384385// disable XOR mode386if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {387j2d_glDisable(GL_COLOR_LOGIC_OP);388j2d_glDisable(GL_ALPHA_TEST);389}390391// we can safely disable blending when:392// - comp is SrcNoEa or SrcOverNoEa, and393// - the source is opaque394// (turning off blending can have a large positive impact on395// performance)396if ((rule == RULE_Src || rule == RULE_SrcOver) &&397(extraAlpha == 1.0f) &&398(flags & OGLC_SRC_IS_OPAQUE))399{400J2dTraceLn1(J2D_TRACE_VERBOSE,401" disabling alpha comp: rule=%d ea=1.0 src=opq", rule);402j2d_glDisable(GL_BLEND);403} else {404J2dTraceLn2(J2D_TRACE_VERBOSE,405" enabling alpha comp: rule=%d ea=%f", rule, extraAlpha);406j2d_glEnable(GL_BLEND);407j2d_glBlendFunc(StdBlendRules[rule].src, StdBlendRules[rule].dst);408}409410// update state411oglc->compState = sun_java2d_SunGraphics2D_COMP_ALPHA;412oglc->extraAlpha = extraAlpha;413}414415/**416* Initializes the OpenGL logic op state to XOR mode. Blending is disabled417* before enabling logic op mode. The XOR pixel value will be applied418* later in the OGLContext_SetColor() method.419*/420void421OGLContext_SetXorComposite(OGLContext *oglc, jint xorPixel)422{423J2dTraceLn1(J2D_TRACE_INFO,424"OGLContext_SetXorComposite: xorPixel=%08x", xorPixel);425426RETURN_IF_NULL(oglc);427CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);428429// disable blending mode430if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {431j2d_glDisable(GL_BLEND);432}433434// enable XOR mode435j2d_glEnable(GL_COLOR_LOGIC_OP);436j2d_glLogicOp(GL_XOR);437438// set up the alpha test so that we discard transparent fragments (this439// is primarily useful for rendering text in XOR mode)440j2d_glEnable(GL_ALPHA_TEST);441j2d_glAlphaFunc(GL_NOTEQUAL, 0.0f);442443// update state444oglc->compState = sun_java2d_SunGraphics2D_COMP_XOR;445oglc->xorPixel = xorPixel;446oglc->extraAlpha = 1.0f;447}448449/**450* Resets the OpenGL transform state back to the identity matrix.451*/452void453OGLContext_ResetTransform(OGLContext *oglc)454{455J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetTransform");456457RETURN_IF_NULL(oglc);458CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);459460j2d_glMatrixMode(GL_MODELVIEW);461j2d_glLoadIdentity();462}463464/**465* Initializes the OpenGL transform state by setting the modelview transform466* using the given matrix parameters.467*468* REMIND: it may be worthwhile to add serial id to AffineTransform, so we469* could do a quick check to see if the xform has changed since470* last time... a simple object compare won't suffice...471*/472void473OGLContext_SetTransform(OGLContext *oglc,474jdouble m00, jdouble m10,475jdouble m01, jdouble m11,476jdouble m02, jdouble m12)477{478J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetTransform");479480RETURN_IF_NULL(oglc);481CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);482483if (oglc->xformMatrix == NULL) {484size_t arrsize = 16 * sizeof(GLdouble);485oglc->xformMatrix = (GLdouble *)malloc(arrsize);486memset(oglc->xformMatrix, 0, arrsize);487oglc->xformMatrix[10] = 1.0;488oglc->xformMatrix[15] = 1.0;489}490491// copy values from AffineTransform object into native matrix array492oglc->xformMatrix[0] = m00;493oglc->xformMatrix[1] = m10;494oglc->xformMatrix[4] = m01;495oglc->xformMatrix[5] = m11;496oglc->xformMatrix[12] = m02;497oglc->xformMatrix[13] = m12;498499J2dTraceLn3(J2D_TRACE_VERBOSE, " [%lf %lf %lf]",500oglc->xformMatrix[0], oglc->xformMatrix[4],501oglc->xformMatrix[12]);502J2dTraceLn3(J2D_TRACE_VERBOSE, " [%lf %lf %lf]",503oglc->xformMatrix[1], oglc->xformMatrix[5],504oglc->xformMatrix[13]);505506j2d_glMatrixMode(GL_MODELVIEW);507j2d_glLoadMatrixd(oglc->xformMatrix);508}509510/**511* Creates a 2D texture of the given format and dimensions and returns the512* texture object identifier. This method is typically used to create a513* temporary texture for intermediate work, such as in the514* OGLContext_InitBlitTileTexture() method below.515*/516GLuint517OGLContext_CreateBlitTexture(GLenum internalFormat, GLenum pixelFormat,518GLuint width, GLuint height)519{520GLuint texID;521GLint sp, sr, rl, align;522GLclampf priority = 1.0f;523524J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateBlitTexture");525526j2d_glGenTextures(1, &texID);527j2d_glBindTexture(GL_TEXTURE_2D, texID);528j2d_glPrioritizeTextures(1, &texID, &priority);529j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);530j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);531OGLSD_RESET_TEXTURE_WRAP(GL_TEXTURE_2D);532533// save pixel store parameters (since this method could be invoked after534// the caller has already set up its pixel store parameters)535j2d_glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &sp);536j2d_glGetIntegerv(GL_UNPACK_SKIP_ROWS, &sr);537j2d_glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rl);538j2d_glGetIntegerv(GL_UNPACK_ALIGNMENT, &align);539540// set pixel store parameters to default values541j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);542j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);543j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);544j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);545546j2d_glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,547width, height, 0,548pixelFormat, GL_UNSIGNED_BYTE, NULL);549550// restore pixel store parameters551j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sp);552j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sr);553j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, rl);554j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, align);555556return texID;557}558559/**560* Initializes a small texture tile for use with tiled blit operations (see561* OGLBlitLoops.c and OGLMaskBlit.c for usage examples). The texture ID for562* the tile is stored in the given OGLContext. The tile is initially filled563* with garbage values, but the tile is updated as needed (via564* glTexSubImage2D()) with real RGBA values used in tiled blit situations.565* The internal format for the texture is GL_RGBA8, which should be sufficient566* for storing system memory surfaces of any known format (see PixelFormats567* for a list of compatible surface formats).568*/569jboolean570OGLContext_InitBlitTileTexture(OGLContext *oglc)571{572J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitBlitTileTexture");573574oglc->blitTextureID =575OGLContext_CreateBlitTexture(GL_RGBA8, GL_RGBA,576OGLC_BLIT_TILE_SIZE,577OGLC_BLIT_TILE_SIZE);578579return JNI_TRUE;580}581582/**583* Destroys the OpenGL resources associated with the given OGLContext.584* It is required that the native context associated with the OGLContext585* be made current prior to calling this method.586*/587void588OGLContext_DestroyContextResources(OGLContext *oglc)589{590J2dTraceLn(J2D_TRACE_INFO, "OGLContext_DestroyContextResources");591592if (oglc->xformMatrix != NULL) {593free(oglc->xformMatrix);594}595596if (oglc->blitTextureID != 0) {597j2d_glDeleteTextures(1, &oglc->blitTextureID);598}599}600601/**602* Returns JNI_TRUE if the given extension name is available for the current603* GraphicsConfig; JNI_FALSE otherwise. An extension is considered available604* if its identifier string is found amongst the space-delimited GL_EXTENSIONS605* string.606*607* Adapted from the OpenGL Red Book, pg. 506.608*/609jboolean610OGLContext_IsExtensionAvailable(const char *extString, char *extName)611{612jboolean ret = JNI_FALSE;613char *p = (char *)extString;614char *end;615616if (extString == NULL) {617J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsExtensionAvailable");618J2dRlsTraceLn(J2D_TRACE_ERROR,619"OGLContext_IsExtensionAvailable: extension string is null");620return JNI_FALSE;621}622623end = p + strlen(p);624625while (p < end) {626size_t n = strcspn(p, " ");627628if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0)) {629ret = JNI_TRUE;630break;631}632633p += (n + 1);634}635636J2dRlsTraceLn2(J2D_TRACE_INFO,637"OGLContext_IsExtensionAvailable: %s=%s",638extName, ret ? "true" : "false");639640return ret;641}642643/**644* Returns JNI_TRUE only if all of the following conditions are met:645* - the GL_EXT_framebuffer_object extension is available646* - FBO support has been enabled via the system property647* - we can successfully create an FBO with depth capabilities648*/649static jboolean650OGLContext_IsFBObjectExtensionAvailable(JNIEnv *env,651const char *extString)652{653jboolean isFBObjectEnabled = JNI_FALSE;654GLuint fbobjectID, textureID, depthID;655jint width = 1, height = 1;656657J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsFBObjectExtensionAvailable");658659// first see if the fbobject extension is available660if (!OGLContext_IsExtensionAvailable(extString,661"GL_EXT_framebuffer_object"))662{663return JNI_FALSE;664}665666// next see if the depth texture extension is available667if (!OGLContext_IsExtensionAvailable(extString,668"GL_ARB_depth_texture"))669{670return JNI_FALSE;671}672673// next see if the fbobject system property has been enabled674isFBObjectEnabled =675JNU_GetStaticFieldByName(env, NULL,676"sun/java2d/opengl/OGLSurfaceData",677"isFBObjectEnabled", "Z").z;678if (!isFBObjectEnabled) {679J2dRlsTraceLn(J2D_TRACE_INFO,680"OGLContext_IsFBObjectExtensionAvailable: disabled via flag");681return JNI_FALSE;682}683684// finally, create a dummy fbobject with depth capabilities to see685// if this configuration is supported by the drivers/hardware686// (first we initialize a color texture object that will be used to687// construct the dummy fbobject)688j2d_glGenTextures(1, &textureID);689j2d_glBindTexture(GL_TEXTURE_2D, textureID);690j2d_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,691width, height, 0,692GL_RGB, GL_UNSIGNED_BYTE, NULL);693j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);694j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);695696// initialize framebuffer object using color texture created above697if (!OGLSD_InitFBObject(&fbobjectID, &depthID,698textureID, GL_TEXTURE_2D,699width, height))700{701J2dRlsTraceLn(J2D_TRACE_INFO,702"OGLContext_IsFBObjectExtensionAvailable: fbobject unsupported");703j2d_glDeleteTextures(1, &textureID);704return JNI_FALSE;705}706707// delete the temporary resources708j2d_glDeleteTextures(1, &textureID);709j2d_glDeleteRenderbuffersEXT(1, &depthID);710j2d_glDeleteFramebuffersEXT(1, &fbobjectID);711712J2dRlsTraceLn(J2D_TRACE_INFO,713"OGLContext_IsFBObjectExtensionAvailable: fbobject supported");714715return JNI_TRUE;716}717718/**719* Returns JNI_TRUE only if all of the following conditions are met:720* - the GL_ARB_fragment_shader extension is available721* - the LCD text shader codepath has been enabled via the system property722* - the hardware supports the minimum number of texture units723*/724static jboolean725OGLContext_IsLCDShaderSupportAvailable(JNIEnv *env,726jboolean fragShaderAvailable)727{728jboolean isLCDShaderEnabled = JNI_FALSE;729GLint maxTexUnits;730731J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsLCDShaderSupportAvailable");732733// first see if the fragment shader extension is available734if (!fragShaderAvailable) {735return JNI_FALSE;736}737738// next see if the lcdshader system property has been enabled739isLCDShaderEnabled =740JNU_GetStaticFieldByName(env, NULL,741"sun/java2d/opengl/OGLSurfaceData",742"isLCDShaderEnabled", "Z").z;743if (!isLCDShaderEnabled) {744J2dRlsTraceLn(J2D_TRACE_INFO,745"OGLContext_IsLCDShaderSupportAvailable: disabled via flag");746return JNI_FALSE;747}748749// finally, check to see if the hardware supports the required number750// of texture units751j2d_glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &maxTexUnits);752if (maxTexUnits < 2) {753J2dRlsTraceLn1(J2D_TRACE_INFO,754"OGLContext_IsLCDShaderSupportAvailable: not enough tex units (%d)",755maxTexUnits);756}757758J2dRlsTraceLn(J2D_TRACE_INFO,759"OGLContext_IsLCDShaderSupportAvailable: LCD text shader supported");760761return JNI_TRUE;762}763764/**765* Returns JNI_TRUE only if all of the following conditions are met:766* - the GL_ARB_fragment_shader extension is available767* - the BufferedImageOp shader codepath has been enabled via the768* system property769*/770static jboolean771OGLContext_IsBIOpShaderSupportAvailable(JNIEnv *env,772jboolean fragShaderAvailable)773{774jboolean isBIOpShaderEnabled = JNI_FALSE;775776J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsBIOpShaderSupportAvailable");777778// first see if the fragment shader extension is available779if (!fragShaderAvailable) {780return JNI_FALSE;781}782783// next see if the biopshader system property has been enabled784isBIOpShaderEnabled =785JNU_GetStaticFieldByName(env, NULL,786"sun/java2d/opengl/OGLSurfaceData",787"isBIOpShaderEnabled", "Z").z;788if (!isBIOpShaderEnabled) {789J2dRlsTraceLn(J2D_TRACE_INFO,790"OGLContext_IsBIOpShaderSupportAvailable: disabled via flag");791return JNI_FALSE;792}793794/*795* Note: In theory we should probably do some other checks here, like796* linking a sample shader to see if the hardware truly supports our797* shader programs. However, our current BufferedImageOp shaders were798* designed to support first-generation shader-level hardware, so the799* assumption is that if our shaders work on those GPUs, then they'll800* work on newer ones as well. Also, linking a fragment program can801* cost valuable CPU cycles, which is another reason to avoid these802* checks at startup.803*/804805J2dRlsTraceLn(J2D_TRACE_INFO,806"OGLContext_IsBIOpShaderSupportAvailable: BufferedImageOp shader supported");807808return JNI_TRUE;809}810811/**812* Returns JNI_TRUE only if all of the following conditions are met:813* - the GL_ARB_fragment_shader extension is available814* - the Linear/RadialGradientPaint shader codepath has been enabled via the815* system property816*/817static jboolean818OGLContext_IsGradShaderSupportAvailable(JNIEnv *env,819jboolean fragShaderAvailable)820{821jboolean isGradShaderEnabled = JNI_FALSE;822823J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsGradShaderSupportAvailable");824825// first see if the fragment shader extension is available826if (!fragShaderAvailable) {827return JNI_FALSE;828}829830// next see if the gradshader system property has been enabled831isGradShaderEnabled =832JNU_GetStaticFieldByName(env, NULL,833"sun/java2d/opengl/OGLSurfaceData",834"isGradShaderEnabled", "Z").z;835if (!isGradShaderEnabled) {836J2dRlsTraceLn(J2D_TRACE_INFO,837"OGLContext_IsGradShaderSupportAvailable: disabled via flag");838return JNI_FALSE;839}840841J2dRlsTraceLn(J2D_TRACE_INFO,842"OGLContext_IsGradShaderSupportAvailable: Linear/RadialGradientPaint shader supported");843844return JNI_TRUE;845}846847/**848* Checks for the presence of the optional extensions used by849* the Java 2D OpenGL pipeline. The given caps bitfield is updated850* to reflect the availability of these extensions.851*/852void853OGLContext_GetExtensionInfo(JNIEnv *env, jint *caps)854{855jint vcap = OGLC_VENDOR_OTHER;856const char *vendor = (char *)j2d_glGetString(GL_VENDOR);857const char *e = (char *)j2d_glGetString(GL_EXTENSIONS);858jboolean fragShaderAvail =859OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_shader");860861J2dTraceLn(J2D_TRACE_INFO, "OGLContext_GetExtensionInfo");862863*caps |= CAPS_TEXNONSQUARE;864if (OGLContext_IsExtensionAvailable(e, "GL_ARB_multitexture")) {865*caps |= CAPS_MULTITEXTURE;866}867if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_non_power_of_two")){868*caps |= CAPS_TEXNONPOW2;869}870// 6656574: Use of the GL_ARB_texture_rectangle extension by Java 2D871// complicates any third-party libraries that try to interact with872// the OGL pipeline (and we've run into driver bugs in the past related873// to this extension), so for now we will disable its use by default (unless874// forced). We will still make use of the GL_ARB_texture_non_power_of_two875// extension when available, which is the better choice going forward876// anyway.877if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_rectangle") &&878getenv("J2D_OGL_TEXRECT") != NULL)879{880*caps |= CAPS_EXT_TEXRECT;881}882if (OGLContext_IsFBObjectExtensionAvailable(env, e)) {883*caps |= CAPS_EXT_FBOBJECT;884}885if (OGLContext_IsLCDShaderSupportAvailable(env, fragShaderAvail)) {886*caps |= CAPS_EXT_LCD_SHADER | CAPS_PS20;887}888if (OGLContext_IsBIOpShaderSupportAvailable(env, fragShaderAvail)) {889*caps |= CAPS_EXT_BIOP_SHADER | CAPS_PS20;890}891if (OGLContext_IsGradShaderSupportAvailable(env, fragShaderAvail)) {892*caps |= CAPS_EXT_GRAD_SHADER | CAPS_PS20;893}894if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program")) {895// this is an Nvidia board, at least PS 2.0, but we can't896// use the "max instructions" heuristic since GeForce FX897// boards report 1024 even though they're only PS 2.0,898// so we'll check the following, which does imply PS 3.0899if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program2")) {900*caps |= CAPS_PS30;901}902} else {903// for all other boards, we look at the "max instructions"904// count reported by the GL_ARB_fragment_program extension905// as a heuristic for detecting PS 3.0 compatible hardware906if (OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_program")) {907GLint instr;908j2d_glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,909GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &instr);910if (instr > 512) {911*caps |= CAPS_PS30;912}913}914}915if (OGLContext_IsExtensionAvailable(e, "GL_NV_texture_barrier")) {916*caps |= CAPS_EXT_TEXBARRIER;917}918919// stuff vendor descriptor in the upper bits of the caps920if (vendor != NULL) {921if (strncmp(vendor, "ATI", 3) == 0) {922vcap = OGLC_VENDOR_ATI;923} else if (strncmp(vendor, "NVIDIA", 6) == 0) {924vcap = OGLC_VENDOR_NVIDIA;925} else if (strncmp(vendor, "Intel", 5) == 0) {926vcap = OGLC_VENDOR_INTEL;927}928// REMIND: new in 7 - check if needs fixing929*caps |= ((vcap & OGLC_VCAP_MASK) << OGLC_VCAP_OFFSET);930}931932}933934/**935* Returns JNI_TRUE if the given GL_VERSION string meets the minimum936* requirements (>= 1.2); JNI_FALSE otherwise.937*/938jboolean939OGLContext_IsVersionSupported(const unsigned char *versionstr)940{941J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsVersionSupported");942943if (versionstr == NULL) {944J2dRlsTraceLn(J2D_TRACE_ERROR,945"OGLContext_IsVersionSupported: version string is null");946return JNI_FALSE;947}948949// note that this check allows for OpenGL 2.x950return ((versionstr[0] == '1' && versionstr[2] >= '2') ||951(versionstr[0] >= '2'));952}953954/**955* Compiles and links the given fragment shader program. If956* successful, this function returns a handle to the newly created shader957* program; otherwise returns 0.958*/959GLhandleARB960OGLContext_CreateFragmentProgram(const char *fragmentShaderSource)961{962GLhandleARB fragmentShader, fragmentProgram;963GLint success;964int infoLogLength = 0;965966J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateFragmentProgram");967968// create the shader object and compile the shader source code969fragmentShader = j2d_glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);970j2d_glShaderSourceARB(fragmentShader, 1, &fragmentShaderSource, NULL);971j2d_glCompileShaderARB(fragmentShader);972j2d_glGetObjectParameterivARB(fragmentShader,973GL_OBJECT_COMPILE_STATUS_ARB,974&success);975976// print the compiler messages, if necessary977j2d_glGetObjectParameterivARB(fragmentShader,978GL_OBJECT_INFO_LOG_LENGTH_ARB,979&infoLogLength);980if (infoLogLength > 1) {981char infoLog[1024];982j2d_glGetInfoLogARB(fragmentShader, 1024, NULL, infoLog);983J2dRlsTraceLn2(J2D_TRACE_WARNING,984"OGLContext_CreateFragmentProgram: compiler msg (%d):\n%s",985infoLogLength, infoLog);986}987988if (!success) {989J2dRlsTraceLn(J2D_TRACE_ERROR,990"OGLContext_CreateFragmentProgram: error compiling shader");991j2d_glDeleteObjectARB(fragmentShader);992return 0;993}994995// create the program object and attach it to the shader996fragmentProgram = j2d_glCreateProgramObjectARB();997j2d_glAttachObjectARB(fragmentProgram, fragmentShader);998999// it is now safe to delete the shader object1000j2d_glDeleteObjectARB(fragmentShader);10011002// link the program1003j2d_glLinkProgramARB(fragmentProgram);1004j2d_glGetObjectParameterivARB(fragmentProgram,1005GL_OBJECT_LINK_STATUS_ARB,1006&success);10071008// print the linker messages, if necessary1009j2d_glGetObjectParameterivARB(fragmentProgram,1010GL_OBJECT_INFO_LOG_LENGTH_ARB,1011&infoLogLength);1012if (infoLogLength > 1) {1013char infoLog[1024];1014j2d_glGetInfoLogARB(fragmentProgram, 1024, NULL, infoLog);1015J2dRlsTraceLn2(J2D_TRACE_WARNING,1016"OGLContext_CreateFragmentProgram: linker msg (%d):\n%s",1017infoLogLength, infoLog);1018}10191020if (!success) {1021J2dRlsTraceLn(J2D_TRACE_ERROR,1022"OGLContext_CreateFragmentProgram: error linking shader");1023j2d_glDeleteObjectARB(fragmentProgram);1024return 0;1025}10261027return fragmentProgram;1028}10291030/*1031* Class: sun_java2d_opengl_OGLContext1032* Method: getOGLIdString1033* Signature: ()Ljava/lang/String;1034*/1035JNIEXPORT jstring JNICALL Java_sun_java2d_opengl_OGLContext_getOGLIdString1036(JNIEnv *env, jclass oglcc)1037{1038char *vendor, *renderer, *version;1039char *pAdapterId;1040jobject ret = NULL;1041int len;10421043J2dTraceLn(J2D_TRACE_INFO, "OGLContext_getOGLIdString");10441045vendor = (char*)j2d_glGetString(GL_VENDOR);1046if (vendor == NULL) {1047vendor = "Unknown Vendor";1048}1049renderer = (char*)j2d_glGetString(GL_RENDERER);1050if (renderer == NULL) {1051renderer = "Unknown Renderer";1052}1053version = (char*)j2d_glGetString(GL_VERSION);1054if (version == NULL) {1055version = "unknown version";1056}10571058// 'vendor renderer (version)0'1059len = strlen(vendor) + 1 + strlen(renderer) + 1 + 1+strlen(version)+1 + 1;1060pAdapterId = malloc(len);1061if (pAdapterId != NULL) {10621063jio_snprintf(pAdapterId, len, "%s %s (%s)", vendor, renderer, version);10641065J2dTraceLn1(J2D_TRACE_VERBOSE, " id=%s", pAdapterId);10661067ret = JNU_NewStringPlatform(env, pAdapterId);10681069free(pAdapterId);1070}10711072return ret;1073}10741075#endif /* !HEADLESS */107610771078