< prev index next >

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

Print this page




 282  * with a single 3D texture lookup.  This approach is at least 2x faster
 283  * than the equivalent pow() calls.
 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;
 341     }
 342 
 343     // "use" the program object temporarily so that we can set the uniforms
 344     j2d_glUseProgramObjectARB(lcdTextProgram);
 345 
 346     // set the "uniform" values
 347     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "glyph_tex");
 348     j2d_glUniform1iARB(loc, 0); // texture unit 0
 349     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "dst_tex");
 350     j2d_glUniform1iARB(loc, 1); // texture unit 1
 351     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "invgamma_tex");
 352     j2d_glUniform1iARB(loc, 2); // texture unit 2
 353     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "gamma_tex");
 354     j2d_glUniform1iARB(loc, 3); // texture unit 3
 355 
 356     // "unuse" the program object; it will be re-bound later as needed
 357     j2d_glUseProgramObjectARB(0);
 358 
 359     return lcdTextProgram;
 360 }
 361 
 362 /**
 363  * Initializes a 3D texture object for use as a three-dimensional gamma
 364  * lookup table.  Note that the wrap mode is initialized to GL_LINEAR so
 365  * that the table will interpolate adjacent values when the index falls
 366  * somewhere in between.
 367  */
 368 static GLuint
 369 OGLTR_InitGammaLutTexture()
 370 {
 371     GLuint lutTextureID;
 372 
 373     j2d_glGenTextures(1, &lutTextureID);
 374     j2d_glBindTexture(GL_TEXTURE_3D, lutTextureID);
 375     j2d_glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 376     j2d_glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 377     j2d_glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 378     j2d_glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 379     j2d_glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
 380 
 381     return lutTextureID;
 382 }
 383 
 384 /**
 385  * Updates the lookup table in the given texture object with the float
 386  * values in the given system memory buffer.  Note that we could use
 387  * glTexSubImage3D() when updating the texture after its first
 388  * initialization, but since we're updating the entire table (with
 389  * power-of-two dimensions) and this is a relatively rare event, we'll
 390  * just stick with glTexImage3D().
 391  */
 392 static void
 393 OGLTR_UpdateGammaLutTexture(GLuint texID, GLfloat *lut, jint size)
 394 {
 395     j2d_glBindTexture(GL_TEXTURE_3D, texID);
 396     j2d_glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB8,
 397                      size, size, size, 0, GL_RGB, GL_FLOAT, lut);
 398 }
 399 
 400 /**
 401  * (Re)Initializes the gamma lookup table textures.
 402  *
 403  * The given contrast value is an int in the range [100, 250] which we will
 404  * then scale to fit in the range [1.0, 2.5].  We create two LUTs, one
 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;
 449                 invlut[z][y][x][1] = igy;
 450                 invlut[z][y][x][2] = igz;
 451             }
 452         }
 453     }
 454 
 455     if (gammaLutTextureID == 0) {
 456         gammaLutTextureID = OGLTR_InitGammaLutTexture();
 457     }
 458     OGLTR_UpdateGammaLutTexture(gammaLutTextureID, (GLfloat *)lut, LUT_EDGE);
 459 
 460     if (invGammaLutTextureID == 0) {
 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




 282  * with a single 3D texture lookup.  This approach is at least 2x faster
 283  * than the equivalent pow() calls.
 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 vec3 gamma;"
 303     "uniform vec3 invgamma;"
 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 = pow(dst_clr.rgb, invgamma);"
 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(pow(result.rgb, gamma), 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;
 341     }
 342 
 343     // "use" the program object temporarily so that we can set the uniforms
 344     j2d_glUseProgramObjectARB(lcdTextProgram);
 345 
 346     // set the "uniform" values
 347     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "glyph_tex");
 348     j2d_glUniform1iARB(loc, 0); // texture unit 0
 349     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "dst_tex");
 350     j2d_glUniform1iARB(loc, 1); // texture unit 1




 351     
 352     // "unuse" the program object; it will be re-bound later as needed
 353     j2d_glUseProgramObjectARB(0);
 354 
 355     return lcdTextProgram;
 356 }
 357 
 358 /**
 359  * (Re)Initializes the gamma related uniforms.






































 360  *
 361  * The given contrast value is an int in the range [100, 250] which we will
 362  * then scale to fit in the range [1.0, 2.5].  








 363  */
 364 static jboolean
 365 OGLTR_UpdateLCDTextContrast(jint contrast)
 366 {
 367     double gamma = ((double)contrast) / 100.0;
 368     double ig = gamma;
 369     double g = 1.0 / ig;
 370     GLint loc;




 371 
 372     J2dTraceLn1(J2D_TRACE_INFO,
 373                 "OGLTR_UpdateLCDTextContrast: contrast=%d", contrast);
 374     
 375     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "gamma");
 376     j2d_glUniform3fARB(loc, g, g, g);












 377 
 378     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "invgamma");
 379     j2d_glUniform3fARB(loc, ig, ig, ig);



















 380 
 381     return JNI_TRUE;
 382 }
 383 
 384 /**
 385  * Updates the current gamma-adjusted source color ("src_adj") of the LCD
 386  * text shader program.  Note that we could calculate this value in the
 387  * shader (e.g. just as we do for "dst_adj"), but would be unnecessary work
 388  * (and a measurable performance hit, maybe around 5%) since this value is
 389  * constant over the entire glyph list.  So instead we just calculate the
 390  * gamma-adjusted value once and update the uniform parameter of the LCD
 391  * shader as needed.
 392  */
 393 static jboolean
 394 OGLTR_UpdateLCDTextColor(jint contrast)
 395 {
 396     double invgamma = ((double)contrast) / 100;
 397     GLfloat radj, gadj, badj;
 398     GLfloat clr[4];
 399     GLint loc;
 400 
 401     J2dTraceLn1(J2D_TRACE_INFO,
 402                 "OGLTR_UpdateLCDTextColor: contrast=%d", contrast);
 403 
 404     /*
 405      * Note: Ideally we would update the "src_adj" uniform parameter only
 406      * when there is a change in the source color.  Fortunately, the cost
 407      * of querying the current OpenGL color state and updating the uniform
 408      * value is quite small, and in the common case we only need to do this
 409      * once per GlyphList, so we gain little from trying to optimize too
 410      * eagerly here.
 411      */
 412 
 413     // get the current OpenGL primary color state
 414     j2d_glGetFloatv(GL_CURRENT_COLOR, clr);
 415 
 416     // gamma adjust the primary color
 417     radj = (GLfloat)pow(clr[0], invgamma);
 418     gadj = (GLfloat)pow(clr[1], invgamma);
 419     badj = (GLfloat)pow(clr[2], invgamma);
 420 
 421     // update the "src_adj" parameter of the shader program with this value
 422     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "src_adj");
 423     j2d_glUniform3fARB(loc, radj, gadj, badj);
 424 
 425     return JNI_TRUE;
 426 }
 427 
 428 /**
 429  * Enables the LCD text shader and updates any related state, such as the
 430  * gamma lookup table textures.
 431  */
 432 static jboolean
 433 OGLTR_EnableLCDGlyphModeState(GLuint glyphTextureID, jint contrast)
 434 {
 435     // bind the texture containing glyph data to texture unit 0
 436     j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 437     j2d_glBindTexture(GL_TEXTURE_2D, glyphTextureID);
 438 
 439     // bind the texture tile containing destination data to texture unit 1


< prev index next >