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