1 /* 2 * Copyright (c) 2007, 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 <jlong.h> 29 #include <string.h> 30 31 #include "sun_java2d_SunGraphics2D.h" 32 #include "sun_java2d_pipe_BufferedPaints.h" 33 34 #include "OGLPaints.h" 35 #include "OGLContext.h" 36 #include "OGLRenderQueue.h" 37 #include "OGLSurfaceData.h" 38 39 void 40 OGLPaints_ResetPaint(OGLContext *oglc) 41 { 42 jubyte ea; 43 44 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_ResetPaint"); 45 46 RETURN_IF_NULL(oglc); 47 J2dTraceLn1(J2D_TRACE_VERBOSE, " state=%d", oglc->paintState); 48 RESET_PREVIOUS_OP(); 49 50 if (oglc->useMask) { 51 // switch to texture unit 1, where paint state is currently enabled 52 j2d_glActiveTextureARB(GL_TEXTURE1_ARB); 53 } 54 55 switch (oglc->paintState) { 56 case sun_java2d_SunGraphics2D_PAINT_GRADIENT: 57 j2d_glDisable(GL_TEXTURE_1D); 58 j2d_glDisable(GL_TEXTURE_GEN_S); 59 break; 60 61 case sun_java2d_SunGraphics2D_PAINT_TEXTURE: 62 // Note: The texture object used in SetTexturePaint() will 63 // still be bound at this point, so it is safe to call the following. 64 OGLSD_RESET_TEXTURE_WRAP(GL_TEXTURE_2D); 65 j2d_glDisable(GL_TEXTURE_2D); 66 j2d_glDisable(GL_TEXTURE_GEN_S); 67 j2d_glDisable(GL_TEXTURE_GEN_T); 68 break; 69 70 case sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT: 71 case sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT: 72 j2d_glUseProgramObjectARB(0); 73 j2d_glDisable(GL_TEXTURE_1D); 74 break; 75 76 case sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR: 77 default: 78 break; 79 } 80 81 if (oglc->useMask) { 82 // restore control to texture unit 0 83 j2d_glActiveTextureARB(GL_TEXTURE0_ARB); 84 } 85 86 // set each component of the current color state to the extra alpha 87 // value, which will effectively apply the extra alpha to each fragment 88 // in paint/texturing operations 89 ea = (jubyte)(oglc->extraAlpha * 0xff + 0.5f); 90 j2d_glColor4ub(ea, ea, ea, ea); 91 oglc->pixel = (ea << 24) | (ea << 16) | (ea << 8) | (ea << 0); 92 oglc->r = ea; 93 oglc->g = ea; 94 oglc->b = ea; 95 oglc->a = ea; 96 oglc->useMask = JNI_FALSE; 97 oglc->paintState = -1; 98 } 99 100 void 101 OGLPaints_SetColor(OGLContext *oglc, jint pixel) 102 { 103 jubyte r, g, b, a; 104 105 J2dTraceLn1(J2D_TRACE_INFO, "OGLPaints_SetColor: pixel=%08x", pixel); 106 107 RETURN_IF_NULL(oglc); 108 109 // glColor*() is allowed within glBegin()/glEnd() pairs, so 110 // no need to reset the current op state here unless the paint 111 // state really needs to be changed 112 if (oglc->paintState > sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) { 113 OGLPaints_ResetPaint(oglc); 114 } 115 116 // store the raw (unmodified) pixel value, which may be used for 117 // special operations later 118 oglc->pixel = pixel; 119 120 if (oglc->compState != sun_java2d_SunGraphics2D_COMP_XOR) { 121 r = (jubyte)(pixel >> 16); 122 g = (jubyte)(pixel >> 8); 123 b = (jubyte)(pixel >> 0); 124 a = (jubyte)(pixel >> 24); 125 126 J2dTraceLn4(J2D_TRACE_VERBOSE, 127 " updating color: r=%02x g=%02x b=%02x a=%02x", 128 r, g, b, a); 129 } else { 130 pixel ^= oglc->xorPixel; 131 132 r = (jubyte)(pixel >> 16); 133 g = (jubyte)(pixel >> 8); 134 b = (jubyte)(pixel >> 0); 135 a = 0xff; 136 137 J2dTraceLn4(J2D_TRACE_VERBOSE, 138 " updating xor color: r=%02x g=%02x b=%02x xorpixel=%08x", 139 r, g, b, oglc->xorPixel); 140 } 141 142 j2d_glColor4ub(r, g, b, a); 143 oglc->r = r; 144 oglc->g = g; 145 oglc->b = b; 146 oglc->a = a; 147 oglc->useMask = JNI_FALSE; 148 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR; 149 } 150 151 /************************* GradientPaint support ****************************/ 152 153 static GLuint gradientTexID = 0; 154 155 static void 156 OGLPaints_InitGradientTexture() 157 { 158 GLclampf priority = 1.0f; 159 160 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_InitGradientTexture"); 161 162 j2d_glGenTextures(1, &gradientTexID); 163 j2d_glBindTexture(GL_TEXTURE_1D, gradientTexID); 164 j2d_glPrioritizeTextures(1, &gradientTexID, &priority); 165 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 166 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 167 j2d_glTexImage1D(GL_TEXTURE_1D, 0, 168 GL_RGBA8, 2, 0, 169 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); 170 } 171 172 void 173 OGLPaints_SetGradientPaint(OGLContext *oglc, 174 jboolean useMask, jboolean cyclic, 175 jdouble p0, jdouble p1, jdouble p3, 176 jint pixel1, jint pixel2) 177 { 178 GLdouble texParams[4]; 179 GLuint pixels[2]; 180 181 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetGradientPaint"); 182 183 RETURN_IF_NULL(oglc); 184 OGLPaints_ResetPaint(oglc); 185 186 texParams[0] = p0; 187 texParams[1] = p1; 188 texParams[2] = 0.0; 189 texParams[3] = p3; 190 191 pixels[0] = pixel1; 192 pixels[1] = pixel2; 193 194 if (useMask) { 195 // set up the paint on texture unit 1 (instead of the usual unit 0) 196 j2d_glActiveTextureARB(GL_TEXTURE1_ARB); 197 j2d_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 198 } else { 199 // texture unit 0 is already active; we can use the helper macro here 200 OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE); 201 } 202 203 if (gradientTexID == 0) { 204 OGLPaints_InitGradientTexture(); 205 } 206 207 j2d_glEnable(GL_TEXTURE_1D); 208 j2d_glEnable(GL_TEXTURE_GEN_S); 209 j2d_glBindTexture(GL_TEXTURE_1D, gradientTexID); 210 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, 211 cyclic ? GL_REPEAT : GL_CLAMP_TO_EDGE); 212 j2d_glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); 213 j2d_glTexGendv(GL_S, GL_OBJECT_PLANE, texParams); 214 215 j2d_glTexSubImage1D(GL_TEXTURE_1D, 0, 216 0, 2, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); 217 218 if (useMask) { 219 // restore control to texture unit 0 220 j2d_glActiveTextureARB(GL_TEXTURE0_ARB); 221 } 222 223 // oglc->pixel has been set appropriately in OGLPaints_ResetPaint() 224 oglc->useMask = useMask; 225 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_GRADIENT; 226 } 227 228 /************************** TexturePaint support ****************************/ 229 230 void 231 OGLPaints_SetTexturePaint(OGLContext *oglc, 232 jboolean useMask, 233 jlong pSrcOps, jboolean filter, 234 jdouble xp0, jdouble xp1, jdouble xp3, 235 jdouble yp0, jdouble yp1, jdouble yp3) 236 { 237 OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps); 238 GLdouble xParams[4]; 239 GLdouble yParams[4]; 240 GLint hint = (filter ? GL_LINEAR : GL_NEAREST); 241 242 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetTexturePaint"); 243 244 RETURN_IF_NULL(srcOps); 245 RETURN_IF_NULL(oglc); 246 OGLPaints_ResetPaint(oglc); 247 248 xParams[0] = xp0; 249 xParams[1] = xp1; 250 xParams[2] = 0.0; 251 xParams[3] = xp3; 252 253 yParams[0] = yp0; 254 yParams[1] = yp1; 255 yParams[2] = 0.0; 256 yParams[3] = yp3; 257 258 /* 259 * Note that we explicitly use GL_TEXTURE_2D below rather than using 260 * srcOps->textureTarget. This is because the texture wrap mode employed 261 * here (GL_REPEAT) is not available for GL_TEXTURE_RECTANGLE_ARB targets. 262 * The setup code in OGLPaints.Texture.isPaintValid() and in 263 * OGLSurfaceData.initTexture() ensures that we only get here for 264 * GL_TEXTURE_2D targets. 265 */ 266 267 if (useMask) { 268 // set up the paint on texture unit 1 (instead of the usual unit 0) 269 j2d_glActiveTextureARB(GL_TEXTURE1_ARB); 270 j2d_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 271 } else { 272 // texture unit 0 is already active; we can use the helper macro here 273 OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE); 274 } 275 276 j2d_glEnable(GL_TEXTURE_2D); 277 j2d_glEnable(GL_TEXTURE_GEN_S); 278 j2d_glEnable(GL_TEXTURE_GEN_T); 279 j2d_glBindTexture(GL_TEXTURE_2D, srcOps->textureID); 280 OGLSD_UPDATE_TEXTURE_FILTER(srcOps, hint); 281 OGLSD_UPDATE_TEXTURE_WRAP(GL_TEXTURE_2D, GL_REPEAT); 282 j2d_glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); 283 j2d_glTexGendv(GL_S, GL_OBJECT_PLANE, xParams); 284 j2d_glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); 285 j2d_glTexGendv(GL_T, GL_OBJECT_PLANE, yParams); 286 287 if (useMask) { 288 // restore control to texture unit 0 289 j2d_glActiveTextureARB(GL_TEXTURE0_ARB); 290 } 291 292 // oglc->pixel has been set appropriately in OGLPaints_ResetPaint() 293 oglc->useMask = useMask; 294 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_TEXTURE; 295 } 296 297 /****************** Shared MultipleGradientPaint support ********************/ 298 299 /** 300 * These constants are identical to those defined in the 301 * MultipleGradientPaint.CycleMethod enum; they are copied here for 302 * convenience (ideally we would pull them directly from the Java level, 303 * but that entails more hassle than it is worth). 304 */ 305 #define CYCLE_NONE 0 306 #define CYCLE_REFLECT 1 307 #define CYCLE_REPEAT 2 308 309 /** 310 * The following constants are flags that can be bitwise-or'ed together 311 * to control how the MultipleGradientPaint shader source code is generated: 312 * 313 * MULTI_CYCLE_METHOD 314 * Placeholder for the CycleMethod enum constant. 315 * 316 * MULTI_LARGE 317 * If set, use the (slower) shader that supports a larger number of 318 * gradient colors; otherwise, use the optimized codepath. See 319 * the MAX_FRACTIONS_SMALL/LARGE constants below for more details. 320 * 321 * MULTI_USE_MASK 322 * If set, apply the alpha mask value from texture unit 0 to the 323 * final color result (only used in the MaskFill case). 324 * 325 * MULTI_LINEAR_RGB 326 * If set, convert the linear RGB result back into the sRGB color space. 327 */ 328 #define MULTI_CYCLE_METHOD (3 << 0) 329 #define MULTI_LARGE (1 << 2) 330 #define MULTI_USE_MASK (1 << 3) 331 #define MULTI_LINEAR_RGB (1 << 4) 332 333 /** 334 * This value determines the size of the array of programs for each 335 * MultipleGradientPaint type. This value reflects the maximum value that 336 * can be represented by performing a bitwise-or of all the MULTI_* 337 * constants defined above. 338 */ 339 #define MAX_PROGRAMS 32 340 341 /** Evaluates to true if the given bit is set on the local flags variable. */ 342 #define IS_SET(flagbit) \ 343 (((flags) & (flagbit)) != 0) 344 345 /** Composes the given parameters as flags into the given flags variable.*/ 346 #define COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear) \ 347 do { \ 348 flags |= ((cycleMethod) & MULTI_CYCLE_METHOD); \ 349 if (large) flags |= MULTI_LARGE; \ 350 if (useMask) flags |= MULTI_USE_MASK; \ 351 if (linear) flags |= MULTI_LINEAR_RGB; \ 352 } while (0) 353 354 /** Extracts the CycleMethod enum value from the given flags variable. */ 355 #define EXTRACT_CYCLE_METHOD(flags) \ 356 ((flags) & MULTI_CYCLE_METHOD) 357 358 /** 359 * The maximum number of gradient "stops" supported by the fragment shader 360 * and related code. When the MULTI_LARGE flag is set, we will use 361 * MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL. By having 362 * two separate values, we can have one highly optimized shader (SMALL) that 363 * supports only a few fractions/colors, and then another, less optimal 364 * shader that supports more stops. 365 */ 366 #define MAX_FRACTIONS sun_java2d_pipe_BufferedPaints_MULTI_MAX_FRACTIONS 367 #define MAX_FRACTIONS_LARGE MAX_FRACTIONS 368 #define MAX_FRACTIONS_SMALL 4 369 370 /** 371 * The maximum number of gradient colors supported by all of the gradient 372 * fragment shaders. Note that this value must be a power of two, as it 373 * determines the size of the 1D texture created below. It also must be 374 * greater than or equal to MAX_FRACTIONS (there is no strict requirement 375 * that the two values be equal). 376 */ 377 #define MAX_COLORS 16 378 379 /** 380 * The handle to the gradient color table texture object used by the shaders. 381 */ 382 static GLuint multiGradientTexID = 0; 383 384 /** 385 * This is essentially a template of the shader source code that can be used 386 * for either LinearGradientPaint or RadialGradientPaint. It includes the 387 * structure and some variables that are common to each; the remaining 388 * code snippets (for CycleMethod, ColorSpaceType, and mask modulation) 389 * are filled in prior to compiling the shader at runtime depending on the 390 * paint parameters. See OGLPaints_CreateMultiGradProgram() for more details. 391 */ 392 static const char *multiGradientShaderSource = 393 // gradient texture size (in texels) 394 "const int TEXTURE_SIZE = %d;" 395 // maximum number of fractions/colors supported by this shader 396 "const int MAX_FRACTIONS = %d;" 397 // size of a single texel 398 "const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));" 399 // size of half of a single texel 400 "const float HALF_TEXEL = (FULL_TEXEL / 2.0);" 401 // texture containing the gradient colors 402 "uniform sampler1D colors;" 403 // array of gradient stops/fractions 404 "uniform float fractions[MAX_FRACTIONS];" 405 // array of scale factors (one for each interval) 406 "uniform float scaleFactors[MAX_FRACTIONS-1];" 407 // (placeholder for mask variable) 408 "%s" 409 // (placeholder for Linear/RadialGP-specific variables) 410 "%s" 411 "" 412 "void main(void)" 413 "{" 414 " float dist;" 415 // (placeholder for Linear/RadialGradientPaint-specific code) 416 " %s" 417 "" 418 " float tc;" 419 // (placeholder for CycleMethod-specific code) 420 " %s" 421 "" 422 // calculate interpolated color 423 " vec4 result = texture1D(colors, tc);" 424 "" 425 // (placeholder for ColorSpace conversion code) 426 " %s" 427 "" 428 // (placeholder for mask modulation code) 429 " %s" 430 "" 431 // modulate with gl_Color in order to apply extra alpha 432 " gl_FragColor = result * gl_Color;" 433 "}"; 434 435 /** 436 * This code takes a "dist" value as input (as calculated earlier by the 437 * LGP/RGP-specific code) in the range [0,1] and produces a texture 438 * coordinate value "tc" that represents the position of the chosen color 439 * in the one-dimensional gradient texture (also in the range [0,1]). 440 * 441 * One naive way to implement this would be to iterate through the fractions 442 * to figure out in which interval "dist" falls, and then compute the 443 * relative distance between the two nearest stops. This approach would 444 * require an "if" check on every iteration, and it is best to avoid 445 * conditionals in fragment shaders for performance reasons. Also, one might 446 * be tempted to use a break statement to jump out of the loop once the 447 * interval was found, but break statements (and non-constant loop bounds) 448 * are not natively available on most graphics hardware today, so that is 449 * a non-starter. 450 * 451 * The more optimal approach used here avoids these issues entirely by using 452 * an accumulation function that is equivalent to the process described above. 453 * The scaleFactors array is pre-initialized at enable time as follows: 454 * scaleFactors[i] = 1.0 / (fractions[i+1] - fractions[i]); 455 * 456 * For each iteration, we subtract fractions[i] from dist and then multiply 457 * that value by scaleFactors[i]. If we are within the target interval, 458 * this value will be a fraction in the range [0,1] indicating the relative 459 * distance between fraction[i] and fraction[i+1]. If we are below the 460 * target interval, this value will be negative, so we clamp it to zero 461 * to avoid accumulating any value. If we are above the target interval, 462 * the value will be greater than one, so we clamp it to one. Upon exiting 463 * the loop, we will have accumulated zero or more 1.0's and a single 464 * fractional value. This accumulated value tells us the position of the 465 * fragment color in the one-dimensional gradient texture, i.e., the 466 * texcoord called "tc". 467 */ 468 static const char *texCoordCalcCode = 469 "int i;" 470 "float relFraction = 0.0;" 471 "for (i = 0; i < MAX_FRACTIONS-1; i++) {" 472 " relFraction +=" 473 " clamp((dist - fractions[i]) * scaleFactors[i], 0.0, 1.0);" 474 "}" 475 // we offset by half a texel so that we find the linearly interpolated 476 // color between the two texel centers of interest 477 "tc = HALF_TEXEL + (FULL_TEXEL * relFraction);"; 478 479 /** Code for NO_CYCLE that gets plugged into the CycleMethod placeholder. */ 480 static const char *noCycleCode = 481 "if (dist <= 0.0) {" 482 " tc = 0.0;" 483 "} else if (dist >= 1.0) {" 484 " tc = 1.0;" 485 "} else {" 486 // (placeholder for texcoord calculation) 487 " %s" 488 "}"; 489 490 /** Code for REFLECT that gets plugged into the CycleMethod placeholder. */ 491 static const char *reflectCode = 492 "dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);" 493 // (placeholder for texcoord calculation) 494 "%s"; 495 496 /** Code for REPEAT that gets plugged into the CycleMethod placeholder. */ 497 static const char *repeatCode = 498 "dist = fract(dist);" 499 // (placeholder for texcoord calculation) 500 "%s"; 501 502 static void 503 OGLPaints_InitMultiGradientTexture() 504 { 505 GLclampf priority = 1.0f; 506 507 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_InitMultiGradientTexture"); 508 509 j2d_glGenTextures(1, &multiGradientTexID); 510 j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID); 511 j2d_glPrioritizeTextures(1, &multiGradientTexID, &priority); 512 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 513 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 514 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 515 j2d_glTexImage1D(GL_TEXTURE_1D, 0, 516 GL_RGBA8, MAX_COLORS, 0, 517 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); 518 } 519 520 /** 521 * Compiles and links the MultipleGradientPaint shader program. If 522 * successful, this function returns a handle to the newly created 523 * shader program; otherwise returns 0. 524 */ 525 static GLhandleARB 526 OGLPaints_CreateMultiGradProgram(jint flags, 527 char *paintVars, char *distCode) 528 { 529 GLhandleARB multiGradProgram; 530 GLint loc; 531 char *maskVars = ""; 532 char *maskCode = ""; 533 char *colorSpaceCode = ""; 534 char cycleCode[1500]; 535 char finalSource[3000]; 536 jint cycleMethod = EXTRACT_CYCLE_METHOD(flags); 537 jint maxFractions = IS_SET(MULTI_LARGE) ? 538 MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL; 539 540 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_CreateMultiGradProgram"); 541 542 if (IS_SET(MULTI_USE_MASK)) { 543 /* 544 * This code modulates the calculated result color with the 545 * corresponding alpha value from the alpha mask texture active 546 * on texture unit 0. Only needed when useMask is true (i.e., only 547 * for MaskFill operations). 548 */ 549 maskVars = "uniform sampler2D mask;"; 550 maskCode = "result *= texture2D(mask, gl_TexCoord[0].st);"; 551 } else { 552 /* 553 * REMIND: This is really wacky, but the gradient shaders will 554 * produce completely incorrect results on ATI hardware (at least 555 * on first-gen (R300-based) boards) if the shader program does not 556 * try to access texture coordinates by using a gl_TexCoord[*] 557 * variable. This problem really should be addressed by ATI, but 558 * in the meantime it seems we can workaround the issue by inserting 559 * a benign operation that accesses gl_TexCoord[0]. Note that we 560 * only need to do this for ATI boards and only in the !useMask case, 561 * because the useMask case already does access gl_TexCoord[1] and 562 * is therefore not affected by this driver bug. 563 */ 564 const char *vendor = (const char *)j2d_glGetString(GL_VENDOR); 565 if (vendor != NULL && strncmp(vendor, "ATI", 3) == 0) { 566 maskCode = "dist = gl_TexCoord[0].s;"; 567 } 568 } 569 570 if (IS_SET(MULTI_LINEAR_RGB)) { 571 /* 572 * This code converts a single pixel in linear RGB space back 573 * into sRGB (note: this code was adapted from the 574 * MultipleGradientPaintContext.convertLinearRGBtoSRGB() method). 575 */ 576 colorSpaceCode = 577 "result.rgb = 1.055 * pow(result.rgb, vec3(0.416667)) - 0.055;"; 578 } 579 580 if (cycleMethod == CYCLE_NONE) { 581 sprintf(cycleCode, noCycleCode, texCoordCalcCode); 582 } else if (cycleMethod == CYCLE_REFLECT) { 583 sprintf(cycleCode, reflectCode, texCoordCalcCode); 584 } else { // (cycleMethod == CYCLE_REPEAT) 585 sprintf(cycleCode, repeatCode, texCoordCalcCode); 586 } 587 588 // compose the final source code string from the various pieces 589 sprintf(finalSource, multiGradientShaderSource, 590 MAX_COLORS, maxFractions, 591 maskVars, paintVars, distCode, 592 cycleCode, colorSpaceCode, maskCode); 593 594 multiGradProgram = OGLContext_CreateFragmentProgram(finalSource); 595 if (multiGradProgram == 0) { 596 J2dRlsTraceLn(J2D_TRACE_ERROR, 597 "OGLPaints_CreateMultiGradProgram: error creating program"); 598 return 0; 599 } 600 601 // "use" the program object temporarily so that we can set the uniforms 602 j2d_glUseProgramObjectARB(multiGradProgram); 603 604 // set the "uniform" texture unit bindings 605 if (IS_SET(MULTI_USE_MASK)) { 606 loc = j2d_glGetUniformLocationARB(multiGradProgram, "mask"); 607 j2d_glUniform1iARB(loc, 0); // texture unit 0 608 loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors"); 609 j2d_glUniform1iARB(loc, 1); // texture unit 1 610 } else { 611 loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors"); 612 j2d_glUniform1iARB(loc, 0); // texture unit 0 613 } 614 615 // "unuse" the program object; it will be re-bound later as needed 616 j2d_glUseProgramObjectARB(0); 617 618 if (multiGradientTexID == 0) { 619 OGLPaints_InitMultiGradientTexture(); 620 } 621 622 return multiGradProgram; 623 } 624 625 /** 626 * Called from the OGLPaints_SetLinear/RadialGradientPaint() methods 627 * in order to setup the fraction/color values that are common to both. 628 */ 629 static void 630 OGLPaints_SetMultiGradientPaint(GLhandleARB multiGradProgram, 631 jint numStops, 632 void *pFractions, void *pPixels) 633 { 634 jint maxFractions = (numStops > MAX_FRACTIONS_SMALL) ? 635 MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL; 636 GLfloat scaleFactors[MAX_FRACTIONS-1]; 637 GLfloat *fractions = (GLfloat *)pFractions; 638 GLint *pixels = (GLint *)pPixels; 639 GLint loc; 640 int i; 641 642 // enable the MultipleGradientPaint shader 643 j2d_glUseProgramObjectARB(multiGradProgram); 644 645 // update the "uniform" fraction values 646 loc = j2d_glGetUniformLocationARB(multiGradProgram, "fractions"); 647 if (numStops < maxFractions) { 648 // fill the remainder of the fractions array with all zeros to 649 // prevent using garbage values from previous paints 650 GLfloat allZeros[MAX_FRACTIONS]; 651 memset(allZeros, 0, sizeof(GLfloat)*MAX_FRACTIONS); 652 j2d_glUniform1fvARB(loc, maxFractions, allZeros); 653 } 654 j2d_glUniform1fvARB(loc, numStops, fractions); 655 656 // update the "uniform" scale values 657 loc = j2d_glGetUniformLocationARB(multiGradProgram, "scaleFactors"); 658 for (i = 0; i < numStops-1; i++) { 659 // calculate a scale factor for each interval 660 scaleFactors[i] = 1.0f / (fractions[i+1] - fractions[i]); 661 } 662 for (; i < maxFractions-1; i++) { 663 // fill remaining scale factors with zero 664 scaleFactors[i] = 0.0f; 665 } 666 j2d_glUniform1fvARB(loc, maxFractions-1, scaleFactors); 667 668 // update the texture containing the gradient colors 669 j2d_glEnable(GL_TEXTURE_1D); 670 j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID); 671 j2d_glTexSubImage1D(GL_TEXTURE_1D, 0, 672 0, numStops, 673 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 674 pixels); 675 if (numStops < MAX_COLORS) { 676 // when we don't have enough colors to fill the entire color gradient, 677 // we have to replicate the last color in the right-most texel for 678 // the NO_CYCLE case where the texcoord is sometimes forced to 1.0 679 j2d_glTexSubImage1D(GL_TEXTURE_1D, 0, 680 MAX_COLORS-1, 1, 681 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 682 pixels+(numStops-1)); 683 } 684 } 685 686 /********************** LinearGradientPaint support *************************/ 687 688 /** 689 * The handles to the LinearGradientPaint fragment program objects. The 690 * index to the array should be a bitwise-or'ing of the MULTI_* flags defined 691 * above. Note that most applications will likely need to initialize one 692 * or two of these elements, so the array is usually sparsely populated. 693 */ 694 static GLhandleARB linearGradPrograms[MAX_PROGRAMS]; 695 696 /** 697 * Compiles and links the LinearGradientPaint shader program. If successful, 698 * this function returns a handle to the newly created shader program; 699 * otherwise returns 0. 700 */ 701 static GLhandleARB 702 OGLPaints_CreateLinearGradProgram(jint flags) 703 { 704 char *paintVars; 705 char *distCode; 706 707 J2dTraceLn1(J2D_TRACE_INFO, 708 "OGLPaints_CreateLinearGradProgram", 709 flags); 710 711 /* 712 * To simplify the code and to make it easier to upload a number of 713 * uniform values at once, we pack a bunch of scalar (float) values 714 * into vec3 values below. Here's how the values are related: 715 * 716 * params.x = p0 717 * params.y = p1 718 * params.z = p3 719 * 720 * yoff = dstOps->yOffset + dstOps->height 721 */ 722 paintVars = 723 "uniform vec3 params;" 724 "uniform float yoff;"; 725 distCode = 726 // note that gl_FragCoord is in window space relative to the 727 // lower-left corner, so we have to flip the y-coordinate here 728 "vec3 fragCoord = vec3(gl_FragCoord.x, yoff-gl_FragCoord.y, 1.0);" 729 "dist = dot(params, fragCoord);"; 730 731 return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode); 732 } 733 734 void 735 OGLPaints_SetLinearGradientPaint(OGLContext *oglc, OGLSDOps *dstOps, 736 jboolean useMask, jboolean linear, 737 jint cycleMethod, jint numStops, 738 jfloat p0, jfloat p1, jfloat p3, 739 void *fractions, void *pixels) 740 { 741 GLhandleARB linearGradProgram; 742 GLint loc; 743 jboolean large = (numStops > MAX_FRACTIONS_SMALL); 744 jint flags = 0; 745 746 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetLinearGradientPaint"); 747 748 RETURN_IF_NULL(oglc); 749 RETURN_IF_NULL(dstOps); 750 OGLPaints_ResetPaint(oglc); 751 752 COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear); 753 754 if (useMask) { 755 // set up the paint on texture unit 1 (instead of the usual unit 0) 756 j2d_glActiveTextureARB(GL_TEXTURE1_ARB); 757 } 758 // no need to set GL_MODULATE here (it is ignored when shader is enabled) 759 760 // locate/initialize the shader program for the given flags 761 if (linearGradPrograms[flags] == 0) { 762 linearGradPrograms[flags] = OGLPaints_CreateLinearGradProgram(flags); 763 if (linearGradPrograms[flags] == 0) { 764 // shouldn't happen, but just in case... 765 return; 766 } 767 } 768 linearGradProgram = linearGradPrograms[flags]; 769 770 // update the common "uniform" values (fractions and colors) 771 OGLPaints_SetMultiGradientPaint(linearGradProgram, 772 numStops, fractions, pixels); 773 774 // update the other "uniform" values 775 loc = j2d_glGetUniformLocationARB(linearGradProgram, "params"); 776 j2d_glUniform3fARB(loc, p0, p1, p3); 777 loc = j2d_glGetUniformLocationARB(linearGradProgram, "yoff"); 778 j2d_glUniform1fARB(loc, (GLfloat)(dstOps->yOffset + dstOps->height)); 779 780 if (useMask) { 781 // restore control to texture unit 0 782 j2d_glActiveTextureARB(GL_TEXTURE0_ARB); 783 } 784 785 // oglc->pixel has been set appropriately in OGLPaints_ResetPaint() 786 oglc->useMask = useMask; 787 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT; 788 } 789 790 /********************** RadialGradientPaint support *************************/ 791 792 /** 793 * The handles to the RadialGradientPaint fragment program objects. The 794 * index to the array should be a bitwise-or'ing of the MULTI_* flags defined 795 * above. Note that most applications will likely need to initialize one 796 * or two of these elements, so the array is usually sparsely populated. 797 */ 798 static GLhandleARB radialGradPrograms[MAX_PROGRAMS]; 799 800 /** 801 * Compiles and links the RadialGradientPaint shader program. If successful, 802 * this function returns a handle to the newly created shader program; 803 * otherwise returns 0. 804 */ 805 static GLhandleARB 806 OGLPaints_CreateRadialGradProgram(jint flags) 807 { 808 char *paintVars; 809 char *distCode; 810 811 J2dTraceLn1(J2D_TRACE_INFO, 812 "OGLPaints_CreateRadialGradProgram", 813 flags); 814 815 /* 816 * To simplify the code and to make it easier to upload a number of 817 * uniform values at once, we pack a bunch of scalar (float) values 818 * into vec3 and vec4 values below. Here's how the values are related: 819 * 820 * m0.x = m00 821 * m0.y = m01 822 * m0.z = m02 823 * 824 * m1.x = m10 825 * m1.y = m11 826 * m1.z = m12 827 * 828 * precalc.x = focusX 829 * precalc.y = yoff = dstOps->yOffset + dstOps->height 830 * precalc.z = 1.0 - (focusX * focusX) 831 * precalc.w = 1.0 / precalc.z 832 */ 833 paintVars = 834 "uniform vec3 m0;" 835 "uniform vec3 m1;" 836 "uniform vec4 precalc;"; 837 838 /* 839 * The following code is derived from Daniel Rice's whitepaper on 840 * radial gradient performance (attached to the bug report for 6521533). 841 * Refer to that document as well as the setup code in the Java-level 842 * BufferedPaints.setRadialGradientPaint() method for more details. 843 */ 844 distCode = 845 // note that gl_FragCoord is in window space relative to the 846 // lower-left corner, so we have to flip the y-coordinate here 847 "vec3 fragCoord =" 848 " vec3(gl_FragCoord.x, precalc.y - gl_FragCoord.y, 1.0);" 849 "float x = dot(fragCoord, m0);" 850 "float y = dot(fragCoord, m1);" 851 "float xfx = x - precalc.x;" 852 "dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.z))*precalc.w;"; 853 854 return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode); 855 } 856 857 void 858 OGLPaints_SetRadialGradientPaint(OGLContext *oglc, OGLSDOps *dstOps, 859 jboolean useMask, jboolean linear, 860 jint cycleMethod, jint numStops, 861 jfloat m00, jfloat m01, jfloat m02, 862 jfloat m10, jfloat m11, jfloat m12, 863 jfloat focusX, 864 void *fractions, void *pixels) 865 { 866 GLhandleARB radialGradProgram; 867 GLint loc; 868 GLfloat yoff, denom, inv_denom; 869 jboolean large = (numStops > MAX_FRACTIONS_SMALL); 870 jint flags = 0; 871 872 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetRadialGradientPaint"); 873 874 RETURN_IF_NULL(oglc); 875 RETURN_IF_NULL(dstOps); 876 OGLPaints_ResetPaint(oglc); 877 878 COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear); 879 880 if (useMask) { 881 // set up the paint on texture unit 1 (instead of the usual unit 0) 882 j2d_glActiveTextureARB(GL_TEXTURE1_ARB); 883 } 884 // no need to set GL_MODULATE here (it is ignored when shader is enabled) 885 886 // locate/initialize the shader program for the given flags 887 if (radialGradPrograms[flags] == 0) { 888 radialGradPrograms[flags] = OGLPaints_CreateRadialGradProgram(flags); 889 if (radialGradPrograms[flags] == 0) { 890 // shouldn't happen, but just in case... 891 return; 892 } 893 } 894 radialGradProgram = radialGradPrograms[flags]; 895 896 // update the common "uniform" values (fractions and colors) 897 OGLPaints_SetMultiGradientPaint(radialGradProgram, 898 numStops, fractions, pixels); 899 900 // update the other "uniform" values 901 loc = j2d_glGetUniformLocationARB(radialGradProgram, "m0"); 902 j2d_glUniform3fARB(loc, m00, m01, m02); 903 loc = j2d_glGetUniformLocationARB(radialGradProgram, "m1"); 904 j2d_glUniform3fARB(loc, m10, m11, m12); 905 906 // pack a few unrelated, precalculated values into a single vec4 907 yoff = (GLfloat)(dstOps->yOffset + dstOps->height); 908 denom = 1.0f - (focusX * focusX); 909 inv_denom = 1.0f / denom; 910 loc = j2d_glGetUniformLocationARB(radialGradProgram, "precalc"); 911 j2d_glUniform4fARB(loc, focusX, yoff, denom, inv_denom); 912 913 if (useMask) { 914 // restore control to texture unit 0 915 j2d_glActiveTextureARB(GL_TEXTURE0_ARB); 916 } 917 918 // oglc->pixel has been set appropriately in OGLPaints_ResetPaint() 919 oglc->useMask = useMask; 920 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT; 921 } 922 923 #endif /* !HEADLESS */