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 code takes a "dist" value as input (as calculated earlier by the 386 * LGP/RGP-specific code) in the range [0,1] and produces a texture 387 * coordinate value "tc" that represents the position of the chosen color 388 * in the one-dimensional gradient texture (also in the range [0,1]). 389 * 390 * One naive way to implement this would be to iterate through the fractions 391 * to figure out in which interval "dist" falls, and then compute the 392 * relative distance between the two nearest stops. This approach would 393 * require an "if" check on every iteration, and it is best to avoid 394 * conditionals in fragment shaders for performance reasons. Also, one might 395 * be tempted to use a break statement to jump out of the loop once the 396 * interval was found, but break statements (and non-constant loop bounds) 397 * are not natively available on most graphics hardware today, so that is 398 * a non-starter. 399 * 400 * The more optimal approach used here avoids these issues entirely by using 401 * an accumulation function that is equivalent to the process described above. 402 * The scaleFactors array is pre-initialized at enable time as follows: 403 * scaleFactors[i] = 1.0 / (fractions[i+1] - fractions[i]); 404 * 405 * For each iteration, we subtract fractions[i] from dist and then multiply 406 * that value by scaleFactors[i]. If we are within the target interval, 407 * this value will be a fraction in the range [0,1] indicating the relative 408 * distance between fraction[i] and fraction[i+1]. If we are below the 409 * target interval, this value will be negative, so we clamp it to zero 410 * to avoid accumulating any value. If we are above the target interval, 411 * the value will be greater than one, so we clamp it to one. Upon exiting 412 * the loop, we will have accumulated zero or more 1.0's and a single 413 * fractional value. This accumulated value tells us the position of the 414 * fragment color in the one-dimensional gradient texture, i.e., the 415 * texcoord called "tc". 416 */ 417 static const char *texCoordCalcCode = 418 "int i;" 419 "float relFraction = 0.0;" 420 "for (i = 0; i < MAX_FRACTIONS-1; i++) {" 421 " relFraction +=" 422 " clamp((dist - fractions[i]) * scaleFactors[i], 0.0, 1.0);" 423 "}" 424 // we offset by half a texel so that we find the linearly interpolated 425 // color between the two texel centers of interest 426 "tc = HALF_TEXEL + (FULL_TEXEL * relFraction);"; 427 428 static void 429 OGLPaints_InitMultiGradientTexture() 430 { 431 GLclampf priority = 1.0f; 432 433 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_InitMultiGradientTexture"); 434 435 j2d_glGenTextures(1, &multiGradientTexID); 436 j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID); 437 j2d_glPrioritizeTextures(1, &multiGradientTexID, &priority); 438 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 439 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 440 j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 441 j2d_glTexImage1D(GL_TEXTURE_1D, 0, 442 GL_RGBA8, MAX_COLORS, 0, 443 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); 444 } 445 446 /** 447 * Compiles and links the MultipleGradientPaint shader program. If 448 * successful, this function returns a handle to the newly created 449 * shader program; otherwise returns 0. 450 */ 451 static GLhandleARB 452 OGLPaints_CreateMultiGradProgram(jint flags, 453 char *paintVars, char *distCode) 454 { 455 GLhandleARB multiGradProgram; 456 GLint loc; 457 char *maskVars = ""; 458 char *maskCode = ""; 459 char *colorSpaceCode = ""; 460 char cycleCode[1500]; 461 char finalSource[3000]; 462 jint cycleMethod = EXTRACT_CYCLE_METHOD(flags); 463 jint maxFractions = IS_SET(MULTI_LARGE) ? 464 MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL; 465 466 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_CreateMultiGradProgram"); 467 468 if (IS_SET(MULTI_USE_MASK)) { 469 /* 470 * This code modulates the calculated result color with the 471 * corresponding alpha value from the alpha mask texture active 472 * on texture unit 0. Only needed when useMask is true (i.e., only 473 * for MaskFill operations). 474 */ 475 maskVars = "uniform sampler2D mask;"; 476 maskCode = "result *= texture2D(mask, gl_TexCoord[0].st);"; 477 } else { 478 /* 479 * REMIND: This is really wacky, but the gradient shaders will 480 * produce completely incorrect results on ATI hardware (at least 481 * on first-gen (R300-based) boards) if the shader program does not 482 * try to access texture coordinates by using a gl_TexCoord[*] 483 * variable. This problem really should be addressed by ATI, but 484 * in the meantime it seems we can workaround the issue by inserting 485 * a benign operation that accesses gl_TexCoord[0]. Note that we 486 * only need to do this for ATI boards and only in the !useMask case, 487 * because the useMask case already does access gl_TexCoord[1] and 488 * is therefore not affected by this driver bug. 489 */ 490 const char *vendor = (const char *)j2d_glGetString(GL_VENDOR); 491 if (vendor != NULL && strncmp(vendor, "ATI", 3) == 0) { 492 maskCode = "dist = gl_TexCoord[0].s;"; 493 } 494 } 495 496 if (IS_SET(MULTI_LINEAR_RGB)) { 497 /* 498 * This code converts a single pixel in linear RGB space back 499 * into sRGB (note: this code was adapted from the 500 * MultipleGradientPaintContext.convertLinearRGBtoSRGB() method). 501 */ 502 colorSpaceCode = 503 "result.rgb = 1.055 * pow(result.rgb, vec3(0.416667)) - 0.055;"; 504 } 505 506 if (cycleMethod == CYCLE_NONE) { 507 sprintf(cycleCode, 508 /** Code for NO_CYCLE that gets plugged into the CycleMethod placeholder. */ 509 "if (dist <= 0.0) {" 510 " tc = 0.0;" 511 "} else if (dist >= 1.0) {" 512 " tc = 1.0;" 513 "} else {" 514 // (placeholder for texcoord calculation) 515 " %s", texCoordCalcCode); 516 } else if (cycleMethod == CYCLE_REFLECT) { 517 sprintf(cycleCode, 518 /** Code for REFLECT that gets plugged into the CycleMethod placeholder. */ 519 "dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);" 520 // (placeholder for texcoord calculation) 521 "%s", texCoordCalcCode); 522 } else { // (cycleMethod == CYCLE_REPEAT) 523 sprintf(cycleCode, 524 /** Code for REPEAT that gets plugged into the CycleMethod placeholder. */ 525 "dist = fract(dist);" 526 // (placeholder for texcoord calculation) 527 "%s", texCoordCalcCode); 528 } 529 530 // compose the final source code string from the various pieces 531 sprintf(finalSource, 532 /** 533 * This is essentially a template of the shader source code that can be used 534 * for either LinearGradientPaint or RadialGradientPaint. It includes the 535 * structure and some variables that are common to each; the remaining 536 * code snippets (for CycleMethod, ColorSpaceType, and mask modulation) 537 * are filled in prior to compiling the shader at runtime depending on the 538 * paint parameters. See OGLPaints_CreateMultiGradProgram() for more details. 539 */ 540 // gradient texture size (in texels) 541 "const int TEXTURE_SIZE = %d;" 542 // maximum number of fractions/colors supported by this shader 543 "const int MAX_FRACTIONS = %d;" 544 // size of a single texel 545 "const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));" 546 // size of half of a single texel 547 "const float HALF_TEXEL = (FULL_TEXEL / 2.0);" 548 // texture containing the gradient colors 549 "uniform sampler1D colors;" 550 // array of gradient stops/fractions 551 "uniform float fractions[MAX_FRACTIONS];" 552 // array of scale factors (one for each interval) 553 "uniform float scaleFactors[MAX_FRACTIONS-1];" 554 // (placeholder for mask variable) 555 "%s" 556 // (placeholder for Linear/RadialGP-specific variables) 557 "%s" 558 "" 559 "void main(void)" 560 "{" 561 " float dist;" 562 // (placeholder for Linear/RadialGradientPaint-specific code) 563 " %s" 564 "" 565 " float tc;" 566 // (placeholder for CycleMethod-specific code) 567 " %s" 568 "" 569 // calculate interpolated color 570 " vec4 result = texture1D(colors, tc);" 571 "" 572 // (placeholder for ColorSpace conversion code) 573 " %s" 574 "" 575 // (placeholder for mask modulation code) 576 " %s" 577 "" 578 // modulate with gl_Color in order to apply extra alpha 579 " gl_FragColor = result * gl_Color;" 580 "}", MAX_COLORS, maxFractions, 581 maskVars, paintVars, distCode, 582 cycleCode, colorSpaceCode, maskCode); 583 584 multiGradProgram = OGLContext_CreateFragmentProgram(finalSource); 585 if (multiGradProgram == 0) { 586 J2dRlsTraceLn(J2D_TRACE_ERROR, 587 "OGLPaints_CreateMultiGradProgram: error creating program"); 588 return 0; 589 } 590 591 // "use" the program object temporarily so that we can set the uniforms 592 j2d_glUseProgramObjectARB(multiGradProgram); 593 594 // set the "uniform" texture unit bindings 595 if (IS_SET(MULTI_USE_MASK)) { 596 loc = j2d_glGetUniformLocationARB(multiGradProgram, "mask"); 597 j2d_glUniform1iARB(loc, 0); // texture unit 0 598 loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors"); 599 j2d_glUniform1iARB(loc, 1); // texture unit 1 600 } else { 601 loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors"); 602 j2d_glUniform1iARB(loc, 0); // texture unit 0 603 } 604 605 // "unuse" the program object; it will be re-bound later as needed 606 j2d_glUseProgramObjectARB(0); 607 608 if (multiGradientTexID == 0) { 609 OGLPaints_InitMultiGradientTexture(); 610 } 611 612 return multiGradProgram; 613 } 614 615 /** 616 * Called from the OGLPaints_SetLinear/RadialGradientPaint() methods 617 * in order to setup the fraction/color values that are common to both. 618 */ 619 static void 620 OGLPaints_SetMultiGradientPaint(GLhandleARB multiGradProgram, 621 jint numStops, 622 void *pFractions, void *pPixels) 623 { 624 jint maxFractions = (numStops > MAX_FRACTIONS_SMALL) ? 625 MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL; 626 GLfloat scaleFactors[MAX_FRACTIONS-1]; 627 GLfloat *fractions = (GLfloat *)pFractions; 628 GLint *pixels = (GLint *)pPixels; 629 GLint loc; 630 int i; 631 632 // enable the MultipleGradientPaint shader 633 j2d_glUseProgramObjectARB(multiGradProgram); 634 635 // update the "uniform" fraction values 636 loc = j2d_glGetUniformLocationARB(multiGradProgram, "fractions"); 637 if (numStops < maxFractions) { 638 // fill the remainder of the fractions array with all zeros to 639 // prevent using garbage values from previous paints 640 GLfloat allZeros[MAX_FRACTIONS]; 641 memset(allZeros, 0, sizeof(GLfloat)*MAX_FRACTIONS); 642 j2d_glUniform1fvARB(loc, maxFractions, allZeros); 643 } 644 j2d_glUniform1fvARB(loc, numStops, fractions); 645 646 // update the "uniform" scale values 647 loc = j2d_glGetUniformLocationARB(multiGradProgram, "scaleFactors"); 648 for (i = 0; i < numStops-1; i++) { 649 // calculate a scale factor for each interval 650 scaleFactors[i] = 1.0f / (fractions[i+1] - fractions[i]); 651 } 652 for (; i < maxFractions-1; i++) { 653 // fill remaining scale factors with zero 654 scaleFactors[i] = 0.0f; 655 } 656 j2d_glUniform1fvARB(loc, maxFractions-1, scaleFactors); 657 658 // update the texture containing the gradient colors 659 j2d_glEnable(GL_TEXTURE_1D); 660 j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID); 661 j2d_glTexSubImage1D(GL_TEXTURE_1D, 0, 662 0, numStops, 663 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 664 pixels); 665 if (numStops < MAX_COLORS) { 666 // when we don't have enough colors to fill the entire color gradient, 667 // we have to replicate the last color in the right-most texel for 668 // the NO_CYCLE case where the texcoord is sometimes forced to 1.0 669 j2d_glTexSubImage1D(GL_TEXTURE_1D, 0, 670 MAX_COLORS-1, 1, 671 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 672 pixels+(numStops-1)); 673 } 674 } 675 676 /********************** LinearGradientPaint support *************************/ 677 678 /** 679 * The handles to the LinearGradientPaint fragment program objects. The 680 * index to the array should be a bitwise-or'ing of the MULTI_* flags defined 681 * above. Note that most applications will likely need to initialize one 682 * or two of these elements, so the array is usually sparsely populated. 683 */ 684 static GLhandleARB linearGradPrograms[MAX_PROGRAMS]; 685 686 /** 687 * Compiles and links the LinearGradientPaint shader program. If successful, 688 * this function returns a handle to the newly created shader program; 689 * otherwise returns 0. 690 */ 691 static GLhandleARB 692 OGLPaints_CreateLinearGradProgram(jint flags) 693 { 694 char *paintVars; 695 char *distCode; 696 697 J2dTraceLn1(J2D_TRACE_INFO, 698 "OGLPaints_CreateLinearGradProgram", 699 flags); 700 701 /* 702 * To simplify the code and to make it easier to upload a number of 703 * uniform values at once, we pack a bunch of scalar (float) values 704 * into vec3 values below. Here's how the values are related: 705 * 706 * params.x = p0 707 * params.y = p1 708 * params.z = p3 709 * 710 * yoff = dstOps->yOffset + dstOps->height 711 */ 712 paintVars = 713 "uniform vec3 params;" 714 "uniform float yoff;"; 715 distCode = 716 // note that gl_FragCoord is in window space relative to the 717 // lower-left corner, so we have to flip the y-coordinate here 718 "vec3 fragCoord = vec3(gl_FragCoord.x, yoff-gl_FragCoord.y, 1.0);" 719 "dist = dot(params, fragCoord);"; 720 721 return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode); 722 } 723 724 void 725 OGLPaints_SetLinearGradientPaint(OGLContext *oglc, OGLSDOps *dstOps, 726 jboolean useMask, jboolean linear, 727 jint cycleMethod, jint numStops, 728 jfloat p0, jfloat p1, jfloat p3, 729 void *fractions, void *pixels) 730 { 731 GLhandleARB linearGradProgram; 732 GLint loc; 733 jboolean large = (numStops > MAX_FRACTIONS_SMALL); 734 jint flags = 0; 735 736 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetLinearGradientPaint"); 737 738 RETURN_IF_NULL(oglc); 739 RETURN_IF_NULL(dstOps); 740 OGLPaints_ResetPaint(oglc); 741 742 COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear); 743 744 if (useMask) { 745 // set up the paint on texture unit 1 (instead of the usual unit 0) 746 j2d_glActiveTextureARB(GL_TEXTURE1_ARB); 747 } 748 // no need to set GL_MODULATE here (it is ignored when shader is enabled) 749 750 // locate/initialize the shader program for the given flags 751 if (linearGradPrograms[flags] == 0) { 752 linearGradPrograms[flags] = OGLPaints_CreateLinearGradProgram(flags); 753 if (linearGradPrograms[flags] == 0) { 754 // shouldn't happen, but just in case... 755 return; 756 } 757 } 758 linearGradProgram = linearGradPrograms[flags]; 759 760 // update the common "uniform" values (fractions and colors) 761 OGLPaints_SetMultiGradientPaint(linearGradProgram, 762 numStops, fractions, pixels); 763 764 // update the other "uniform" values 765 loc = j2d_glGetUniformLocationARB(linearGradProgram, "params"); 766 j2d_glUniform3fARB(loc, p0, p1, p3); 767 loc = j2d_glGetUniformLocationARB(linearGradProgram, "yoff"); 768 j2d_glUniform1fARB(loc, (GLfloat)(dstOps->yOffset + dstOps->height)); 769 770 if (useMask) { 771 // restore control to texture unit 0 772 j2d_glActiveTextureARB(GL_TEXTURE0_ARB); 773 } 774 775 // oglc->pixel has been set appropriately in OGLPaints_ResetPaint() 776 oglc->useMask = useMask; 777 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT; 778 } 779 780 /********************** RadialGradientPaint support *************************/ 781 782 /** 783 * The handles to the RadialGradientPaint fragment program objects. The 784 * index to the array should be a bitwise-or'ing of the MULTI_* flags defined 785 * above. Note that most applications will likely need to initialize one 786 * or two of these elements, so the array is usually sparsely populated. 787 */ 788 static GLhandleARB radialGradPrograms[MAX_PROGRAMS]; 789 790 /** 791 * Compiles and links the RadialGradientPaint shader program. If successful, 792 * this function returns a handle to the newly created shader program; 793 * otherwise returns 0. 794 */ 795 static GLhandleARB 796 OGLPaints_CreateRadialGradProgram(jint flags) 797 { 798 char *paintVars; 799 char *distCode; 800 801 J2dTraceLn1(J2D_TRACE_INFO, 802 "OGLPaints_CreateRadialGradProgram", 803 flags); 804 805 /* 806 * To simplify the code and to make it easier to upload a number of 807 * uniform values at once, we pack a bunch of scalar (float) values 808 * into vec3 and vec4 values below. Here's how the values are related: 809 * 810 * m0.x = m00 811 * m0.y = m01 812 * m0.z = m02 813 * 814 * m1.x = m10 815 * m1.y = m11 816 * m1.z = m12 817 * 818 * precalc.x = focusX 819 * precalc.y = yoff = dstOps->yOffset + dstOps->height 820 * precalc.z = 1.0 - (focusX * focusX) 821 * precalc.w = 1.0 / precalc.z 822 */ 823 paintVars = 824 "uniform vec3 m0;" 825 "uniform vec3 m1;" 826 "uniform vec4 precalc;"; 827 828 /* 829 * The following code is derived from Daniel Rice's whitepaper on 830 * radial gradient performance (attached to the bug report for 6521533). 831 * Refer to that document as well as the setup code in the Java-level 832 * BufferedPaints.setRadialGradientPaint() method for more details. 833 */ 834 distCode = 835 // note that gl_FragCoord is in window space relative to the 836 // lower-left corner, so we have to flip the y-coordinate here 837 "vec3 fragCoord =" 838 " vec3(gl_FragCoord.x, precalc.y - gl_FragCoord.y, 1.0);" 839 "float x = dot(fragCoord, m0);" 840 "float y = dot(fragCoord, m1);" 841 "float xfx = x - precalc.x;" 842 "dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.z))*precalc.w;"; 843 844 return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode); 845 } 846 847 void 848 OGLPaints_SetRadialGradientPaint(OGLContext *oglc, OGLSDOps *dstOps, 849 jboolean useMask, jboolean linear, 850 jint cycleMethod, jint numStops, 851 jfloat m00, jfloat m01, jfloat m02, 852 jfloat m10, jfloat m11, jfloat m12, 853 jfloat focusX, 854 void *fractions, void *pixels) 855 { 856 GLhandleARB radialGradProgram; 857 GLint loc; 858 GLfloat yoff, denom, inv_denom; 859 jboolean large = (numStops > MAX_FRACTIONS_SMALL); 860 jint flags = 0; 861 862 J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetRadialGradientPaint"); 863 864 RETURN_IF_NULL(oglc); 865 RETURN_IF_NULL(dstOps); 866 OGLPaints_ResetPaint(oglc); 867 868 COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear); 869 870 if (useMask) { 871 // set up the paint on texture unit 1 (instead of the usual unit 0) 872 j2d_glActiveTextureARB(GL_TEXTURE1_ARB); 873 } 874 // no need to set GL_MODULATE here (it is ignored when shader is enabled) 875 876 // locate/initialize the shader program for the given flags 877 if (radialGradPrograms[flags] == 0) { 878 radialGradPrograms[flags] = OGLPaints_CreateRadialGradProgram(flags); 879 if (radialGradPrograms[flags] == 0) { 880 // shouldn't happen, but just in case... 881 return; 882 } 883 } 884 radialGradProgram = radialGradPrograms[flags]; 885 886 // update the common "uniform" values (fractions and colors) 887 OGLPaints_SetMultiGradientPaint(radialGradProgram, 888 numStops, fractions, pixels); 889 890 // update the other "uniform" values 891 loc = j2d_glGetUniformLocationARB(radialGradProgram, "m0"); 892 j2d_glUniform3fARB(loc, m00, m01, m02); 893 loc = j2d_glGetUniformLocationARB(radialGradProgram, "m1"); 894 j2d_glUniform3fARB(loc, m10, m11, m12); 895 896 // pack a few unrelated, precalculated values into a single vec4 897 yoff = (GLfloat)(dstOps->yOffset + dstOps->height); 898 denom = 1.0f - (focusX * focusX); 899 inv_denom = 1.0f / denom; 900 loc = j2d_glGetUniformLocationARB(radialGradProgram, "precalc"); 901 j2d_glUniform4fARB(loc, focusX, yoff, denom, inv_denom); 902 903 if (useMask) { 904 // restore control to texture unit 0 905 j2d_glActiveTextureARB(GL_TEXTURE0_ARB); 906 } 907 908 // oglc->pixel has been set appropriately in OGLPaints_ResetPaint() 909 oglc->useMask = useMask; 910 oglc->paintState = sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT; 911 } 912 913 #endif /* !HEADLESS */