< prev index next >

src/java.desktop/share/native/common/java2d/opengl/OGLPaints.c

Print this page




 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"
 516                 "}", texCoordCalcCode);
 517     } else if (cycleMethod == CYCLE_REFLECT) {
 518         sprintf(cycleCode,
 519     /** Code for REFLECT that gets plugged into the CycleMethod placeholder. */
 520             "dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);"
 521             // (placeholder for texcoord calculation)
 522             "%s", texCoordCalcCode);
 523     } else { // (cycleMethod == CYCLE_REPEAT)
 524         sprintf(cycleCode,
 525     /** Code for REPEAT that gets plugged into the CycleMethod placeholder. */
 526             "dist = fract(dist);"
 527             // (placeholder for texcoord calculation)
 528             "%s", texCoordCalcCode);
 529     }
 530 
 531     // compose the final source code string from the various pieces
 532     sprintf(finalSource,
 533 /**
 534  * This is essentially a template of the shader source code that can be used
 535  * for either LinearGradientPaint or RadialGradientPaint.  It includes the
 536  * structure and some variables that are common to each; the remaining
 537  * code snippets (for CycleMethod, ColorSpaceType, and mask modulation)
 538  * are filled in prior to compiling the shader at runtime depending on the
 539  * paint parameters.  See OGLPaints_CreateMultiGradProgram() for more details.
 540  */
 541         // gradient texture size (in texels)
 542         "const int TEXTURE_SIZE = %d;"
 543         // maximum number of fractions/colors supported by this shader
 544         "const int MAX_FRACTIONS = %d;"
 545         // size of a single texel
 546         "const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));"
 547         // size of half of a single texel
 548         "const float HALF_TEXEL = (FULL_TEXEL / 2.0);"
 549         // texture containing the gradient colors
 550         "uniform sampler1D colors;"
 551         // array of gradient stops/fractions
 552         "uniform float fractions[MAX_FRACTIONS];"
 553         // array of scale factors (one for each interval)
 554         "uniform float scaleFactors[MAX_FRACTIONS-1];"
 555         // (placeholder for mask variable)
 556         "%s"
 557         // (placeholder for Linear/RadialGP-specific variables)
 558         "%s"
 559         ""
 560         "void main(void)"
 561         "{"
 562         "    float dist;"
 563              // (placeholder for Linear/RadialGradientPaint-specific code)
 564         "    %s"
 565         ""
 566         "    float tc;"
 567              // (placeholder for CycleMethod-specific code)
 568         "    %s"
 569         ""
 570              // calculate interpolated color
 571         "    vec4 result = texture1D(colors, tc);"
 572         ""
 573              // (placeholder for ColorSpace conversion code)
 574         "    %s"
 575         ""
 576              // (placeholder for mask modulation code)
 577         "    %s"
 578         ""
 579              // modulate with gl_Color in order to apply extra alpha
 580         "    gl_FragColor = result * gl_Color;"
 581         "}", MAX_COLORS, maxFractions,
 582             maskVars, paintVars, distCode,
 583             cycleCode, colorSpaceCode, maskCode);
 584 
 585     multiGradProgram = OGLContext_CreateFragmentProgram(finalSource);
 586     if (multiGradProgram == 0) {
 587         J2dRlsTraceLn(J2D_TRACE_ERROR,
 588             "OGLPaints_CreateMultiGradProgram: error creating program");
 589         return 0;
 590     }
 591 
 592     // "use" the program object temporarily so that we can set the uniforms
 593     j2d_glUseProgramObjectARB(multiGradProgram);
 594 
 595     // set the "uniform" texture unit bindings
 596     if (IS_SET(MULTI_USE_MASK)) {
 597         loc = j2d_glGetUniformLocationARB(multiGradProgram, "mask");
 598         j2d_glUniform1iARB(loc, 0); // texture unit 0
 599         loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");
 600         j2d_glUniform1iARB(loc, 1); // texture unit 1
 601     } else {


< prev index next >