< 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", 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 {


< prev index next >