jdk/src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c
changeset 31158 062c7363dd12
parent 26751 70bac69b37c9
child 31171 59d8e7712c0b
equal deleted inserted replaced
31157:25a62bb54efa 31158:062c7363dd12
   273  * The "uniform" variables at the top are initialized once the program is
   273  * The "uniform" variables at the top are initialized once the program is
   274  * linked, and are updated at runtime as needed (e.g. when the source color
   274  * linked, and are updated at runtime as needed (e.g. when the source color
   275  * changes, we will modify the "src_adj" value in OGLTR_UpdateLCDTextColor()).
   275  * changes, we will modify the "src_adj" value in OGLTR_UpdateLCDTextColor()).
   276  *
   276  *
   277  * The "main" function is executed for each "fragment" (or pixel) in the
   277  * The "main" function is executed for each "fragment" (or pixel) in the
   278  * glyph image.  We have determined that the pow() function can be quite
   278  * glyph image. The pow() routine operates on vectors, gives precise results,
   279  * slow and it only operates on scalar values, not vectors as we require.
   279  * and provides acceptable level of performance, so we use it to perform
   280  * So instead we build two 3D textures containing gamma (and inverse gamma)
   280  * the gamma adjustment.
   281  * lookup tables that allow us to approximate a component-wise pow() function
       
   282  * with a single 3D texture lookup.  This approach is at least 2x faster
       
   283  * than the equivalent pow() calls.
       
   284  *
   281  *
   285  * The variables involved in the equation can be expressed as follows:
   282  * The variables involved in the equation can be expressed as follows:
   286  *
   283  *
   287  *   Cs = Color component of the source (foreground color) [0.0, 1.0]
   284  *   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]
   285  *   Cd = Color component of the destination (background color) [0.0, 1.0]
   297  */
   294  */
   298 static const char *lcdTextShaderSource =
   295 static const char *lcdTextShaderSource =
   299     "uniform vec3 src_adj;"
   296     "uniform vec3 src_adj;"
   300     "uniform sampler2D glyph_tex;"
   297     "uniform sampler2D glyph_tex;"
   301     "uniform sampler2D dst_tex;"
   298     "uniform sampler2D dst_tex;"
   302     "uniform sampler3D invgamma_tex;"
   299     "uniform vec3 gamma;"
   303     "uniform sampler3D gamma_tex;"
   300     "uniform vec3 invgamma;"
   304     ""
   301     ""
   305     "void main(void)"
   302     "void main(void)"
   306     "{"
   303     "{"
   307          // load the RGB value from the glyph image at the current texcoord
   304          // load the RGB value from the glyph image at the current texcoord
   308     "    vec3 glyph_clr = vec3(texture2D(glyph_tex, gl_TexCoord[0].st));"
   305     "    vec3 glyph_clr = vec3(texture2D(glyph_tex, gl_TexCoord[0].st));"
   310              // zero coverage, so skip this fragment
   307              // zero coverage, so skip this fragment
   311     "        discard;"
   308     "        discard;"
   312     "    }"
   309     "    }"
   313          // load the RGB value from the corresponding destination pixel
   310          // load the RGB value from the corresponding destination pixel
   314     "    vec3 dst_clr = vec3(texture2D(dst_tex, gl_TexCoord[1].st));"
   311     "    vec3 dst_clr = vec3(texture2D(dst_tex, gl_TexCoord[1].st));"
   315          // gamma adjust the dest color using the invgamma LUT
   312          // gamma adjust the dest color
   316     "    vec3 dst_adj = vec3(texture3D(invgamma_tex, dst_clr.stp));"
   313     "    vec3 dst_adj = pow(dst_clr.rgb, gamma);"
   317          // linearly interpolate the three color values
   314          // linearly interpolate the three color values
   318     "    vec3 result = mix(dst_adj, src_adj, glyph_clr);"
   315     "    vec3 result = mix(dst_adj, src_adj, glyph_clr);"
   319          // gamma re-adjust the resulting color (alpha is always set to 1.0)
   316          // 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);"
   317     "    gl_FragColor = vec4(pow(result.rgb, invgamma), 1.0);"
   321     "}";
   318     "}";
   322 
   319 
   323 /**
   320 /**
   324  * Compiles and links the LCD text shader program.  If successful, this
   321  * Compiles and links the LCD text shader program.  If successful, this
   325  * function returns a handle to the newly created shader program; otherwise
   322  * function returns a handle to the newly created shader program; otherwise
   346     // set the "uniform" values
   343     // set the "uniform" values
   347     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "glyph_tex");
   344     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "glyph_tex");
   348     j2d_glUniform1iARB(loc, 0); // texture unit 0
   345     j2d_glUniform1iARB(loc, 0); // texture unit 0
   349     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "dst_tex");
   346     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "dst_tex");
   350     j2d_glUniform1iARB(loc, 1); // texture unit 1
   347     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 
   348 
   356     // "unuse" the program object; it will be re-bound later as needed
   349     // "unuse" the program object; it will be re-bound later as needed
   357     j2d_glUseProgramObjectARB(0);
   350     j2d_glUseProgramObjectARB(0);
   358 
   351 
   359     return lcdTextProgram;
   352     return lcdTextProgram;
   360 }
   353 }
   361 
   354 
   362 /**
   355 /**
   363  * Initializes a 3D texture object for use as a three-dimensional gamma
   356  * (Re)Initializes the gamma related uniforms.
   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  *
   357  *
   403  * The given contrast value is an int in the range [100, 250] which we will
   358  * 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
   359  * then scale to fit in the range [1.0, 2.5].
   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  */
   360  */
   414 static jboolean
   361 static jboolean
   415 OGLTR_UpdateLCDTextContrast(jint contrast)
   362 OGLTR_UpdateLCDTextContrast(jint contrast)
   416 {
   363 {
   417     double gamma = ((double)contrast) / 100.0;
   364     double g = ((double)contrast) / 100.0;
   418     double ig = gamma;
   365     double ig = 1.0 / g;
   419     double g = 1.0 / ig;
   366     GLint loc;
   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 
   367 
   426     J2dTraceLn1(J2D_TRACE_INFO,
   368     J2dTraceLn1(J2D_TRACE_INFO,
   427                 "OGLTR_UpdateLCDTextContrast: contrast=%d", contrast);
   369                 "OGLTR_UpdateLCDTextContrast: contrast=%d", contrast);
   428 
   370 
   429     for (z = min; z <= max; z++) {
   371     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "gamma");
   430         double zval = ((double)z) / max;
   372     j2d_glUniform3fARB(loc, g, g, g);
   431         GLfloat gz = (GLfloat)pow(zval, g);
   373 
   432         GLfloat igz = (GLfloat)pow(zval, ig);
   374     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "invgamma");
   433 
   375     j2d_glUniform3fARB(loc, ig, ig, ig);
   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 
   376 
   466     return JNI_TRUE;
   377     return JNI_TRUE;
   467 }
   378 }
   468 
   379 
   469 /**
   380 /**