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