1 /*
   2  * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifndef HEADLESS
  27 
  28 #include <stdlib.h>
  29 #include <string.h>
  30 
  31 #include "sun_java2d_SunGraphics2D.h"
  32 
  33 #include "jlong.h"
  34 #include "jni_util.h"
  35 #include "OGLContext.h"
  36 #include "OGLRenderQueue.h"
  37 #include "OGLSurfaceData.h"
  38 #include "GraphicsPrimitiveMgr.h"
  39 #include "Region.h"
  40 
  41 #include "jvm.h"
  42 
  43 /**
  44  * The following methods are implemented in the windowing system (i.e. GLX
  45  * and WGL) source files.
  46  */
  47 extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo);
  48 extern OGLContext *OGLSD_MakeOGLContextCurrent(JNIEnv *env,
  49                                                OGLSDOps *srcOps,
  50                                                OGLSDOps *dstOps);
  51 
  52 /**
  53  * This table contains the standard blending rules (or Porter-Duff compositing
  54  * factors) used in glBlendFunc(), indexed by the rule constants from the
  55  * AlphaComposite class.
  56  */
  57 OGLBlendRule StdBlendRules[] = {
  58     { GL_ZERO,                GL_ZERO                }, /* 0 - Nothing      */
  59     { GL_ZERO,                GL_ZERO                }, /* 1 - RULE_Clear   */
  60     { GL_ONE,                 GL_ZERO                }, /* 2 - RULE_Src     */
  61     { GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA }, /* 3 - RULE_SrcOver */
  62     { GL_ONE_MINUS_DST_ALPHA, GL_ONE                 }, /* 4 - RULE_DstOver */
  63     { GL_DST_ALPHA,           GL_ZERO                }, /* 5 - RULE_SrcIn   */
  64     { GL_ZERO,                GL_SRC_ALPHA           }, /* 6 - RULE_DstIn   */
  65     { GL_ONE_MINUS_DST_ALPHA, GL_ZERO                }, /* 7 - RULE_SrcOut  */
  66     { GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA }, /* 8 - RULE_DstOut  */
  67     { GL_ZERO,                GL_ONE                 }, /* 9 - RULE_Dst     */
  68     { GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA }, /*10 - RULE_SrcAtop */
  69     { GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA           }, /*11 - RULE_DstAtop */
  70     { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*12 - RULE_AlphaXor*/
  71 };
  72 
  73 /** Evaluates to "front" or "back", depending on the value of buf. */
  74 #define OGLC_ACTIVE_BUFFER_NAME(buf) \
  75     (buf == GL_FRONT || buf == GL_COLOR_ATTACHMENT0_EXT) ? "front" : "back"
  76 
  77 /**
  78  * Initializes the viewport and projection matrix, effectively positioning
  79  * the origin at the top-left corner of the surface.  This allows Java 2D
  80  * coordinates to be passed directly to OpenGL, which is typically based on
  81  * a bottom-right coordinate system.  This method also sets the appropriate
  82  * read and draw buffers.
  83  */
  84 static void
  85 OGLContext_SetViewport(OGLSDOps *srcOps, OGLSDOps *dstOps)
  86 {
  87     jint width = dstOps->width;
  88     jint height = dstOps->height;
  89 
  90     J2dTraceLn4(J2D_TRACE_INFO,
  91                 "OGLContext_SetViewport: w=%d h=%d read=%s draw=%s",
  92                 width, height,
  93                 OGLC_ACTIVE_BUFFER_NAME(srcOps->activeBuffer),
  94                 OGLC_ACTIVE_BUFFER_NAME(dstOps->activeBuffer));
  95 
  96     // set the viewport and projection matrix
  97     j2d_glViewport(dstOps->xOffset, dstOps->yOffset,
  98                    (GLsizei)width, (GLsizei)height);
  99     j2d_glMatrixMode(GL_PROJECTION);
 100     j2d_glLoadIdentity();
 101     j2d_glOrtho(0.0, (GLdouble)width, (GLdouble)height, 0.0, -1.0, 1.0);
 102 
 103     // set the active read and draw buffers
 104     j2d_glReadBuffer(srcOps->activeBuffer);
 105     j2d_glDrawBuffer(dstOps->activeBuffer);
 106 
 107     // set the color mask to enable alpha channel only when necessary
 108     j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);
 109 }
 110 
 111 /**
 112  * Initializes the alpha channel of the current surface so that it contains
 113  * fully opaque alpha values.
 114  */
 115 static void
 116 OGLContext_InitAlphaChannel()
 117 {
 118     GLboolean scissorEnabled;
 119 
 120     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitAlphaChannel");
 121 
 122     // it is possible for the scissor test to be enabled at this point;
 123     // if it is, disable it temporarily since it can affect the glClear() op
 124     scissorEnabled = j2d_glIsEnabled(GL_SCISSOR_TEST);
 125     if (scissorEnabled) {
 126         j2d_glDisable(GL_SCISSOR_TEST);
 127     }
 128 
 129     // set the color mask so that we only affect the alpha channel
 130     j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
 131 
 132     // clear the color buffer so that the alpha channel is fully opaque
 133     j2d_glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 134     j2d_glClear(GL_COLOR_BUFFER_BIT);
 135 
 136     // restore the color mask (as it was set in OGLContext_SetViewport())
 137     j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
 138 
 139     // re-enable scissor test, only if it was enabled earlier
 140     if (scissorEnabled) {
 141         j2d_glEnable(GL_SCISSOR_TEST);
 142     }
 143 }
 144 
 145 /**
 146  * Fetches the OGLContext associated with the given destination surface,
 147  * makes the context current for those surfaces, updates the destination
 148  * viewport, and then returns a pointer to the OGLContext.
 149  */
 150 OGLContext *
 151 OGLContext_SetSurfaces(JNIEnv *env, jlong pSrc, jlong pDst)
 152 {
 153     OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrc);
 154     OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDst);
 155     OGLContext *oglc = NULL;
 156 
 157     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetSurfaces");
 158 
 159     if (srcOps == NULL || dstOps == NULL) {
 160         J2dRlsTraceLn(J2D_TRACE_ERROR,
 161             "OGLContext_SetSurfaces: ops are null");
 162         return NULL;
 163     }
 164 
 165     J2dTraceLn2(J2D_TRACE_VERBOSE, "  srctype=%d dsttype=%d",
 166                 srcOps->drawableType, dstOps->drawableType);
 167 
 168     if (dstOps->drawableType == OGLSD_TEXTURE) {
 169         J2dRlsTraceLn(J2D_TRACE_ERROR,
 170             "OGLContext_SetSurfaces: texture cannot be used as destination");
 171         return NULL;
 172     }
 173 
 174     if (dstOps->drawableType == OGLSD_UNDEFINED) {
 175         // initialize the surface as an OGLSD_WINDOW
 176         if (!OGLSD_InitOGLWindow(env, dstOps)) {
 177             J2dRlsTraceLn(J2D_TRACE_ERROR,
 178                 "OGLContext_SetSurfaces: could not init OGL window");
 179             return NULL;
 180         }
 181     }
 182 
 183     // make the context current
 184     oglc = OGLSD_MakeOGLContextCurrent(env, srcOps, dstOps);
 185     if (oglc == NULL) {
 186         J2dRlsTraceLn(J2D_TRACE_ERROR,
 187             "OGLContext_SetSurfaces: could not make context current");
 188         return NULL;
 189     }
 190 
 191     // update the viewport
 192     OGLContext_SetViewport(srcOps, dstOps);
 193 
 194     // perform additional one-time initialization, if necessary
 195     if (dstOps->needsInit) {
 196         if (dstOps->isOpaque) {
 197             // in this case we are treating the destination as opaque, but
 198             // to do so, first we need to ensure that the alpha channel
 199             // is filled with fully opaque values (see 6319663)
 200             OGLContext_InitAlphaChannel();
 201         }
 202         dstOps->needsInit = JNI_FALSE;
 203     }
 204 
 205     return oglc;
 206 }
 207 
 208 /**
 209  * Resets the current clip state (disables both scissor and depth tests).
 210  */
 211 void
 212 OGLContext_ResetClip(OGLContext *oglc)
 213 {
 214     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetClip");
 215 
 216     RETURN_IF_NULL(oglc);
 217     CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
 218 
 219     j2d_glDisable(GL_SCISSOR_TEST);
 220     j2d_glDisable(GL_DEPTH_TEST);
 221 }
 222 
 223 /**
 224  * Sets the OpenGL scissor bounds to the provided rectangular clip bounds.
 225  */
 226 void
 227 OGLContext_SetRectClip(OGLContext *oglc, OGLSDOps *dstOps,
 228                        jint x1, jint y1, jint x2, jint y2)
 229 {
 230     jint width = x2 - x1;
 231     jint height = y2 - y1;
 232 
 233     J2dTraceLn4(J2D_TRACE_INFO,
 234                 "OGLContext_SetRectClip: x=%d y=%d w=%d h=%d",
 235                 x1, y1, width, height);
 236 
 237     RETURN_IF_NULL(dstOps);
 238     RETURN_IF_NULL(oglc);
 239     CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
 240 
 241     if ((width < 0) || (height < 0)) {
 242         // use an empty scissor rectangle when the region is empty
 243         width = 0;
 244         height = 0;
 245     }
 246 
 247     j2d_glDisable(GL_DEPTH_TEST);
 248     j2d_glEnable(GL_SCISSOR_TEST);
 249 
 250     // the scissor rectangle is specified using the lower-left
 251     // origin of the clip region (in the framebuffer's coordinate
 252     // space), so we must account for the x/y offsets of the
 253     // destination surface
 254     j2d_glScissor(dstOps->xOffset + x1,
 255                   dstOps->yOffset + dstOps->height - (y1 + height),
 256                   width, height);
 257 }
 258 
 259 /**
 260  * Sets up a complex (shape) clip using the OpenGL depth buffer.  This
 261  * method prepares the depth buffer so that the clip Region spans can
 262  * be "rendered" into it.  The depth buffer is first cleared, then the
 263  * depth func is setup so that when we render the clip spans,
 264  * nothing is rendered into the color buffer, but for each pixel that would
 265  * be rendered, a non-zero value is placed into that location in the depth
 266  * buffer.  With depth test enabled, pixels will only be rendered into the
 267  * color buffer if the corresponding value at that (x,y) location in the
 268  * depth buffer differs from the incoming depth value.
 269  */
 270 void
 271 OGLContext_BeginShapeClip(OGLContext *oglc)
 272 {
 273     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_BeginShapeClip");
 274 
 275     RETURN_IF_NULL(oglc);
 276     RESET_PREVIOUS_OP();
 277 
 278     j2d_glDisable(GL_SCISSOR_TEST);
 279 
 280     // enable depth test and clear depth buffer so that depth values are at
 281     // their maximum; also set the depth func to GL_ALWAYS so that the
 282     // depth values of the clip spans are forced into the depth buffer
 283     j2d_glEnable(GL_DEPTH_TEST);
 284     j2d_glClearDepth(1.0);
 285     j2d_glClear(GL_DEPTH_BUFFER_BIT);
 286     j2d_glDepthFunc(GL_ALWAYS);
 287 
 288     // disable writes into the color buffer while we set up the clip
 289     j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 290 
 291     // save current transform
 292     j2d_glMatrixMode(GL_MODELVIEW);
 293     j2d_glPushMatrix();
 294 
 295     // use identity transform plus slight translation in the z-axis when
 296     // setting the clip spans; this will push the clip spans (which would
 297     // normally be at z=0) to the z=1 plane to give them some depth
 298     j2d_glLoadIdentity();
 299     j2d_glTranslatef(0.0f, 0.0f, 1.0f);
 300 }
 301 
 302 /**
 303  * Finishes setting up the shape clip by resetting the depth func
 304  * so that future rendering operations will once again be written into the
 305  * color buffer (while respecting the clip set up in the depth buffer).
 306  */
 307 void
 308 OGLContext_EndShapeClip(OGLContext *oglc, OGLSDOps *dstOps)
 309 {
 310     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_EndShapeClip");
 311 
 312     RETURN_IF_NULL(dstOps);
 313     RETURN_IF_NULL(oglc);
 314     RESET_PREVIOUS_OP();
 315 
 316     // restore transform
 317     j2d_glPopMatrix();
 318 
 319     // re-enable writes into the color buffer
 320     j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);
 321 
 322     // enable the depth test so that only fragments within the clip region
 323     // (i.e. those fragments whose z-values are >= the values currently
 324     // stored in the depth buffer) are rendered
 325     j2d_glDepthFunc(GL_GEQUAL);
 326 }
 327 
 328 /**
 329  * Initializes the OpenGL state responsible for applying extra alpha.  This
 330  * step is only necessary for any operation that uses glDrawPixels() or
 331  * glCopyPixels() with a non-1.0f extra alpha value.  Since the source is
 332  * always premultiplied, we apply the extra alpha value to both alpha and
 333  * color components using GL_*_SCALE.
 334  */
 335 void
 336 OGLContext_SetExtraAlpha(jfloat ea)
 337 {
 338     J2dTraceLn1(J2D_TRACE_INFO, "OGLContext_SetExtraAlpha: ea=%f", ea);
 339 
 340     j2d_glPixelTransferf(GL_ALPHA_SCALE, ea);
 341     j2d_glPixelTransferf(GL_RED_SCALE, ea);
 342     j2d_glPixelTransferf(GL_GREEN_SCALE, ea);
 343     j2d_glPixelTransferf(GL_BLUE_SCALE, ea);
 344 }
 345 
 346 /**
 347  * Resets all OpenGL compositing state (disables blending and logic
 348  * operations).
 349  */
 350 void
 351 OGLContext_ResetComposite(OGLContext *oglc)
 352 {
 353     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetComposite");
 354 
 355     RETURN_IF_NULL(oglc);
 356     CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
 357 
 358     // disable blending and XOR mode
 359     if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {
 360         j2d_glDisable(GL_BLEND);
 361     } else if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {
 362         j2d_glDisable(GL_COLOR_LOGIC_OP);
 363         j2d_glDisable(GL_ALPHA_TEST);
 364     }
 365 
 366     // set state to default values
 367     oglc->compState = sun_java2d_SunGraphics2D_COMP_ISCOPY;
 368     oglc->extraAlpha = 1.0f;
 369 }
 370 
 371 /**
 372  * Initializes the OpenGL blending state.  XOR mode is disabled and the
 373  * appropriate blend functions are setup based on the AlphaComposite rule
 374  * constant.
 375  */
 376 void
 377 OGLContext_SetAlphaComposite(OGLContext *oglc,
 378                              jint rule, jfloat extraAlpha, jint flags)
 379 {
 380     J2dTraceLn1(J2D_TRACE_INFO,
 381                 "OGLContext_SetAlphaComposite: flags=%d", flags);
 382 
 383     RETURN_IF_NULL(oglc);
 384     CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
 385 
 386     // disable XOR mode
 387     if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {
 388         j2d_glDisable(GL_COLOR_LOGIC_OP);
 389         j2d_glDisable(GL_ALPHA_TEST);
 390     }
 391 
 392     // we can safely disable blending when:
 393     //   - comp is SrcNoEa or SrcOverNoEa, and
 394     //   - the source is opaque
 395     // (turning off blending can have a large positive impact on
 396     // performance)
 397     if ((rule == RULE_Src || rule == RULE_SrcOver) &&
 398         (extraAlpha == 1.0f) &&
 399         (flags & OGLC_SRC_IS_OPAQUE))
 400     {
 401         J2dTraceLn1(J2D_TRACE_VERBOSE,
 402                     "  disabling alpha comp: rule=%d ea=1.0 src=opq", rule);
 403         j2d_glDisable(GL_BLEND);
 404     } else {
 405         J2dTraceLn2(J2D_TRACE_VERBOSE,
 406                     "  enabling alpha comp: rule=%d ea=%f", rule, extraAlpha);
 407         j2d_glEnable(GL_BLEND);
 408         j2d_glBlendFunc(StdBlendRules[rule].src, StdBlendRules[rule].dst);
 409     }
 410 
 411     // update state
 412     oglc->compState = sun_java2d_SunGraphics2D_COMP_ALPHA;
 413     oglc->extraAlpha = extraAlpha;
 414 }
 415 
 416 /**
 417  * Initializes the OpenGL logic op state to XOR mode.  Blending is disabled
 418  * before enabling logic op mode.  The XOR pixel value will be applied
 419  * later in the OGLContext_SetColor() method.
 420  */
 421 void
 422 OGLContext_SetXorComposite(OGLContext *oglc, jint xorPixel)
 423 {
 424     J2dTraceLn1(J2D_TRACE_INFO,
 425                 "OGLContext_SetXorComposite: xorPixel=%08x", xorPixel);
 426 
 427     RETURN_IF_NULL(oglc);
 428     CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
 429 
 430     // disable blending mode
 431     if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {
 432         j2d_glDisable(GL_BLEND);
 433     }
 434 
 435     // enable XOR mode
 436     j2d_glEnable(GL_COLOR_LOGIC_OP);
 437     j2d_glLogicOp(GL_XOR);
 438 
 439     // set up the alpha test so that we discard transparent fragments (this
 440     // is primarily useful for rendering text in XOR mode)
 441     j2d_glEnable(GL_ALPHA_TEST);
 442     j2d_glAlphaFunc(GL_NOTEQUAL, 0.0f);
 443 
 444     // update state
 445     oglc->compState = sun_java2d_SunGraphics2D_COMP_XOR;
 446     oglc->xorPixel = xorPixel;
 447     oglc->extraAlpha = 1.0f;
 448 }
 449 
 450 /**
 451  * Resets the OpenGL transform state back to the identity matrix.
 452  */
 453 void
 454 OGLContext_ResetTransform(OGLContext *oglc)
 455 {
 456     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetTransform");
 457 
 458     RETURN_IF_NULL(oglc);
 459     CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
 460 
 461     j2d_glMatrixMode(GL_MODELVIEW);
 462     j2d_glLoadIdentity();
 463 }
 464 
 465 /**
 466  * Initializes the OpenGL transform state by setting the modelview transform
 467  * using the given matrix parameters.
 468  *
 469  * REMIND: it may be worthwhile to add serial id to AffineTransform, so we
 470  *         could do a quick check to see if the xform has changed since
 471  *         last time... a simple object compare won't suffice...
 472  */
 473 void
 474 OGLContext_SetTransform(OGLContext *oglc,
 475                         jdouble m00, jdouble m10,
 476                         jdouble m01, jdouble m11,
 477                         jdouble m02, jdouble m12)
 478 {
 479     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetTransform");
 480 
 481     RETURN_IF_NULL(oglc);
 482     CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
 483 
 484     if (oglc->xformMatrix == NULL) {
 485         size_t arrsize = 16 * sizeof(GLdouble);
 486         oglc->xformMatrix = (GLdouble *)malloc(arrsize);
 487         memset(oglc->xformMatrix, 0, arrsize);
 488         oglc->xformMatrix[10] = 1.0;
 489         oglc->xformMatrix[15] = 1.0;
 490     }
 491 
 492     // copy values from AffineTransform object into native matrix array
 493     oglc->xformMatrix[0] = m00;
 494     oglc->xformMatrix[1] = m10;
 495     oglc->xformMatrix[4] = m01;
 496     oglc->xformMatrix[5] = m11;
 497     oglc->xformMatrix[12] = m02;
 498     oglc->xformMatrix[13] = m12;
 499 
 500     J2dTraceLn3(J2D_TRACE_VERBOSE, "  [%lf %lf %lf]",
 501                 oglc->xformMatrix[0], oglc->xformMatrix[4],
 502                 oglc->xformMatrix[12]);
 503     J2dTraceLn3(J2D_TRACE_VERBOSE, "  [%lf %lf %lf]",
 504                 oglc->xformMatrix[1], oglc->xformMatrix[5],
 505                 oglc->xformMatrix[13]);
 506 
 507     j2d_glMatrixMode(GL_MODELVIEW);
 508     j2d_glLoadMatrixd(oglc->xformMatrix);
 509 }
 510 
 511 /**
 512  * Creates a 2D texture of the given format and dimensions and returns the
 513  * texture object identifier.  This method is typically used to create a
 514  * temporary texture for intermediate work, such as in the
 515  * OGLContext_InitBlitTileTexture() method below.
 516  */
 517 GLuint
 518 OGLContext_CreateBlitTexture(GLenum internalFormat, GLenum pixelFormat,
 519                              GLuint width, GLuint height)
 520 {
 521     GLuint texID;
 522     GLint sp, sr, rl, align;
 523     GLclampf priority = 1.0f;
 524 
 525     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateBlitTexture");
 526 
 527     j2d_glGenTextures(1, &texID);
 528     j2d_glBindTexture(GL_TEXTURE_2D, texID);
 529     j2d_glPrioritizeTextures(1, &texID, &priority);
 530     j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 531     j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 532     OGLSD_RESET_TEXTURE_WRAP(GL_TEXTURE_2D);
 533 
 534     // save pixel store parameters (since this method could be invoked after
 535     // the caller has already set up its pixel store parameters)
 536     j2d_glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &sp);
 537     j2d_glGetIntegerv(GL_UNPACK_SKIP_ROWS, &sr);
 538     j2d_glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rl);
 539     j2d_glGetIntegerv(GL_UNPACK_ALIGNMENT, &align);
 540 
 541     // set pixel store parameters to default values
 542     j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 543     j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
 544     j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 545     j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 546 
 547     j2d_glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,
 548                      width, height, 0,
 549                      pixelFormat, GL_UNSIGNED_BYTE, NULL);
 550 
 551     // restore pixel store parameters
 552     j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sp);
 553     j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sr);
 554     j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, rl);
 555     j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, align);
 556 
 557     return texID;
 558 }
 559 
 560 /**
 561  * Initializes a small texture tile for use with tiled blit operations (see
 562  * OGLBlitLoops.c and OGLMaskBlit.c for usage examples).  The texture ID for
 563  * the tile is stored in the given OGLContext.  The tile is initially filled
 564  * with garbage values, but the tile is updated as needed (via
 565  * glTexSubImage2D()) with real RGBA values used in tiled blit situations.
 566  * The internal format for the texture is GL_RGBA8, which should be sufficient
 567  * for storing system memory surfaces of any known format (see PixelFormats
 568  * for a list of compatible surface formats).
 569  */
 570 jboolean
 571 OGLContext_InitBlitTileTexture(OGLContext *oglc)
 572 {
 573     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitBlitTileTexture");
 574 
 575     oglc->blitTextureID =
 576         OGLContext_CreateBlitTexture(GL_RGBA8, GL_RGBA,
 577                                      OGLC_BLIT_TILE_SIZE,
 578                                      OGLC_BLIT_TILE_SIZE);
 579 
 580     return JNI_TRUE;
 581 }
 582 
 583 /**
 584  * Destroys the OpenGL resources associated with the given OGLContext.
 585  * It is required that the native context associated with the OGLContext
 586  * be made current prior to calling this method.
 587  */
 588 void
 589 OGLContext_DestroyContextResources(OGLContext *oglc)
 590 {
 591     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_DestroyContextResources");
 592 
 593     if (oglc->xformMatrix != NULL) {
 594         free(oglc->xformMatrix);
 595     }
 596 
 597     if (oglc->blitTextureID != 0) {
 598         j2d_glDeleteTextures(1, &oglc->blitTextureID);
 599     }
 600 }
 601 
 602 /**
 603  * Returns JNI_TRUE if the given extension name is available for the current
 604  * GraphicsConfig; JNI_FALSE otherwise.  An extension is considered available
 605  * if its identifier string is found amongst the space-delimited GL_EXTENSIONS
 606  * string.
 607  *
 608  * Adapted from the OpenGL Red Book, pg. 506.
 609  */
 610 jboolean
 611 OGLContext_IsExtensionAvailable(const char *extString, char *extName)
 612 {
 613     jboolean ret = JNI_FALSE;
 614     char *p = (char *)extString;
 615     char *end;
 616 
 617     if (extString == NULL) {
 618         J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsExtensionAvailable");
 619         J2dRlsTraceLn(J2D_TRACE_ERROR,
 620             "OGLContext_IsExtensionAvailable: extension string is null");
 621         return JNI_FALSE;
 622     }
 623 
 624     end = p + strlen(p);
 625 
 626     while (p < end) {
 627         size_t n = strcspn(p, " ");
 628 
 629         if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0)) {
 630             ret = JNI_TRUE;
 631             break;
 632         }
 633 
 634         p += (n + 1);
 635     }
 636 
 637     J2dRlsTraceLn2(J2D_TRACE_INFO,
 638                    "OGLContext_IsExtensionAvailable: %s=%s",
 639                    extName, ret ? "true" : "false");
 640 
 641     return ret;
 642 }
 643 
 644 /**
 645  * Returns JNI_TRUE only if all of the following conditions are met:
 646  *   - the GL_EXT_framebuffer_object extension is available
 647  *   - FBO support has been enabled via the system property
 648  *   - we can successfully create an FBO with depth capabilities
 649  */
 650 static jboolean
 651 OGLContext_IsFBObjectExtensionAvailable(JNIEnv *env,
 652                                         const char *extString)
 653 {
 654     jboolean isFBObjectEnabled = JNI_FALSE;
 655     GLuint fbobjectID, textureID, depthID;
 656     jint width = 1, height = 1;
 657 
 658     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsFBObjectExtensionAvailable");
 659 
 660     // first see if the fbobject extension is available
 661     if (!OGLContext_IsExtensionAvailable(extString,
 662                                          "GL_EXT_framebuffer_object"))
 663     {
 664         return JNI_FALSE;
 665     }
 666 
 667     // next see if the depth texture extension is available
 668     if (!OGLContext_IsExtensionAvailable(extString,
 669                                          "GL_ARB_depth_texture"))
 670     {
 671         return JNI_FALSE;
 672     }
 673 
 674     // next see if the fbobject system property has been enabled
 675     isFBObjectEnabled =
 676         JNU_GetStaticFieldByName(env, NULL,
 677                                  "sun/java2d/opengl/OGLSurfaceData",
 678                                  "isFBObjectEnabled", "Z").z;
 679     if (!isFBObjectEnabled) {
 680         J2dRlsTraceLn(J2D_TRACE_INFO,
 681             "OGLContext_IsFBObjectExtensionAvailable: disabled via flag");
 682         return JNI_FALSE;
 683     }
 684 
 685     // finally, create a dummy fbobject with depth capabilities to see
 686     // if this configuration is supported by the drivers/hardware
 687     // (first we initialize a color texture object that will be used to
 688     // construct the dummy fbobject)
 689     j2d_glGenTextures(1, &textureID);
 690     j2d_glBindTexture(GL_TEXTURE_2D, textureID);
 691     j2d_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
 692                      width, height, 0,
 693                      GL_RGB, GL_UNSIGNED_BYTE, NULL);
 694     j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 695     j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 696 
 697     // initialize framebuffer object using color texture created above
 698     if (!OGLSD_InitFBObject(&fbobjectID, &depthID,
 699                             textureID, GL_TEXTURE_2D,
 700                             width, height))
 701     {
 702         J2dRlsTraceLn(J2D_TRACE_INFO,
 703             "OGLContext_IsFBObjectExtensionAvailable: fbobject unsupported");
 704         j2d_glDeleteTextures(1, &textureID);
 705         return JNI_FALSE;
 706     }
 707 
 708     // delete the temporary resources
 709     j2d_glDeleteTextures(1, &textureID);
 710     j2d_glDeleteRenderbuffersEXT(1, &depthID);
 711     j2d_glDeleteFramebuffersEXT(1, &fbobjectID);
 712 
 713     J2dRlsTraceLn(J2D_TRACE_INFO,
 714         "OGLContext_IsFBObjectExtensionAvailable: fbobject supported");
 715 
 716     return JNI_TRUE;
 717 }
 718 
 719 /**
 720  * Returns JNI_TRUE only if all of the following conditions are met:
 721  *   - the GL_ARB_fragment_shader extension is available
 722  *   - the LCD text shader codepath has been enabled via the system property
 723  *   - the hardware supports the minimum number of texture units
 724  */
 725 static jboolean
 726 OGLContext_IsLCDShaderSupportAvailable(JNIEnv *env,
 727                                        jboolean fragShaderAvailable)
 728 {
 729     jboolean isLCDShaderEnabled = JNI_FALSE;
 730     GLint maxTexUnits;
 731 
 732     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsLCDShaderSupportAvailable");
 733 
 734     // first see if the fragment shader extension is available
 735     if (!fragShaderAvailable) {
 736         return JNI_FALSE;
 737     }
 738 
 739     // next see if the lcdshader system property has been enabled
 740     isLCDShaderEnabled =
 741         JNU_GetStaticFieldByName(env, NULL,
 742                                  "sun/java2d/opengl/OGLSurfaceData",
 743                                  "isLCDShaderEnabled", "Z").z;
 744     if (!isLCDShaderEnabled) {
 745         J2dRlsTraceLn(J2D_TRACE_INFO,
 746             "OGLContext_IsLCDShaderSupportAvailable: disabled via flag");
 747         return JNI_FALSE;
 748     }
 749 
 750     // finally, check to see if the hardware supports the required number
 751     // of texture units
 752     j2d_glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &maxTexUnits);
 753     if (maxTexUnits < 4) {
 754         J2dRlsTraceLn1(J2D_TRACE_INFO,
 755           "OGLContext_IsLCDShaderSupportAvailable: not enough tex units (%d)",
 756           maxTexUnits);
 757     }
 758 
 759     J2dRlsTraceLn(J2D_TRACE_INFO,
 760         "OGLContext_IsLCDShaderSupportAvailable: LCD text shader supported");
 761 
 762     return JNI_TRUE;
 763 }
 764 
 765 /**
 766  * Returns JNI_TRUE only if all of the following conditions are met:
 767  *   - the GL_ARB_fragment_shader extension is available
 768  *   - the BufferedImageOp shader codepath has been enabled via the
 769  *     system property
 770  */
 771 static jboolean
 772 OGLContext_IsBIOpShaderSupportAvailable(JNIEnv *env,
 773                                         jboolean fragShaderAvailable)
 774 {
 775     jboolean isBIOpShaderEnabled = JNI_FALSE;
 776 
 777     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsBIOpShaderSupportAvailable");
 778 
 779     // first see if the fragment shader extension is available
 780     if (!fragShaderAvailable) {
 781         return JNI_FALSE;
 782     }
 783 
 784     // next see if the biopshader system property has been enabled
 785     isBIOpShaderEnabled =
 786         JNU_GetStaticFieldByName(env, NULL,
 787                                  "sun/java2d/opengl/OGLSurfaceData",
 788                                  "isBIOpShaderEnabled", "Z").z;
 789     if (!isBIOpShaderEnabled) {
 790         J2dRlsTraceLn(J2D_TRACE_INFO,
 791             "OGLContext_IsBIOpShaderSupportAvailable: disabled via flag");
 792         return JNI_FALSE;
 793     }
 794 
 795     /*
 796      * Note: In theory we should probably do some other checks here, like
 797      * linking a sample shader to see if the hardware truly supports our
 798      * shader programs.  However, our current BufferedImageOp shaders were
 799      * designed to support first-generation shader-level hardware, so the
 800      * assumption is that if our shaders work on those GPUs, then they'll
 801      * work on newer ones as well.  Also, linking a fragment program can
 802      * cost valuable CPU cycles, which is another reason to avoid these
 803      * checks at startup.
 804      */
 805 
 806     J2dRlsTraceLn(J2D_TRACE_INFO,
 807         "OGLContext_IsBIOpShaderSupportAvailable: BufferedImageOp shader supported");
 808 
 809     return JNI_TRUE;
 810 }
 811 
 812 /**
 813  * Returns JNI_TRUE only if all of the following conditions are met:
 814  *   - the GL_ARB_fragment_shader extension is available
 815  *   - the Linear/RadialGradientPaint shader codepath has been enabled via the
 816  *     system property
 817  */
 818 static jboolean
 819 OGLContext_IsGradShaderSupportAvailable(JNIEnv *env,
 820                                         jboolean fragShaderAvailable)
 821 {
 822     jboolean isGradShaderEnabled = JNI_FALSE;
 823 
 824     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsGradShaderSupportAvailable");
 825 
 826     // first see if the fragment shader extension is available
 827     if (!fragShaderAvailable) {
 828         return JNI_FALSE;
 829     }
 830 
 831     // next see if the gradshader system property has been enabled
 832     isGradShaderEnabled =
 833         JNU_GetStaticFieldByName(env, NULL,
 834                                  "sun/java2d/opengl/OGLSurfaceData",
 835                                  "isGradShaderEnabled", "Z").z;
 836     if (!isGradShaderEnabled) {
 837         J2dRlsTraceLn(J2D_TRACE_INFO,
 838             "OGLContext_IsGradShaderSupportAvailable: disabled via flag");
 839         return JNI_FALSE;
 840     }
 841 
 842     J2dRlsTraceLn(J2D_TRACE_INFO,
 843         "OGLContext_IsGradShaderSupportAvailable: Linear/RadialGradientPaint shader supported");
 844 
 845     return JNI_TRUE;
 846 }
 847 
 848 /**
 849  * Checks for the presence of the optional extensions used by
 850  * the Java 2D OpenGL pipeline.  The given caps bitfield is updated
 851  * to reflect the availability of these extensions.
 852  */
 853 void
 854 OGLContext_GetExtensionInfo(JNIEnv *env, jint *caps)
 855 {
 856     jint vcap = OGLC_VENDOR_OTHER;
 857     const char *vendor = (char *)j2d_glGetString(GL_VENDOR);
 858     const char *e = (char *)j2d_glGetString(GL_EXTENSIONS);
 859     jboolean fragShaderAvail =
 860         OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_shader");
 861 
 862     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_GetExtensionInfo");
 863 
 864     *caps |= CAPS_TEXNONSQUARE;
 865     if (OGLContext_IsExtensionAvailable(e, "GL_ARB_multitexture")) {
 866         *caps |= CAPS_MULTITEXTURE;
 867     }
 868     if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_non_power_of_two")){
 869         *caps |= CAPS_TEXNONPOW2;
 870     }
 871     // 6656574: Use of the GL_ARB_texture_rectangle extension by Java 2D
 872     // complicates any third-party libraries that try to interact with
 873     // the OGL pipeline (and we've run into driver bugs in the past related
 874     // to this extension), so for now we will disable its use by default (unless
 875     // forced). We will still make use of the GL_ARB_texture_non_power_of_two
 876     // extension when available, which is the better choice going forward
 877     // anyway.
 878     if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_rectangle") &&
 879         getenv("J2D_OGL_TEXRECT") != NULL)
 880     {
 881         *caps |= CAPS_EXT_TEXRECT;
 882     }
 883     if (OGLContext_IsFBObjectExtensionAvailable(env, e)) {
 884         *caps |= CAPS_EXT_FBOBJECT;
 885     }
 886     if (OGLContext_IsLCDShaderSupportAvailable(env, fragShaderAvail)) {
 887         *caps |= CAPS_EXT_LCD_SHADER | CAPS_PS20;
 888     }
 889     if (OGLContext_IsBIOpShaderSupportAvailable(env, fragShaderAvail)) {
 890         *caps |= CAPS_EXT_BIOP_SHADER | CAPS_PS20;
 891     }
 892     if (OGLContext_IsGradShaderSupportAvailable(env, fragShaderAvail)) {
 893         *caps |= CAPS_EXT_GRAD_SHADER | CAPS_PS20;
 894     }
 895     if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program")) {
 896         // this is an Nvidia board, at least PS 2.0, but we can't
 897         // use the "max instructions" heuristic since GeForce FX
 898         // boards report 1024 even though they're only PS 2.0,
 899         // so we'll check the following, which does imply PS 3.0
 900         if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program2")) {
 901             *caps |= CAPS_PS30;
 902         }
 903     } else {
 904         // for all other boards, we look at the "max instructions"
 905         // count reported by the GL_ARB_fragment_program extension
 906         // as a heuristic for detecting PS 3.0 compatible hardware
 907         if (OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_program")) {
 908             GLint instr;
 909             j2d_glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
 910                                   GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &instr);
 911             if (instr > 512) {
 912                 *caps |= CAPS_PS30;
 913             }
 914         }
 915     }
 916     // stuff vendor descriptor in the upper bits of the caps
 917     if (vendor != NULL) {
 918         if (strncmp(vendor, "ATI", 3) == 0) {
 919             vcap = OGLC_VENDOR_ATI;
 920         } else if (strncmp(vendor, "NVIDIA", 6) == 0) {
 921             vcap = OGLC_VENDOR_NVIDIA;
 922         } else if (strncmp(vendor, "Sun", 3) == 0) {
 923             vcap = OGLC_VENDOR_SUN;
 924         }
 925         // REMIND: new in 7 - check if needs fixing
 926         *caps |= ((vcap & OGLC_VCAP_MASK) << OGLC_VCAP_OFFSET);
 927     }
 928 
 929 }
 930 
 931 /**
 932  * Returns JNI_TRUE if the given GL_VERSION string meets the minimum
 933  * requirements (>= 1.2); JNI_FALSE otherwise.
 934  */
 935 jboolean
 936 OGLContext_IsVersionSupported(const unsigned char *versionstr)
 937 {
 938     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsVersionSupported");
 939 
 940     if (versionstr == NULL) {
 941         J2dRlsTraceLn(J2D_TRACE_ERROR,
 942             "OGLContext_IsVersionSupported: version string is null");
 943         return JNI_FALSE;
 944     }
 945 
 946     // note that this check allows for OpenGL 2.x
 947     return ((versionstr[0] == '1' && versionstr[2] >= '2') ||
 948             (versionstr[0] >= '2'));
 949 }
 950 
 951 /**
 952  * Compiles and links the given fragment shader program.  If
 953  * successful, this function returns a handle to the newly created shader
 954  * program; otherwise returns 0.
 955  */
 956 GLhandleARB
 957 OGLContext_CreateFragmentProgram(const char *fragmentShaderSource)
 958 {
 959     GLhandleARB fragmentShader, fragmentProgram;
 960     GLint success;
 961     int infoLogLength = 0;
 962 
 963     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateFragmentProgram");
 964 
 965     // create the shader object and compile the shader source code
 966     fragmentShader = j2d_glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
 967     j2d_glShaderSourceARB(fragmentShader, 1, &fragmentShaderSource, NULL);
 968     j2d_glCompileShaderARB(fragmentShader);
 969     j2d_glGetObjectParameterivARB(fragmentShader,
 970                                   GL_OBJECT_COMPILE_STATUS_ARB,
 971                                   &success);
 972 
 973     // print the compiler messages, if necessary
 974     j2d_glGetObjectParameterivARB(fragmentShader,
 975                                   GL_OBJECT_INFO_LOG_LENGTH_ARB,
 976                                   &infoLogLength);
 977     if (infoLogLength > 1) {
 978         char infoLog[1024];
 979         j2d_glGetInfoLogARB(fragmentShader, 1024, NULL, infoLog);
 980         J2dRlsTraceLn2(J2D_TRACE_WARNING,
 981             "OGLContext_CreateFragmentProgram: compiler msg (%d):\n%s",
 982                        infoLogLength, infoLog);
 983     }
 984 
 985     if (!success) {
 986         J2dRlsTraceLn(J2D_TRACE_ERROR,
 987             "OGLContext_CreateFragmentProgram: error compiling shader");
 988         j2d_glDeleteObjectARB(fragmentShader);
 989         return 0;
 990     }
 991 
 992     // create the program object and attach it to the shader
 993     fragmentProgram = j2d_glCreateProgramObjectARB();
 994     j2d_glAttachObjectARB(fragmentProgram, fragmentShader);
 995 
 996     // it is now safe to delete the shader object
 997     j2d_glDeleteObjectARB(fragmentShader);
 998 
 999     // link the program
1000     j2d_glLinkProgramARB(fragmentProgram);
1001     j2d_glGetObjectParameterivARB(fragmentProgram,
1002                                   GL_OBJECT_LINK_STATUS_ARB,
1003                                   &success);
1004 
1005     // print the linker messages, if necessary
1006     j2d_glGetObjectParameterivARB(fragmentProgram,
1007                                   GL_OBJECT_INFO_LOG_LENGTH_ARB,
1008                                   &infoLogLength);
1009     if (infoLogLength > 1) {
1010         char infoLog[1024];
1011         j2d_glGetInfoLogARB(fragmentProgram, 1024, NULL, infoLog);
1012         J2dRlsTraceLn2(J2D_TRACE_WARNING,
1013             "OGLContext_CreateFragmentProgram: linker msg (%d):\n%s",
1014                        infoLogLength, infoLog);
1015     }
1016 
1017     if (!success) {
1018         J2dRlsTraceLn(J2D_TRACE_ERROR,
1019             "OGLContext_CreateFragmentProgram: error linking shader");
1020         j2d_glDeleteObjectARB(fragmentProgram);
1021         return 0;
1022     }
1023 
1024     return fragmentProgram;
1025 }
1026 
1027 /*
1028  * Class:     sun_java2d_opengl_OGLContext
1029  * Method:    getOGLIdString
1030  * Signature: ()Ljava/lang/String;
1031  */
1032 JNIEXPORT jstring JNICALL Java_sun_java2d_opengl_OGLContext_getOGLIdString
1033   (JNIEnv *env, jclass oglcc)
1034 {
1035     char *vendor, *renderer, *version;
1036     char *pAdapterId;
1037     jobject ret = NULL;
1038     int len;
1039 
1040     J2dTraceLn(J2D_TRACE_INFO, "OGLContext_getOGLIdString");
1041 
1042     vendor = (char*)j2d_glGetString(GL_VENDOR);
1043     if (vendor == NULL) {
1044         vendor = "Unknown Vendor";
1045     }
1046     renderer = (char*)j2d_glGetString(GL_RENDERER);
1047     if (renderer == NULL) {
1048         renderer = "Unknown Renderer";
1049     }
1050     version = (char*)j2d_glGetString(GL_VERSION);
1051     if (version == NULL) {
1052         version = "unknown version";
1053     }
1054 
1055     // 'vendor renderer (version)0'
1056     len = strlen(vendor) + 1 + strlen(renderer) + 1 + 1+strlen(version)+1 + 1;
1057     pAdapterId = malloc(len);
1058     if (pAdapterId != NULL) {
1059 
1060         jio_snprintf(pAdapterId, len, "%s %s (%s)", vendor, renderer, version);
1061 
1062         J2dTraceLn1(J2D_TRACE_VERBOSE, "  id=%s", pAdapterId);
1063 
1064         ret = JNU_NewStringPlatform(env, pAdapterId);
1065 
1066         free(pAdapterId);
1067     }
1068 
1069     return ret;
1070 }
1071 
1072 #endif /* !HEADLESS */