< prev index next >

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

Print this page




 284  *
 285  * The variables involved in the equation can be expressed as follows:
 286  *
 287  *   Cs = Color component of the source (foreground color) [0.0, 1.0]
 288  *   Cd = Color component of the destination (background color) [0.0, 1.0]
 289  *   Cr = Color component to be written to the destination [0.0, 1.0]
 290  *   Ag = Glyph alpha (aka intensity or coverage) [0.0, 1.0]
 291  *   Ga = Gamma adjustment in the range [1.0, 2.5]
 292  *   (^ means raised to the power)
 293  *
 294  * And here is the theoretical equation approximated by this shader:
 295  *
 296  *            Cr = (Ag*(Cs^Ga) + (1-Ag)*(Cd^Ga)) ^ (1/Ga)
 297  */
 298 static const char *lcdTextShaderSource =
 299     "uniform vec3 src_adj;"
 300     "uniform sampler2D glyph_tex;"
 301     "uniform sampler2D dst_tex;"
 302     "uniform sampler3D invgamma_tex;"
 303     "uniform sampler3D gamma_tex;"


 304     ""
 305     "void main(void)"
 306     "{"
 307          // load the RGB value from the glyph image at the current texcoord
 308     "    vec3 glyph_clr = vec3(texture2D(glyph_tex, gl_TexCoord[0].st));"
 309     "    if (glyph_clr == vec3(0.0)) {"
 310              // zero coverage, so skip this fragment
 311     "        discard;"
 312     "    }"
 313          // load the RGB value from the corresponding destination pixel
 314     "    vec3 dst_clr = vec3(texture2D(dst_tex, gl_TexCoord[1].st));"
 315          // gamma adjust the dest color using the invgamma LUT
 316     "    vec3 dst_adj = vec3(texture3D(invgamma_tex, dst_clr.stp));"
 317          // linearly interpolate the three color values
 318     "    vec3 result = mix(dst_adj, src_adj, glyph_clr);"
 319          // gamma re-adjust the resulting color (alpha is always set to 1.0)
 320     "    gl_FragColor = vec4(vec3(texture3D(gamma_tex, result.stp)), 1.0);"
 321     "}";
 322 
 323 /**
 324  * Compiles and links the LCD text shader program.  If successful, this
 325  * function returns a handle to the newly created shader program; otherwise
 326  * returns 0.
 327  */
 328 static GLhandleARB
 329 OGLTR_CreateLCDTextProgram()
 330 {
 331     GLhandleARB lcdTextProgram;
 332     GLint loc;
 333 
 334     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_CreateLCDTextProgram");
 335 
 336     lcdTextProgram = OGLContext_CreateFragmentProgram(lcdTextShaderSource);
 337     if (lcdTextProgram == 0) {
 338         J2dRlsTraceLn(J2D_TRACE_ERROR,
 339                       "OGLTR_CreateLCDTextProgram: error creating program");
 340         return 0;


 405  * that essentially calculates pow(x, gamma) and the other calculates
 406  * pow(x, 1/gamma).  These values are replicated in all three dimensions, so
 407  * given a single 3D texture coordinate (typically this will be a triplet
 408  * in the form (r,g,b)), the 3D texture lookup will return an RGB triplet:
 409  *
 410  *     (pow(r,g), pow(y,g), pow(z,g)
 411  *
 412  * where g is either gamma or 1/gamma, depending on the table.
 413  */
 414 static jboolean
 415 OGLTR_UpdateLCDTextContrast(jint contrast)
 416 {
 417     double gamma = ((double)contrast) / 100.0;
 418     double ig = gamma;
 419     double g = 1.0 / ig;
 420     GLfloat lut[LUT_EDGE][LUT_EDGE][LUT_EDGE][3];
 421     GLfloat invlut[LUT_EDGE][LUT_EDGE][LUT_EDGE][3];
 422     int min = 0;
 423     int max = LUT_EDGE - 1;
 424     int x, y, z;

 425 
 426     J2dTraceLn1(J2D_TRACE_INFO,
 427                 "OGLTR_UpdateLCDTextContrast: contrast=%d", contrast);
 428 






 429     for (z = min; z <= max; z++) {
 430         double zval = ((double)z) / max;
 431         GLfloat gz = (GLfloat)pow(zval, g);
 432         GLfloat igz = (GLfloat)pow(zval, ig);
 433 
 434         for (y = min; y <= max; y++) {
 435             double yval = ((double)y) / max;
 436             GLfloat gy = (GLfloat)pow(yval, g);
 437             GLfloat igy = (GLfloat)pow(yval, ig);
 438 
 439             for (x = min; x <= max; x++) {
 440                 double xval = ((double)x) / max;
 441                 GLfloat gx = (GLfloat)pow(xval, g);
 442                 GLfloat igx = (GLfloat)pow(xval, ig);
 443 
 444                 lut[z][y][x][0] = gx;
 445                 lut[z][y][x][1] = gy;
 446                 lut[z][y][x][2] = gz;
 447 
 448                 invlut[z][y][x][0] = igx;


 461         invGammaLutTextureID = OGLTR_InitGammaLutTexture();
 462     }
 463     OGLTR_UpdateGammaLutTexture(invGammaLutTextureID,
 464                                 (GLfloat *)invlut, LUT_EDGE);
 465 
 466     return JNI_TRUE;
 467 }
 468 
 469 /**
 470  * Updates the current gamma-adjusted source color ("src_adj") of the LCD
 471  * text shader program.  Note that we could calculate this value in the
 472  * shader (e.g. just as we do for "dst_adj"), but would be unnecessary work
 473  * (and a measurable performance hit, maybe around 5%) since this value is
 474  * constant over the entire glyph list.  So instead we just calculate the
 475  * gamma-adjusted value once and update the uniform parameter of the LCD
 476  * shader as needed.
 477  */
 478 static jboolean
 479 OGLTR_UpdateLCDTextColor(jint contrast)
 480 {
 481     double gamma = ((double)contrast) / 100.0;
 482     GLfloat radj, gadj, badj;
 483     GLfloat clr[4];
 484     GLint loc;
 485 
 486     J2dTraceLn1(J2D_TRACE_INFO,
 487                 "OGLTR_UpdateLCDTextColor: contrast=%d", contrast);
 488 
 489     /*
 490      * Note: Ideally we would update the "src_adj" uniform parameter only
 491      * when there is a change in the source color.  Fortunately, the cost
 492      * of querying the current OpenGL color state and updating the uniform
 493      * value is quite small, and in the common case we only need to do this
 494      * once per GlyphList, so we gain little from trying to optimize too
 495      * eagerly here.
 496      */
 497 
 498     // get the current OpenGL primary color state
 499     j2d_glGetFloatv(GL_CURRENT_COLOR, clr);
 500 
 501     // gamma adjust the primary color
 502     radj = (GLfloat)pow(clr[0], gamma);
 503     gadj = (GLfloat)pow(clr[1], gamma);
 504     badj = (GLfloat)pow(clr[2], gamma);
 505 
 506     // update the "src_adj" parameter of the shader program with this value
 507     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "src_adj");
 508     j2d_glUniform3fARB(loc, radj, gadj, badj);
 509 
 510     return JNI_TRUE;
 511 }
 512 
 513 /**
 514  * Enables the LCD text shader and updates any related state, such as the
 515  * gamma lookup table textures.
 516  */
 517 static jboolean
 518 OGLTR_EnableLCDGlyphModeState(GLuint glyphTextureID, jint contrast)
 519 {
 520     // bind the texture containing glyph data to texture unit 0
 521     j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 522     j2d_glBindTexture(GL_TEXTURE_2D, glyphTextureID);
 523 
 524     // bind the texture tile containing destination data to texture unit 1




 284  *
 285  * The variables involved in the equation can be expressed as follows:
 286  *
 287  *   Cs = Color component of the source (foreground color) [0.0, 1.0]
 288  *   Cd = Color component of the destination (background color) [0.0, 1.0]
 289  *   Cr = Color component to be written to the destination [0.0, 1.0]
 290  *   Ag = Glyph alpha (aka intensity or coverage) [0.0, 1.0]
 291  *   Ga = Gamma adjustment in the range [1.0, 2.5]
 292  *   (^ means raised to the power)
 293  *
 294  * And here is the theoretical equation approximated by this shader:
 295  *
 296  *            Cr = (Ag*(Cs^Ga) + (1-Ag)*(Cd^Ga)) ^ (1/Ga)
 297  */
 298 static const char *lcdTextShaderSource =
 299     "uniform vec3 src_adj;"
 300     "uniform sampler2D glyph_tex;"
 301     "uniform sampler2D dst_tex;"
 302     "uniform sampler3D invgamma_tex;"
 303     "uniform sampler3D gamma_tex;"
 304     "uniform vec3 gamma;"
 305     "uniform vec3 invgamma;"
 306     ""
 307     "void main(void)"
 308     "{"
 309          // load the RGB value from the glyph image at the current texcoord
 310     "    vec3 glyph_clr = vec3(texture2D(glyph_tex, gl_TexCoord[0].st));"
 311     "    if (glyph_clr == vec3(0.0)) {"
 312              // zero coverage, so skip this fragment
 313     "        discard;"
 314     "    }"
 315          // load the RGB value from the corresponding destination pixel
 316     "    vec3 dst_clr = vec3(texture2D(dst_tex, gl_TexCoord[1].st));"
 317          // gamma adjust the dest color using the invgamma LUT
 318     "    vec3 dst_adj = pow(dst_clr.rgb, invgamma);"
 319          // linearly interpolate the three color values
 320     "    vec3 result = mix(dst_adj, src_adj, glyph_clr);"
 321          // gamma re-adjust the resulting color (alpha is always set to 1.0)
 322     "    gl_FragColor = vec4(pow(result.rgb, gamma), 1.0);"
 323     "}";
 324 
 325 /**
 326  * Compiles and links the LCD text shader program.  If successful, this
 327  * function returns a handle to the newly created shader program; otherwise
 328  * returns 0.
 329  */
 330 static GLhandleARB
 331 OGLTR_CreateLCDTextProgram()
 332 {
 333     GLhandleARB lcdTextProgram;
 334     GLint loc;
 335 
 336     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_CreateLCDTextProgram");
 337 
 338     lcdTextProgram = OGLContext_CreateFragmentProgram(lcdTextShaderSource);
 339     if (lcdTextProgram == 0) {
 340         J2dRlsTraceLn(J2D_TRACE_ERROR,
 341                       "OGLTR_CreateLCDTextProgram: error creating program");
 342         return 0;


 407  * that essentially calculates pow(x, gamma) and the other calculates
 408  * pow(x, 1/gamma).  These values are replicated in all three dimensions, so
 409  * given a single 3D texture coordinate (typically this will be a triplet
 410  * in the form (r,g,b)), the 3D texture lookup will return an RGB triplet:
 411  *
 412  *     (pow(r,g), pow(y,g), pow(z,g)
 413  *
 414  * where g is either gamma or 1/gamma, depending on the table.
 415  */
 416 static jboolean
 417 OGLTR_UpdateLCDTextContrast(jint contrast)
 418 {
 419     double gamma = ((double)contrast) / 100.0;
 420     double ig = gamma;
 421     double g = 1.0 / ig;
 422     GLfloat lut[LUT_EDGE][LUT_EDGE][LUT_EDGE][3];
 423     GLfloat invlut[LUT_EDGE][LUT_EDGE][LUT_EDGE][3];
 424     int min = 0;
 425     int max = LUT_EDGE - 1;
 426     int x, y, z;
 427     GLint loc;
 428 
 429     J2dTraceLn1(J2D_TRACE_INFO,
 430                 "OGLTR_UpdateLCDTextContrast: contrast=%d", contrast);
 431     
 432     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "gamma");
 433     j2d_glUniform3fARB(loc, g, g, g);
 434 
 435     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "invgamma");
 436     j2d_glUniform3fARB(loc, ig, ig, ig);
 437 
 438     for (z = min; z <= max; z++) {
 439         double zval = ((double)z) / max;
 440         GLfloat gz = (GLfloat)pow(zval, g);
 441         GLfloat igz = (GLfloat)pow(zval, ig);
 442 
 443         for (y = min; y <= max; y++) {
 444             double yval = ((double)y) / max;
 445             GLfloat gy = (GLfloat)pow(yval, g);
 446             GLfloat igy = (GLfloat)pow(yval, ig);
 447 
 448             for (x = min; x <= max; x++) {
 449                 double xval = ((double)x) / max;
 450                 GLfloat gx = (GLfloat)pow(xval, g);
 451                 GLfloat igx = (GLfloat)pow(xval, ig);
 452 
 453                 lut[z][y][x][0] = gx;
 454                 lut[z][y][x][1] = gy;
 455                 lut[z][y][x][2] = gz;
 456 
 457                 invlut[z][y][x][0] = igx;


 470         invGammaLutTextureID = OGLTR_InitGammaLutTexture();
 471     }
 472     OGLTR_UpdateGammaLutTexture(invGammaLutTextureID,
 473                                 (GLfloat *)invlut, LUT_EDGE);
 474 
 475     return JNI_TRUE;
 476 }
 477 
 478 /**
 479  * Updates the current gamma-adjusted source color ("src_adj") of the LCD
 480  * text shader program.  Note that we could calculate this value in the
 481  * shader (e.g. just as we do for "dst_adj"), but would be unnecessary work
 482  * (and a measurable performance hit, maybe around 5%) since this value is
 483  * constant over the entire glyph list.  So instead we just calculate the
 484  * gamma-adjusted value once and update the uniform parameter of the LCD
 485  * shader as needed.
 486  */
 487 static jboolean
 488 OGLTR_UpdateLCDTextColor(jint contrast)
 489 {
 490     double invgamma = ((double)contrast) / 100;
 491     GLfloat radj, gadj, badj;
 492     GLfloat clr[4];
 493     GLint loc;
 494 
 495     J2dTraceLn1(J2D_TRACE_INFO,
 496                 "OGLTR_UpdateLCDTextColor: contrast=%d", contrast);
 497 
 498     /*
 499      * Note: Ideally we would update the "src_adj" uniform parameter only
 500      * when there is a change in the source color.  Fortunately, the cost
 501      * of querying the current OpenGL color state and updating the uniform
 502      * value is quite small, and in the common case we only need to do this
 503      * once per GlyphList, so we gain little from trying to optimize too
 504      * eagerly here.
 505      */
 506 
 507     // get the current OpenGL primary color state
 508     j2d_glGetFloatv(GL_CURRENT_COLOR, clr);
 509 
 510     // gamma adjust the primary color
 511     radj = (GLfloat)pow(clr[0], invgamma);
 512     gadj = (GLfloat)pow(clr[1], invgamma);
 513     badj = (GLfloat)pow(clr[2], invgamma);
 514 
 515     // update the "src_adj" parameter of the shader program with this value
 516     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "src_adj");
 517     j2d_glUniform3fARB(loc, radj, gadj, badj);
 518 
 519     return JNI_TRUE;
 520 }
 521 
 522 /**
 523  * Enables the LCD text shader and updates any related state, such as the
 524  * gamma lookup table textures.
 525  */
 526 static jboolean
 527 OGLTR_EnableLCDGlyphModeState(GLuint glyphTextureID, jint contrast)
 528 {
 529     // bind the texture containing glyph data to texture unit 0
 530     j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 531     j2d_glBindTexture(GL_TEXTURE_2D, glyphTextureID);
 532 
 533     // bind the texture tile containing destination data to texture unit 1


< prev index next >