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 */