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