< prev index next >

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

Print this page




  29 #include <math.h>
  30 #include <jlong.h>
  31 
  32 #include "sun_java2d_opengl_OGLTextRenderer.h"
  33 
  34 #include "SurfaceData.h"
  35 #include "OGLContext.h"
  36 #include "OGLSurfaceData.h"
  37 #include "OGLRenderQueue.h"
  38 #include "OGLTextRenderer.h"
  39 #include "OGLVertexCache.h"
  40 #include "AccelGlyphCache.h"
  41 #include "fontscalerdefs.h"
  42 
  43 /**
  44  * The following constants define the inner and outer bounds of the
  45  * accelerated glyph cache.
  46  */
  47 #define OGLTR_CACHE_WIDTH       512
  48 #define OGLTR_CACHE_HEIGHT      512
  49 #define OGLTR_CACHE_CELL_WIDTH  16
  50 #define OGLTR_CACHE_CELL_HEIGHT 16
  51 
  52 /**
  53  * The current "glyph mode" state.  This variable is used to track the
  54  * codepath used to render a particular glyph.  This variable is reset to
  55  * MODE_NOT_INITED at the beginning of every call to OGLTR_DrawGlyphList().
  56  * As each glyph is rendered, the glyphMode variable is updated to reflect
  57  * the current mode, so if the current mode is the same as the mode used
  58  * to render the previous glyph, we can avoid doing costly setup operations
  59  * each time.
  60  */
  61 typedef enum {
  62     MODE_NOT_INITED,
  63     MODE_USE_CACHE_GRAY,
  64     MODE_USE_CACHE_LCD,
  65     MODE_NO_CACHE_GRAY,
  66     MODE_NO_CACHE_LCD
  67 } GlyphMode;
  68 static GlyphMode glyphMode = MODE_NOT_INITED;
  69 
  70 /**
  71  * This enum indicates the current state of the hardware glyph cache.
  72  * Initially the CacheStatus is set to CACHE_NOT_INITED, and then it is
  73  * set to either GRAY or LCD when the glyph cache is initialized.
  74  */
  75 typedef enum {
  76     CACHE_NOT_INITED,
  77     CACHE_GRAY,
  78     CACHE_LCD
  79 } CacheStatus;
  80 static CacheStatus cacheStatus = CACHE_NOT_INITED;
  81 
  82 /**
  83  * This is the one glyph cache.  Once it is initialized as either GRAY or
  84  * LCD, it stays in that mode for the duration of the application.  It should
  85  * be safe to use this one glyph cache for all screens in a multimon
  86  * environment, since the glyph cache texture is shared between all contexts,
  87  * and (in theory) OpenGL drivers should be smart enough to manage that
  88  * texture across all screens.
  89  */
  90 static GlyphCacheInfo *glyphCache = NULL;


  91 
  92 /**
  93  * The handle to the LCD text fragment program object.
  94  */
  95 static GLhandleARB lcdTextProgram = 0;
  96 
  97 /**
  98  * This value tracks the previous LCD contrast setting, so if the contrast
  99  * value hasn't changed since the last time the gamma uniforms were
 100  * updated (not very common), then we can skip updating the unforms.
 101  */
 102 static jint lastLCDContrast = -1;
 103 
 104 /**
 105  * This value tracks the previous LCD rgbOrder setting, so if the rgbOrder
 106  * value has changed since the last time, it indicates that we need to
 107  * invalidate the cache, which may already store glyph images in the reverse
 108  * order.  Note that in most real world applications this value will not
 109  * change over the course of the application, but tests like Font2DTest
 110  * allow for changing the ordering at runtime, so we need to handle that case.


 121 /**
 122  * These constants define the size of the "cached destination" texture.
 123  * This texture is only used when rendering LCD-optimized text, as that
 124  * codepath needs direct access to the destination.  There is no way to
 125  * access the framebuffer directly from an OpenGL shader, so we need to first
 126  * copy the destination region corresponding to a particular glyph into
 127  * this cached texture, and then that texture will be accessed inside the
 128  * shader.  Copying the destination into this cached texture can be a very
 129  * expensive operation (accounting for about half the rendering time for
 130  * LCD text), so to mitigate this cost we try to bulk read a horizontal
 131  * region of the destination at a time.  (These values are empirically
 132  * derived for the common case where text runs horizontally.)
 133  *
 134  * Note: It is assumed in various calculations below that:
 135  *     (OGLTR_CACHED_DEST_WIDTH  >= OGLTR_CACHE_CELL_WIDTH)  &&
 136  *     (OGLTR_CACHED_DEST_WIDTH  >= OGLTR_NOCACHE_TILE_SIZE) &&
 137  *     (OGLTR_CACHED_DEST_HEIGHT >= OGLTR_CACHE_CELL_HEIGHT) &&
 138  *     (OGLTR_CACHED_DEST_HEIGHT >= OGLTR_NOCACHE_TILE_SIZE)
 139  */
 140 #define OGLTR_CACHED_DEST_WIDTH  512
 141 #define OGLTR_CACHED_DEST_HEIGHT 32
 142 
 143 /**
 144  * The handle to the "cached destination" texture object.
 145  */
 146 static GLuint cachedDestTextureID = 0;
 147 
 148 /**
 149  * The current bounds of the "cached destination" texture, in destination
 150  * coordinate space.  The width/height of these bounds will not exceed the
 151  * OGLTR_CACHED_DEST_WIDTH/HEIGHT values defined above.  These bounds are
 152  * only considered valid when the isCachedDestValid flag is JNI_TRUE.
 153  */
 154 static SurfaceDataBounds cachedDestBounds;
 155 
 156 /**
 157  * This flag indicates whether the "cached destination" texture contains
 158  * valid data.  This flag is reset to JNI_FALSE at the beginning of every
 159  * call to OGLTR_DrawGlyphList().  Once we copy valid destination data
 160  * into the cached texture, this flag is set to JNI_TRUE.  This way, we can
 161  * limit the number of times we need to copy destination data, which is a


 195                                   OGLTR_CACHE_CELL_WIDTH,
 196                                   OGLTR_CACHE_CELL_HEIGHT,
 197                                   OGLVertexCache_FlushVertexCache);
 198     if (gcinfo == NULL) {
 199         J2dRlsTraceLn(J2D_TRACE_ERROR,
 200                       "OGLTR_InitGlyphCache: could not init OGL glyph cache");
 201         return JNI_FALSE;
 202     }
 203 
 204     // init cache texture object
 205     j2d_glGenTextures(1, &gcinfo->cacheID);
 206     j2d_glBindTexture(GL_TEXTURE_2D, gcinfo->cacheID);
 207     j2d_glPrioritizeTextures(1, &gcinfo->cacheID, &priority);
 208     j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 209     j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 210 
 211     j2d_glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,
 212                      OGLTR_CACHE_WIDTH, OGLTR_CACHE_HEIGHT, 0,
 213                      pixelFormat, GL_UNSIGNED_BYTE, NULL);
 214 
 215     cacheStatus = (lcdCache ? CACHE_LCD : CACHE_GRAY);
 216     glyphCache = gcinfo;



 217 
 218     return JNI_TRUE;
 219 }
 220 
 221 /**
 222  * Adds the given glyph to the glyph cache (texture and data structure)
 223  * associated with the given OGLContext.
 224  */
 225 static void
 226 OGLTR_AddToGlyphCache(GlyphInfo *glyph, jboolean rgbOrder)
 227 {
 228     GLenum pixelFormat;
 229     CacheCellInfo *ccinfo;

 230 
 231     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_AddToGlyphCache");
 232 
 233     if ((glyphCache == NULL) || (glyph->image == NULL)) {
 234         return;


 235     }
 236 
 237     if (cacheStatus == CACHE_LCD) {
 238         pixelFormat = rgbOrder ? GL_RGB : GL_BGR;
 239     } else {
 240         pixelFormat = GL_LUMINANCE;
 241     }
 242 
 243     AccelGlyphCache_AddGlyph(glyphCache, glyph);
 244     ccinfo = (CacheCellInfo *) glyph->cellInfo;
 245 
 246     if (ccinfo != NULL) {
 247         // store glyph image in texture cell
 248         j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
 249                             ccinfo->x, ccinfo->y,
 250                             glyph->width, glyph->height,
 251                             pixelFormat, GL_UNSIGNED_BYTE, glyph->image);
 252     }
 253 }
 254 
 255 /**
 256  * This is the GLSL fragment shader source code for rendering LCD-optimized
 257  * text.  Do not be frightened; it is much easier to understand than the
 258  * equivalent ASM-like fragment program!
 259  *
 260  * The "uniform" variables at the top are initialized once the program is
 261  * linked, and are updated at runtime as needed (e.g. when the source color
 262  * changes, we will modify the "src_adj" value in OGLTR_UpdateLCDTextColor()).
 263  *


 396     // get the current OpenGL primary color state
 397     j2d_glGetFloatv(GL_CURRENT_COLOR, clr);
 398 
 399     // gamma adjust the primary color
 400     radj = (GLfloat)pow(clr[0], gamma);
 401     gadj = (GLfloat)pow(clr[1], gamma);
 402     badj = (GLfloat)pow(clr[2], gamma);
 403 
 404     // update the "src_adj" parameter of the shader program with this value
 405     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "src_adj");
 406     j2d_glUniform3fARB(loc, radj, gadj, badj);
 407 
 408     return JNI_TRUE;
 409 }
 410 
 411 /**
 412  * Enables the LCD text shader and updates any related state, such as the
 413  * gamma lookup table textures.
 414  */
 415 static jboolean
 416 OGLTR_EnableLCDGlyphModeState(GLuint glyphTextureID, jint contrast)


 417 {
 418     // bind the texture containing glyph data to texture unit 0
 419     j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 420     j2d_glBindTexture(GL_TEXTURE_2D, glyphTextureID);

 421 
 422     // bind the texture tile containing destination data to texture unit 1
 423     j2d_glActiveTextureARB(GL_TEXTURE1_ARB);



 424     if (cachedDestTextureID == 0) {
 425         cachedDestTextureID =
 426             OGLContext_CreateBlitTexture(GL_RGB8, GL_RGB,
 427                                          OGLTR_CACHED_DEST_WIDTH,
 428                                          OGLTR_CACHED_DEST_HEIGHT);
 429         if (cachedDestTextureID == 0) {
 430             return JNI_FALSE;
 431         }
 432     }
 433     j2d_glBindTexture(GL_TEXTURE_2D, cachedDestTextureID);

 434 
 435     // note that GL_TEXTURE_2D was already enabled for texture unit 0,
 436     // but we need to explicitly enable it for texture unit 1
 437     j2d_glEnable(GL_TEXTURE_2D);
 438 
 439     // create the LCD text shader, if necessary
 440     if (lcdTextProgram == 0) {
 441         lcdTextProgram = OGLTR_CreateLCDTextProgram();
 442         if (lcdTextProgram == 0) {
 443             return JNI_FALSE;
 444         }
 445     }
 446 
 447     // enable the LCD text shader
 448     j2d_glUseProgramObjectARB(lcdTextProgram);
 449 
 450     // update the current contrast settings, if necessary
 451     if (lastLCDContrast != contrast) {
 452         if (!OGLTR_UpdateLCDTextContrast(contrast)) {
 453             return JNI_FALSE;


 455         lastLCDContrast = contrast;
 456     }
 457 
 458     // update the current color settings
 459     if (!OGLTR_UpdateLCDTextColor(contrast)) {
 460         return JNI_FALSE;
 461     }
 462 
 463     return JNI_TRUE;
 464 }
 465 
 466 void
 467 OGLTR_EnableGlyphVertexCache(OGLContext *oglc)
 468 {
 469     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_EnableGlyphVertexCache");
 470 
 471     if (!OGLVertexCache_InitVertexCache(oglc)) {
 472         return;
 473     }
 474 
 475     if (glyphCache == NULL) {
 476         if (!OGLTR_InitGlyphCache(JNI_FALSE)) {
 477             return;
 478         }
 479     }
 480 
 481     j2d_glEnable(GL_TEXTURE_2D);
 482     j2d_glBindTexture(GL_TEXTURE_2D, glyphCache->cacheID);
 483     j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 484 
 485     // for grayscale/monochrome text, the current OpenGL source color
 486     // is modulated with the glyph image as part of the texture
 487     // application stage, so we use GL_MODULATE here
 488     OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
 489 }
 490 
 491 void
 492 OGLTR_DisableGlyphVertexCache(OGLContext *oglc)
 493 {
 494     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DisableGlyphVertexCache");
 495 
 496     OGLVertexCache_FlushVertexCache();
 497     OGLVertexCache_RestoreColorState(oglc);
 498 
 499     j2d_glDisable(GL_TEXTURE_2D);
 500     j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 501     j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 502     j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);


 505 
 506 /**
 507  * Disables any pending state associated with the current "glyph mode".
 508  */
 509 static void
 510 OGLTR_DisableGlyphModeState()
 511 {
 512     switch (glyphMode) {
 513     case MODE_NO_CACHE_LCD:
 514         j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 515         j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
 516         /* FALLTHROUGH */
 517 
 518     case MODE_USE_CACHE_LCD:
 519         j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 520         j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 521         j2d_glUseProgramObjectARB(0);
 522         j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
 523         j2d_glDisable(GL_TEXTURE_2D);
 524         j2d_glActiveTextureARB(GL_TEXTURE0_ARB);

 525         break;
 526 
 527     case MODE_NO_CACHE_GRAY:
 528     case MODE_USE_CACHE_GRAY:
 529     case MODE_NOT_INITED:
 530     default:
 531         break;
 532     }
 533 }
 534 
 535 static jboolean
 536 OGLTR_DrawGrayscaleGlyphViaCache(OGLContext *oglc,
 537                                  GlyphInfo *ginfo, jint x, jint y)
 538 {
 539     CacheCellInfo *cell;
 540     jfloat x1, y1, x2, y2;
 541 
 542     if (glyphMode != MODE_USE_CACHE_GRAY) {
 543         OGLTR_DisableGlyphModeState();
 544         CHECK_PREVIOUS_OP(OGL_STATE_GLYPH_OP);
 545         glyphMode = MODE_USE_CACHE_GRAY;
 546     }
 547 
 548     if (ginfo->cellInfo == NULL) {
 549         // attempt to add glyph to accelerated glyph cache
 550         OGLTR_AddToGlyphCache(ginfo, JNI_FALSE);
 551 
 552         if (ginfo->cellInfo == NULL) {
 553             // we'll just no-op in the rare case that the cell is NULL
 554             return JNI_TRUE;
 555         }
 556     }
 557 
 558     cell = (CacheCellInfo *) (ginfo->cellInfo);
 559     cell->timesRendered++;
 560 
 561     x1 = (jfloat)x;
 562     y1 = (jfloat)y;
 563     x2 = x1 + ginfo->width;
 564     y2 = y1 + ginfo->height;
 565 
 566     OGLVertexCache_AddGlyphQuad(oglc,
 567                                 cell->tx1, cell->ty1,
 568                                 cell->tx2, cell->ty2,
 569                                 x1, y1, x2, y2);
 570 


 690 
 691         // update the cached bounds and mark it valid
 692         cachedDestBounds.x1 = dx1;
 693         cachedDestBounds.y1 = dy1;
 694         cachedDestBounds.x2 = dx2;
 695         cachedDestBounds.y2 = dy2;
 696         isCachedDestValid = JNI_TRUE;
 697     }
 698 
 699     // always update the previous glyph bounds
 700     previousGlyphBounds.x1 = gx1;
 701     previousGlyphBounds.y1 = gy1;
 702     previousGlyphBounds.x2 = gx2;
 703     previousGlyphBounds.y2 = gy2;
 704 }
 705 
 706 static jboolean
 707 OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps,
 708                            GlyphInfo *ginfo, jint x, jint y,
 709                            jint glyphIndex, jint totalGlyphs,
 710                            jboolean rgbOrder, jint contrast)

 711 {
 712     CacheCellInfo *cell;
 713     jint dx1, dy1, dx2, dy2;
 714     jfloat dtx1, dty1, dtx2, dty2;
 715 
 716     if (glyphMode != MODE_USE_CACHE_LCD) {
 717         OGLTR_DisableGlyphModeState();
 718         CHECK_PREVIOUS_OP(GL_TEXTURE_2D);
 719         j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 720 
 721         if (glyphCache == NULL) {
 722             if (!OGLTR_InitGlyphCache(JNI_TRUE)) {
 723                 return JNI_FALSE;
 724             }
 725         }
 726 
 727         if (rgbOrder != lastRGBOrder) {
 728             // need to invalidate the cache in this case; see comments
 729             // for lastRGBOrder above
 730             AccelGlyphCache_Invalidate(glyphCache);
 731             lastRGBOrder = rgbOrder;
 732         }
 733 
 734         if (!OGLTR_EnableLCDGlyphModeState(glyphCache->cacheID, contrast)) {


 735             return JNI_FALSE;
 736         }
 737 
 738         // when a fragment shader is enabled, the texture function state is
 739         // ignored, so the following line is not needed...
 740         // OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
 741 
 742         glyphMode = MODE_USE_CACHE_LCD;
 743     }
 744 
 745     if (ginfo->cellInfo == NULL) {
 746         // rowBytes will always be a multiple of 3, so the following is safe
 747         j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, ginfo->rowBytes / 3);
 748 
 749         // make sure the glyph cache texture is bound to texture unit 0
 750         j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 751 
 752         // attempt to add glyph to accelerated glyph cache
 753         OGLTR_AddToGlyphCache(ginfo, rgbOrder);
 754 
 755         if (ginfo->cellInfo == NULL) {
 756             // we'll just no-op in the rare case that the cell is NULL
 757             return JNI_TRUE;
 758         }
 759     }
 760 
 761     cell = (CacheCellInfo *) (ginfo->cellInfo);
 762     cell->timesRendered++;
 763 
 764     // location of the glyph in the destination's coordinate space
 765     dx1 = x;
 766     dy1 = y;
 767     dx2 = dx1 + ginfo->width;
 768     dy2 = dy1 + ginfo->height;
 769 

 770     // copy destination into second cached texture, if necessary
 771     OGLTR_UpdateCachedDestination(dstOps, ginfo,
 772                                   dx1, dy1, dx2, dy2,
 773                                   glyphIndex, totalGlyphs);
 774 
 775     // texture coordinates of the destination tile
 776     dtx1 = ((jfloat)(dx1 - cachedDestBounds.x1)) / OGLTR_CACHED_DEST_WIDTH;
 777     dty1 = ((jfloat)(cachedDestBounds.y2 - dy1)) / OGLTR_CACHED_DEST_HEIGHT;
 778     dtx2 = ((jfloat)(dx2 - cachedDestBounds.x1)) / OGLTR_CACHED_DEST_WIDTH;
 779     dty2 = ((jfloat)(cachedDestBounds.y2 - dy2)) / OGLTR_CACHED_DEST_HEIGHT;

















 780 
 781     // render composed texture to the destination surface
 782     j2d_glBegin(GL_QUADS);
 783     j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty1);
 784     j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
 785     j2d_glVertex2i(dx1, dy1);
 786     j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx2, cell->ty1);
 787     j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
 788     j2d_glVertex2i(dx2, dy1);
 789     j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx2, cell->ty2);
 790     j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
 791     j2d_glVertex2i(dx2, dy2);
 792     j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty2);
 793     j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
 794     j2d_glVertex2i(dx1, dy2);
 795     j2d_glEnd();
 796 
 797     return JNI_TRUE;
 798 }
 799 


 820     for (sy = 0; sy < h; sy += th, y += th) {
 821         x = x0;
 822         sh = ((sy + th) > h) ? (h - sy) : th;
 823 
 824         for (sx = 0; sx < w; sx += tw, x += tw) {
 825             sw = ((sx + tw) > w) ? (w - sx) : tw;
 826 
 827             OGLVertexCache_AddMaskQuad(oglc,
 828                                        sx, sy, x, y, sw, sh,
 829                                        w, ginfo->image);
 830         }
 831     }
 832 
 833     return JNI_TRUE;
 834 }
 835 
 836 static jboolean
 837 OGLTR_DrawLCDGlyphNoCache(OGLContext *oglc, OGLSDOps *dstOps,
 838                           GlyphInfo *ginfo, jint x, jint y,
 839                           jint rowBytesOffset,
 840                           jboolean rgbOrder, jint contrast)

 841 {
 842     GLfloat tx1, ty1, tx2, ty2;
 843     GLfloat dtx1, dty1, dtx2, dty2;
 844     jint tw, th;
 845     jint sx, sy, sw, sh, dxadj, dyadj;
 846     jint x0;
 847     jint w = ginfo->width;
 848     jint h = ginfo->height;
 849     GLenum pixelFormat = rgbOrder ? GL_RGB : GL_BGR;
 850 
 851     if (glyphMode != MODE_NO_CACHE_LCD) {
 852         OGLTR_DisableGlyphModeState();
 853         CHECK_PREVIOUS_OP(GL_TEXTURE_2D);
 854         j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 855 
 856         if (oglc->blitTextureID == 0) {
 857             if (!OGLContext_InitBlitTileTexture(oglc)) {
 858                 return JNI_FALSE;
 859             }
 860         }
 861 
 862         if (!OGLTR_EnableLCDGlyphModeState(oglc->blitTextureID, contrast)) {


 863             return JNI_FALSE;
 864         }
 865 
 866         // when a fragment shader is enabled, the texture function state is
 867         // ignored, so the following line is not needed...
 868         // OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
 869 
 870         glyphMode = MODE_NO_CACHE_LCD;
 871     }
 872 
 873     // rowBytes will always be a multiple of 3, so the following is safe
 874     j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, ginfo->rowBytes / 3);
 875 
 876     x0 = x;
 877     tx1 = 0.0f;
 878     ty1 = 0.0f;
 879     dtx1 = 0.0f;
 880     dty2 = 0.0f;
 881     tw = OGLTR_NOCACHE_TILE_SIZE;
 882     th = OGLTR_NOCACHE_TILE_SIZE;


 890 
 891             // update the source pointer offsets
 892             j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
 893             j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
 894 
 895             // copy LCD mask into glyph texture tile
 896             j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 897             j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
 898                                 0, 0, sw, sh,
 899                                 pixelFormat, GL_UNSIGNED_BYTE,
 900                                 ginfo->image + rowBytesOffset);
 901 
 902             // update the lower-right glyph texture coordinates
 903             tx2 = ((GLfloat)sw) / OGLC_BLIT_TILE_SIZE;
 904             ty2 = ((GLfloat)sh) / OGLC_BLIT_TILE_SIZE;
 905 
 906             // this accounts for lower-left origin of the destination region
 907             dxadj = dstOps->xOffset + x;
 908             dyadj = dstOps->yOffset + dstOps->height - (y + sh);
 909 

 910             // copy destination into cached texture tile (the lower-left
 911             // corner of the destination region will be positioned at the
 912             // lower-left corner (0,0) of the texture)
 913             j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
 914             j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
 915                                     0, 0,
 916                                     dxadj, dyadj,
 917                                     sw, sh);
 918 
 919             // update the remaining destination texture coordinates
 920             dtx2 = ((GLfloat)sw) / OGLTR_CACHED_DEST_WIDTH;
 921             dty1 = ((GLfloat)sh) / OGLTR_CACHED_DEST_HEIGHT;











 922 
 923             // render composed texture to the destination surface
 924             j2d_glBegin(GL_QUADS);
 925             j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx1, ty1);
 926             j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
 927             j2d_glVertex2i(x, y);
 928             j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty1);
 929             j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
 930             j2d_glVertex2i(x + sw, y);
 931             j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty2);
 932             j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
 933             j2d_glVertex2i(x + sw, y + sh);
 934             j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx1, ty2);
 935             j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
 936             j2d_glVertex2i(x, y + sh);
 937             j2d_glEnd();
 938         }
 939     }
 940 
 941     return JNI_TRUE;
 942 }
 943 
 944 // see DrawGlyphList.c for more on this macro...
 945 #define FLOOR_ASSIGN(l, r) \
 946     if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
 947 
 948 void
 949 OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
 950                     jint totalGlyphs, jboolean usePositions,
 951                     jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
 952                     jfloat glyphListOrigX, jfloat glyphListOrigY,
 953                     unsigned char *images, unsigned char *positions)
 954 {
 955     int glyphCounter;

 956 
 957     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DrawGlyphList");
 958 
 959     RETURN_IF_NULL(oglc);
 960     RETURN_IF_NULL(dstOps);
 961     RETURN_IF_NULL(images);
 962     if (usePositions) {
 963         RETURN_IF_NULL(positions);
 964     }
 965 
 966     glyphMode = MODE_NOT_INITED;
 967     isCachedDestValid = JNI_FALSE;
 968 






 969     for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
 970         jint x, y;
 971         jfloat glyphx, glyphy;
 972         jboolean grayscale, ok;
 973         GlyphInfo *ginfo = (GlyphInfo *)jlong_to_ptr(NEXT_LONG(images));
 974 
 975         if (ginfo == NULL) {
 976             // this shouldn't happen, but if it does we'll just break out...
 977             J2dRlsTraceLn(J2D_TRACE_ERROR,
 978                           "OGLTR_DrawGlyphList: glyph info is null");
 979             break;
 980         }
 981 
 982         grayscale = (ginfo->rowBytes == ginfo->width);
 983 
 984         if (usePositions) {
 985             jfloat posx = NEXT_FLOAT(positions);
 986             jfloat posy = NEXT_FLOAT(positions);
 987             glyphx = glyphListOrigX + posx + ginfo->topLeftX;
 988             glyphy = glyphListOrigY + posy + ginfo->topLeftY;
 989             FLOOR_ASSIGN(x, glyphx);
 990             FLOOR_ASSIGN(y, glyphy);
 991         } else {
 992             glyphx = glyphListOrigX + ginfo->topLeftX;
 993             glyphy = glyphListOrigY + ginfo->topLeftY;
 994             FLOOR_ASSIGN(x, glyphx);
 995             FLOOR_ASSIGN(y, glyphy);
 996             glyphListOrigX += ginfo->advanceX;
 997             glyphListOrigY += ginfo->advanceY;
 998         }
 999 
1000         if (ginfo->image == NULL) {
1001             continue;
1002         }
1003 
1004         if (grayscale) {
1005             // grayscale or monochrome glyph data
1006             if (cacheStatus != CACHE_LCD &&
1007                 ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
1008                 ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
1009             {
1010                 ok = OGLTR_DrawGrayscaleGlyphViaCache(oglc, ginfo, x, y);
1011             } else {
1012                 ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y);
1013             }
1014         } else {
1015             // LCD-optimized glyph data
1016             jint rowBytesOffset = 0;
1017 
1018             if (subPixPos) {
1019                 jint frac = (jint)((glyphx - x) * 3);
1020                 if (frac != 0) {
1021                     rowBytesOffset = 3 - frac;
1022                     x += 1;
1023                 }
1024             }
1025 
1026             if (rowBytesOffset == 0 &&
1027                 cacheStatus != CACHE_GRAY &&
1028                 ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
1029                 ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
1030             {
1031                 ok = OGLTR_DrawLCDGlyphViaCache(oglc, dstOps,
1032                                                 ginfo, x, y,
1033                                                 glyphCounter, totalGlyphs,
1034                                                 rgbOrder, lcdContrast);

1035             } else {
1036                 ok = OGLTR_DrawLCDGlyphNoCache(oglc, dstOps,
1037                                                ginfo, x, y,
1038                                                rowBytesOffset,
1039                                                rgbOrder, lcdContrast);

1040             }
1041         }
1042 
1043         if (!ok) {
1044             break;
1045         }
1046     }
1047 
1048     OGLTR_DisableGlyphModeState();
1049 }
1050 
1051 JNIEXPORT void JNICALL
1052 Java_sun_java2d_opengl_OGLTextRenderer_drawGlyphList
1053     (JNIEnv *env, jobject self,
1054      jint numGlyphs, jboolean usePositions,
1055      jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
1056      jfloat glyphListOrigX, jfloat glyphListOrigY,
1057      jlongArray imgArray, jfloatArray posArray)
1058 {
1059     unsigned char *images;




  29 #include <math.h>
  30 #include <jlong.h>
  31 
  32 #include "sun_java2d_opengl_OGLTextRenderer.h"
  33 
  34 #include "SurfaceData.h"
  35 #include "OGLContext.h"
  36 #include "OGLSurfaceData.h"
  37 #include "OGLRenderQueue.h"
  38 #include "OGLTextRenderer.h"
  39 #include "OGLVertexCache.h"
  40 #include "AccelGlyphCache.h"
  41 #include "fontscalerdefs.h"
  42 
  43 /**
  44  * The following constants define the inner and outer bounds of the
  45  * accelerated glyph cache.
  46  */
  47 #define OGLTR_CACHE_WIDTH       512
  48 #define OGLTR_CACHE_HEIGHT      512
  49 #define OGLTR_CACHE_CELL_WIDTH  32
  50 #define OGLTR_CACHE_CELL_HEIGHT 32
  51 
  52 /**
  53  * The current "glyph mode" state.  This variable is used to track the
  54  * codepath used to render a particular glyph.  This variable is reset to
  55  * MODE_NOT_INITED at the beginning of every call to OGLTR_DrawGlyphList().
  56  * As each glyph is rendered, the glyphMode variable is updated to reflect
  57  * the current mode, so if the current mode is the same as the mode used
  58  * to render the previous glyph, we can avoid doing costly setup operations
  59  * each time.
  60  */
  61 typedef enum {
  62     MODE_NOT_INITED,
  63     MODE_USE_CACHE_GRAY,
  64     MODE_USE_CACHE_LCD,
  65     MODE_NO_CACHE_GRAY,
  66     MODE_NO_CACHE_LCD
  67 } GlyphMode;
  68 static GlyphMode glyphMode = MODE_NOT_INITED;
  69 
  70 /**
  71  * There are two separate glyph caches: for AA and for LCD.
  72  * Once one of them is initialized as either GRAY or LCD, it
  73  * stays in that mode for the duration of the application.  It should











  74  * be safe to use this one glyph cache for all screens in a multimon
  75  * environment, since the glyph cache texture is shared between all contexts,
  76  * and (in theory) OpenGL drivers should be smart enough to manage that
  77  * texture across all screens.
  78  */
  79 
  80 static GlyphCacheInfo *glyphCacheLCD = NULL;
  81 static GlyphCacheInfo *glyphCacheAA = NULL;
  82 
  83 /**
  84  * The handle to the LCD text fragment program object.
  85  */
  86 static GLhandleARB lcdTextProgram = 0;
  87 
  88 /**
  89  * This value tracks the previous LCD contrast setting, so if the contrast
  90  * value hasn't changed since the last time the gamma uniforms were
  91  * updated (not very common), then we can skip updating the unforms.
  92  */
  93 static jint lastLCDContrast = -1;
  94 
  95 /**
  96  * This value tracks the previous LCD rgbOrder setting, so if the rgbOrder
  97  * value has changed since the last time, it indicates that we need to
  98  * invalidate the cache, which may already store glyph images in the reverse
  99  * order.  Note that in most real world applications this value will not
 100  * change over the course of the application, but tests like Font2DTest
 101  * allow for changing the ordering at runtime, so we need to handle that case.


 112 /**
 113  * These constants define the size of the "cached destination" texture.
 114  * This texture is only used when rendering LCD-optimized text, as that
 115  * codepath needs direct access to the destination.  There is no way to
 116  * access the framebuffer directly from an OpenGL shader, so we need to first
 117  * copy the destination region corresponding to a particular glyph into
 118  * this cached texture, and then that texture will be accessed inside the
 119  * shader.  Copying the destination into this cached texture can be a very
 120  * expensive operation (accounting for about half the rendering time for
 121  * LCD text), so to mitigate this cost we try to bulk read a horizontal
 122  * region of the destination at a time.  (These values are empirically
 123  * derived for the common case where text runs horizontally.)
 124  *
 125  * Note: It is assumed in various calculations below that:
 126  *     (OGLTR_CACHED_DEST_WIDTH  >= OGLTR_CACHE_CELL_WIDTH)  &&
 127  *     (OGLTR_CACHED_DEST_WIDTH  >= OGLTR_NOCACHE_TILE_SIZE) &&
 128  *     (OGLTR_CACHED_DEST_HEIGHT >= OGLTR_CACHE_CELL_HEIGHT) &&
 129  *     (OGLTR_CACHED_DEST_HEIGHT >= OGLTR_NOCACHE_TILE_SIZE)
 130  */
 131 #define OGLTR_CACHED_DEST_WIDTH  512
 132 #define OGLTR_CACHED_DEST_HEIGHT (OGLTR_CACHE_CELL_HEIGHT * 2)
 133 
 134 /**
 135  * The handle to the "cached destination" texture object.
 136  */
 137 static GLuint cachedDestTextureID = 0;
 138 
 139 /**
 140  * The current bounds of the "cached destination" texture, in destination
 141  * coordinate space.  The width/height of these bounds will not exceed the
 142  * OGLTR_CACHED_DEST_WIDTH/HEIGHT values defined above.  These bounds are
 143  * only considered valid when the isCachedDestValid flag is JNI_TRUE.
 144  */
 145 static SurfaceDataBounds cachedDestBounds;
 146 
 147 /**
 148  * This flag indicates whether the "cached destination" texture contains
 149  * valid data.  This flag is reset to JNI_FALSE at the beginning of every
 150  * call to OGLTR_DrawGlyphList().  Once we copy valid destination data
 151  * into the cached texture, this flag is set to JNI_TRUE.  This way, we can
 152  * limit the number of times we need to copy destination data, which is a


 186                                   OGLTR_CACHE_CELL_WIDTH,
 187                                   OGLTR_CACHE_CELL_HEIGHT,
 188                                   OGLVertexCache_FlushVertexCache);
 189     if (gcinfo == NULL) {
 190         J2dRlsTraceLn(J2D_TRACE_ERROR,
 191                       "OGLTR_InitGlyphCache: could not init OGL glyph cache");
 192         return JNI_FALSE;
 193     }
 194 
 195     // init cache texture object
 196     j2d_glGenTextures(1, &gcinfo->cacheID);
 197     j2d_glBindTexture(GL_TEXTURE_2D, gcinfo->cacheID);
 198     j2d_glPrioritizeTextures(1, &gcinfo->cacheID, &priority);
 199     j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 200     j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 201 
 202     j2d_glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,
 203                      OGLTR_CACHE_WIDTH, OGLTR_CACHE_HEIGHT, 0,
 204                      pixelFormat, GL_UNSIGNED_BYTE, NULL);
 205 
 206     if (lcdCache) {
 207         glyphCacheLCD = gcinfo;
 208     } else {
 209         glyphCacheAA = gcinfo;
 210     }
 211 
 212     return JNI_TRUE;
 213 }
 214 
 215 /**
 216  * Adds the given glyph to the glyph cache (texture and data structure)
 217  * associated with the given OGLContext.
 218  */
 219 static void
 220 OGLTR_AddToGlyphCache(GlyphInfo *glyph, GLenum pixelFormat)
 221 {

 222     CacheCellInfo *ccinfo;
 223     GlyphCacheInfo *gcinfo;
 224 
 225     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_AddToGlyphCache");
 226 
 227     if (pixelFormat == GL_LUMINANCE) {
 228         gcinfo = glyphCacheAA;
 229     } else {
 230         gcinfo = glyphCacheLCD;
 231     }
 232     
 233     if ((gcinfo == NULL) || (glyph->image == NULL)) {
 234         return;


 235     }
 236 
 237     AccelGlyphCache_AddGlyph(gcinfo, glyph);
 238     ccinfo = (CacheCellInfo *) glyph->cellInfo;
 239 
 240     if (ccinfo != NULL) {
 241         // store glyph image in texture cell
 242         j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
 243                             ccinfo->x, ccinfo->y,
 244                             glyph->width, glyph->height,
 245                             pixelFormat, GL_UNSIGNED_BYTE, glyph->image);
 246     }
 247 }
 248 
 249 /**
 250  * This is the GLSL fragment shader source code for rendering LCD-optimized
 251  * text.  Do not be frightened; it is much easier to understand than the
 252  * equivalent ASM-like fragment program!
 253  *
 254  * The "uniform" variables at the top are initialized once the program is
 255  * linked, and are updated at runtime as needed (e.g. when the source color
 256  * changes, we will modify the "src_adj" value in OGLTR_UpdateLCDTextColor()).
 257  *


 390     // get the current OpenGL primary color state
 391     j2d_glGetFloatv(GL_CURRENT_COLOR, clr);
 392 
 393     // gamma adjust the primary color
 394     radj = (GLfloat)pow(clr[0], gamma);
 395     gadj = (GLfloat)pow(clr[1], gamma);
 396     badj = (GLfloat)pow(clr[2], gamma);
 397 
 398     // update the "src_adj" parameter of the shader program with this value
 399     loc = j2d_glGetUniformLocationARB(lcdTextProgram, "src_adj");
 400     j2d_glUniform3fARB(loc, radj, gadj, badj);
 401 
 402     return JNI_TRUE;
 403 }
 404 
 405 /**
 406  * Enables the LCD text shader and updates any related state, such as the
 407  * gamma lookup table textures.
 408  */
 409 static jboolean
 410 OGLTR_EnableLCDGlyphModeState(GLuint glyphTextureID,
 411                               GLuint dstTextureID,
 412                               jint contrast)
 413 {
 414     // bind the texture containing glyph data to texture unit 0
 415     j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 416     j2d_glBindTexture(GL_TEXTURE_2D, glyphTextureID);
 417     j2d_glEnable(GL_TEXTURE_2D);
 418 
 419     // bind the texture tile containing destination data to texture unit 1
 420     j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
 421     if (dstTextureID != 0) {
 422         j2d_glBindTexture(GL_TEXTURE_2D, dstTextureID);
 423     } else {
 424         if (cachedDestTextureID == 0) {
 425             cachedDestTextureID =
 426                 OGLContext_CreateBlitTexture(GL_RGB8, GL_RGB,
 427                                              OGLTR_CACHED_DEST_WIDTH,
 428                                              OGLTR_CACHED_DEST_HEIGHT);
 429             if (cachedDestTextureID == 0) {
 430                 return JNI_FALSE;
 431             }
 432         }
 433         j2d_glBindTexture(GL_TEXTURE_2D, cachedDestTextureID);
 434     }
 435 
 436     // note that GL_TEXTURE_2D was already enabled for texture unit 0,
 437     // but we need to explicitly enable it for texture unit 1
 438     j2d_glEnable(GL_TEXTURE_2D);
 439 
 440     // create the LCD text shader, if necessary
 441     if (lcdTextProgram == 0) {
 442         lcdTextProgram = OGLTR_CreateLCDTextProgram();
 443         if (lcdTextProgram == 0) {
 444             return JNI_FALSE;
 445         }
 446     }
 447 
 448     // enable the LCD text shader
 449     j2d_glUseProgramObjectARB(lcdTextProgram);
 450 
 451     // update the current contrast settings, if necessary
 452     if (lastLCDContrast != contrast) {
 453         if (!OGLTR_UpdateLCDTextContrast(contrast)) {
 454             return JNI_FALSE;


 456         lastLCDContrast = contrast;
 457     }
 458 
 459     // update the current color settings
 460     if (!OGLTR_UpdateLCDTextColor(contrast)) {
 461         return JNI_FALSE;
 462     }
 463 
 464     return JNI_TRUE;
 465 }
 466 
 467 void
 468 OGLTR_EnableGlyphVertexCache(OGLContext *oglc)
 469 {
 470     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_EnableGlyphVertexCache");
 471 
 472     if (!OGLVertexCache_InitVertexCache(oglc)) {
 473         return;
 474     }
 475 
 476     if (glyphCacheAA == NULL) {
 477         if (!OGLTR_InitGlyphCache(JNI_FALSE)) {
 478             return;
 479         }
 480     }
 481 
 482     j2d_glEnable(GL_TEXTURE_2D);
 483     j2d_glBindTexture(GL_TEXTURE_2D, glyphCacheAA->cacheID);
 484     j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 485 
 486     // for grayscale/monochrome text, the current OpenGL source color
 487     // is modulated with the glyph image as part of the texture
 488     // application stage, so we use GL_MODULATE here
 489     OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
 490 }
 491 
 492 void
 493 OGLTR_DisableGlyphVertexCache(OGLContext *oglc)
 494 {
 495     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DisableGlyphVertexCache");
 496 
 497     OGLVertexCache_FlushVertexCache();
 498     OGLVertexCache_RestoreColorState(oglc);
 499 
 500     j2d_glDisable(GL_TEXTURE_2D);
 501     j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 502     j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 503     j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);


 506 
 507 /**
 508  * Disables any pending state associated with the current "glyph mode".
 509  */
 510 static void
 511 OGLTR_DisableGlyphModeState()
 512 {
 513     switch (glyphMode) {
 514     case MODE_NO_CACHE_LCD:
 515         j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 516         j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
 517         /* FALLTHROUGH */
 518 
 519     case MODE_USE_CACHE_LCD:
 520         j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 521         j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 522         j2d_glUseProgramObjectARB(0);
 523         j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
 524         j2d_glDisable(GL_TEXTURE_2D);
 525         j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 526         j2d_glDisable(GL_TEXTURE_2D);
 527         break;
 528 
 529     case MODE_NO_CACHE_GRAY:
 530     case MODE_USE_CACHE_GRAY:
 531     case MODE_NOT_INITED:
 532     default:
 533         break;
 534     }
 535 }
 536 
 537 static jboolean
 538 OGLTR_DrawGrayscaleGlyphViaCache(OGLContext *oglc,
 539                                  GlyphInfo *ginfo, jint x, jint y)
 540 {
 541     CacheCellInfo *cell;
 542     jfloat x1, y1, x2, y2;
 543 
 544     if (glyphMode != MODE_USE_CACHE_GRAY) {
 545         OGLTR_DisableGlyphModeState();
 546         CHECK_PREVIOUS_OP(OGL_STATE_GLYPH_OP);
 547         glyphMode = MODE_USE_CACHE_GRAY;
 548     }
 549 
 550     if (ginfo->cellInfo == NULL) {
 551         // attempt to add glyph to accelerated glyph cache
 552         OGLTR_AddToGlyphCache(ginfo, GL_LUMINANCE);
 553 
 554         if (ginfo->cellInfo == NULL) {
 555             // we'll just no-op in the rare case that the cell is NULL
 556             return JNI_TRUE;
 557         }
 558     }
 559 
 560     cell = (CacheCellInfo *) (ginfo->cellInfo);
 561     cell->timesRendered++;
 562 
 563     x1 = (jfloat)x;
 564     y1 = (jfloat)y;
 565     x2 = x1 + ginfo->width;
 566     y2 = y1 + ginfo->height;
 567 
 568     OGLVertexCache_AddGlyphQuad(oglc,
 569                                 cell->tx1, cell->ty1,
 570                                 cell->tx2, cell->ty2,
 571                                 x1, y1, x2, y2);
 572 


 692 
 693         // update the cached bounds and mark it valid
 694         cachedDestBounds.x1 = dx1;
 695         cachedDestBounds.y1 = dy1;
 696         cachedDestBounds.x2 = dx2;
 697         cachedDestBounds.y2 = dy2;
 698         isCachedDestValid = JNI_TRUE;
 699     }
 700 
 701     // always update the previous glyph bounds
 702     previousGlyphBounds.x1 = gx1;
 703     previousGlyphBounds.y1 = gy1;
 704     previousGlyphBounds.x2 = gx2;
 705     previousGlyphBounds.y2 = gy2;
 706 }
 707 
 708 static jboolean
 709 OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps,
 710                            GlyphInfo *ginfo, jint x, jint y,
 711                            jint glyphIndex, jint totalGlyphs,
 712                            jboolean rgbOrder, jint contrast,
 713                             GLuint dstTextureID)
 714 {
 715     CacheCellInfo *cell;
 716     jint dx1, dy1, dx2, dy2;
 717     jfloat dtx1, dty1, dtx2, dty2;
 718 
 719     if (glyphMode != MODE_USE_CACHE_LCD) {
 720         OGLTR_DisableGlyphModeState();
 721         CHECK_PREVIOUS_OP(GL_TEXTURE_2D);
 722         j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 723 
 724         if (glyphCacheLCD == NULL) {
 725             if (!OGLTR_InitGlyphCache(JNI_TRUE)) {
 726                 return JNI_FALSE;
 727             }
 728         }
 729 
 730         if (rgbOrder != lastRGBOrder) {
 731             // need to invalidate the cache in this case; see comments
 732             // for lastRGBOrder above
 733             AccelGlyphCache_Invalidate(glyphCacheLCD);
 734             lastRGBOrder = rgbOrder;
 735         }
 736 
 737         if (!OGLTR_EnableLCDGlyphModeState(glyphCacheLCD->cacheID,
 738                                            dstTextureID, contrast))
 739         {
 740             return JNI_FALSE;
 741         }
 742 
 743         // when a fragment shader is enabled, the texture function state is
 744         // ignored, so the following line is not needed...
 745         // OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
 746 
 747         glyphMode = MODE_USE_CACHE_LCD;
 748     }
 749 
 750     if (ginfo->cellInfo == NULL) {
 751         // rowBytes will always be a multiple of 3, so the following is safe
 752         j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, ginfo->rowBytes / 3);
 753 
 754         // make sure the glyph cache texture is bound to texture unit 0
 755         j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 756 
 757         // attempt to add glyph to accelerated glyph cache
 758         OGLTR_AddToGlyphCache(ginfo, rgbOrder ? GL_RGB : GL_BGR);
 759 
 760         if (ginfo->cellInfo == NULL) {
 761             // we'll just no-op in the rare case that the cell is NULL
 762             return JNI_TRUE;
 763         }
 764     }
 765 
 766     cell = (CacheCellInfo *) (ginfo->cellInfo);
 767     cell->timesRendered++;
 768 
 769     // location of the glyph in the destination's coordinate space
 770     dx1 = x;
 771     dy1 = y;
 772     dx2 = dx1 + ginfo->width;
 773     dy2 = dy1 + ginfo->height;
 774 
 775     if (dstTextureID == 0) {
 776         // copy destination into second cached texture, if necessary
 777         OGLTR_UpdateCachedDestination(dstOps, ginfo,
 778                                       dx1, dy1, dx2, dy2,
 779                                       glyphIndex, totalGlyphs);
 780 
 781         // texture coordinates of the destination tile
 782         dtx1 = ((jfloat)(dx1 - cachedDestBounds.x1)) / OGLTR_CACHED_DEST_WIDTH;
 783         dty1 = ((jfloat)(cachedDestBounds.y2 - dy1)) / OGLTR_CACHED_DEST_HEIGHT;
 784         dtx2 = ((jfloat)(dx2 - cachedDestBounds.x1)) / OGLTR_CACHED_DEST_WIDTH;
 785         dty2 = ((jfloat)(cachedDestBounds.y2 - dy2)) / OGLTR_CACHED_DEST_HEIGHT;
 786     } else {
 787         jint gw = ginfo->width;
 788         jint gh = ginfo->height;
 789 
 790         // this accounts for lower-left origin of the destination region
 791         jint dxadj = dstOps->xOffset + x;
 792         jint dyadj = dstOps->yOffset + dstOps->height - (y + gh);
 793 
 794         // update the remaining destination texture coordinates
 795         dtx1 =((GLfloat)dxadj) / dstOps->textureWidth;
 796         dtx2 = ((GLfloat)dxadj + gw) / dstOps->textureWidth;
 797 
 798         dty1 = ((GLfloat)dyadj + gh) / dstOps->textureHeight;
 799         dty2 = ((GLfloat)dyadj) / dstOps->textureHeight;
 800 
 801         j2d_glTextureBarrierNV();
 802     }
 803 
 804     // render composed texture to the destination surface
 805     j2d_glBegin(GL_QUADS);
 806     j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty1);
 807     j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
 808     j2d_glVertex2i(dx1, dy1);
 809     j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx2, cell->ty1);
 810     j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
 811     j2d_glVertex2i(dx2, dy1);
 812     j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx2, cell->ty2);
 813     j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
 814     j2d_glVertex2i(dx2, dy2);
 815     j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty2);
 816     j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
 817     j2d_glVertex2i(dx1, dy2);
 818     j2d_glEnd();
 819 
 820     return JNI_TRUE;
 821 }
 822 


 843     for (sy = 0; sy < h; sy += th, y += th) {
 844         x = x0;
 845         sh = ((sy + th) > h) ? (h - sy) : th;
 846 
 847         for (sx = 0; sx < w; sx += tw, x += tw) {
 848             sw = ((sx + tw) > w) ? (w - sx) : tw;
 849 
 850             OGLVertexCache_AddMaskQuad(oglc,
 851                                        sx, sy, x, y, sw, sh,
 852                                        w, ginfo->image);
 853         }
 854     }
 855 
 856     return JNI_TRUE;
 857 }
 858 
 859 static jboolean
 860 OGLTR_DrawLCDGlyphNoCache(OGLContext *oglc, OGLSDOps *dstOps,
 861                           GlyphInfo *ginfo, jint x, jint y,
 862                           jint rowBytesOffset,
 863                           jboolean rgbOrder, jint contrast,
 864                           GLuint dstTextureID)
 865 {
 866     GLfloat tx1, ty1, tx2, ty2;
 867     GLfloat dtx1, dty1, dtx2, dty2;
 868     jint tw, th;
 869     jint sx, sy, sw, sh, dxadj, dyadj;
 870     jint x0;
 871     jint w = ginfo->width;
 872     jint h = ginfo->height;
 873     GLenum pixelFormat = rgbOrder ? GL_RGB : GL_BGR;
 874 
 875     if (glyphMode != MODE_NO_CACHE_LCD) {
 876         OGLTR_DisableGlyphModeState();
 877         CHECK_PREVIOUS_OP(GL_TEXTURE_2D);
 878         j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 879 
 880         if (oglc->blitTextureID == 0) {
 881             if (!OGLContext_InitBlitTileTexture(oglc)) {
 882                 return JNI_FALSE;
 883             }
 884         }
 885 
 886         if (!OGLTR_EnableLCDGlyphModeState(oglc->blitTextureID,
 887                                            dstTextureID, contrast))
 888         {
 889             return JNI_FALSE;
 890         }
 891 
 892         // when a fragment shader is enabled, the texture function state is
 893         // ignored, so the following line is not needed...
 894         // OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
 895 
 896         glyphMode = MODE_NO_CACHE_LCD;
 897     }
 898 
 899     // rowBytes will always be a multiple of 3, so the following is safe
 900     j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, ginfo->rowBytes / 3);
 901 
 902     x0 = x;
 903     tx1 = 0.0f;
 904     ty1 = 0.0f;
 905     dtx1 = 0.0f;
 906     dty2 = 0.0f;
 907     tw = OGLTR_NOCACHE_TILE_SIZE;
 908     th = OGLTR_NOCACHE_TILE_SIZE;


 916 
 917             // update the source pointer offsets
 918             j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
 919             j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
 920 
 921             // copy LCD mask into glyph texture tile
 922             j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
 923             j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
 924                                 0, 0, sw, sh,
 925                                 pixelFormat, GL_UNSIGNED_BYTE,
 926                                 ginfo->image + rowBytesOffset);
 927 
 928             // update the lower-right glyph texture coordinates
 929             tx2 = ((GLfloat)sw) / OGLC_BLIT_TILE_SIZE;
 930             ty2 = ((GLfloat)sh) / OGLC_BLIT_TILE_SIZE;
 931 
 932             // this accounts for lower-left origin of the destination region
 933             dxadj = dstOps->xOffset + x;
 934             dyadj = dstOps->yOffset + dstOps->height - (y + sh);
 935 
 936             if (dstTextureID == 0) {
 937                 // copy destination into cached texture tile (the lower-left
 938                 // corner of the destination region will be positioned at the
 939                 // lower-left corner (0,0) of the texture)
 940                 j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
 941                 j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
 942                                         0, 0,
 943                                         dxadj, dyadj,
 944                                         sw, sh);

 945                 // update the remaining destination texture coordinates
 946                 dtx2 = ((GLfloat)sw) / OGLTR_CACHED_DEST_WIDTH;
 947                 dty1 = ((GLfloat)sh) / OGLTR_CACHED_DEST_HEIGHT;
 948             } else {
 949                 // use the destination texture directly
 950                 // update the remaining destination texture coordinates
 951                 dtx1 =((GLfloat)dxadj) / ((GLfloat)dstOps->textureWidth);
 952                 dtx2 = ((GLfloat)dxadj + sw) / ((GLfloat)dstOps->textureWidth);
 953 
 954                 dty1 = ((GLfloat)dyadj + sh) / ((GLfloat)dstOps->textureHeight);
 955                 dty2 = ((GLfloat)dyadj) / ((GLfloat)dstOps->textureHeight);
 956 
 957                 j2d_glTextureBarrierNV();
 958             }
 959 
 960             // render composed texture to the destination surface
 961             j2d_glBegin(GL_QUADS);
 962             j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx1, ty1);
 963             j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
 964             j2d_glVertex2i(x, y);
 965             j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty1);
 966             j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
 967             j2d_glVertex2i(x + sw, y);
 968             j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty2);
 969             j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
 970             j2d_glVertex2i(x + sw, y + sh);
 971             j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx1, ty2);
 972             j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
 973             j2d_glVertex2i(x, y + sh);
 974             j2d_glEnd();
 975         }
 976     }
 977 
 978     return JNI_TRUE;
 979 }
 980 
 981 // see DrawGlyphList.c for more on this macro...
 982 #define FLOOR_ASSIGN(l, r) \
 983     if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
 984 
 985 void
 986 OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
 987                     jint totalGlyphs, jboolean usePositions,
 988                     jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
 989                     jfloat glyphListOrigX, jfloat glyphListOrigY,
 990                     unsigned char *images, unsigned char *positions)
 991 {
 992     int glyphCounter;
 993     GLuint dstTextureID = 0;
 994 
 995     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DrawGlyphList");
 996 
 997     RETURN_IF_NULL(oglc);
 998     RETURN_IF_NULL(dstOps);
 999     RETURN_IF_NULL(images);
1000     if (usePositions) {
1001         RETURN_IF_NULL(positions);
1002     }
1003 
1004     glyphMode = MODE_NOT_INITED;
1005     isCachedDestValid = JNI_FALSE;
1006 
1007     if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_TEXBARRIER) &&
1008         dstOps->textureTarget == GL_TEXTURE_2D)
1009     {
1010         dstTextureID = dstOps->textureID;
1011     }
1012 
1013     for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
1014         jint x, y;
1015         jfloat glyphx, glyphy;
1016         jboolean grayscale, ok;
1017         GlyphInfo *ginfo = (GlyphInfo *)jlong_to_ptr(NEXT_LONG(images));
1018 
1019         if (ginfo == NULL) {
1020             // this shouldn't happen, but if it does we'll just break out...
1021             J2dRlsTraceLn(J2D_TRACE_ERROR,
1022                           "OGLTR_DrawGlyphList: glyph info is null");
1023             break;
1024         }
1025 
1026         grayscale = (ginfo->rowBytes == ginfo->width);
1027 
1028         if (usePositions) {
1029             jfloat posx = NEXT_FLOAT(positions);
1030             jfloat posy = NEXT_FLOAT(positions);
1031             glyphx = glyphListOrigX + posx + ginfo->topLeftX;
1032             glyphy = glyphListOrigY + posy + ginfo->topLeftY;
1033             FLOOR_ASSIGN(x, glyphx);
1034             FLOOR_ASSIGN(y, glyphy);
1035         } else {
1036             glyphx = glyphListOrigX + ginfo->topLeftX;
1037             glyphy = glyphListOrigY + ginfo->topLeftY;
1038             FLOOR_ASSIGN(x, glyphx);
1039             FLOOR_ASSIGN(y, glyphy);
1040             glyphListOrigX += ginfo->advanceX;
1041             glyphListOrigY += ginfo->advanceY;
1042         }
1043 
1044         if (ginfo->image == NULL) {
1045             continue;
1046         }
1047 
1048         if (grayscale) {
1049             // grayscale or monochrome glyph data
1050             if (ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&

1051                 ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
1052             {
1053                 ok = OGLTR_DrawGrayscaleGlyphViaCache(oglc, ginfo, x, y);
1054             } else {
1055                 ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y);
1056             }
1057         } else {
1058             // LCD-optimized glyph data
1059             jint rowBytesOffset = 0;
1060 
1061             if (subPixPos) {
1062                 jint frac = (jint)((glyphx - x) * 3);
1063                 if (frac != 0) {
1064                     rowBytesOffset = 3 - frac;
1065                     x += 1;
1066                 }
1067             }
1068 
1069             if (rowBytesOffset == 0 &&

1070                 ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
1071                 ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
1072             {
1073                 ok = OGLTR_DrawLCDGlyphViaCache(oglc, dstOps,
1074                                                 ginfo, x, y,
1075                                                 glyphCounter, totalGlyphs,
1076                                                 rgbOrder, lcdContrast,
1077                                                 dstTextureID);
1078             } else {
1079                 ok = OGLTR_DrawLCDGlyphNoCache(oglc, dstOps,
1080                                                ginfo, x, y,
1081                                                rowBytesOffset,
1082                                                rgbOrder, lcdContrast,
1083                                                dstTextureID);
1084             }
1085         }
1086 
1087         if (!ok) {
1088             break;
1089         }
1090     }
1091 
1092     OGLTR_DisableGlyphModeState();
1093 }
1094 
1095 JNIEXPORT void JNICALL
1096 Java_sun_java2d_opengl_OGLTextRenderer_drawGlyphList
1097     (JNIEnv *env, jobject self,
1098      jint numGlyphs, jboolean usePositions,
1099      jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
1100      jfloat glyphListOrigX, jfloat glyphListOrigY,
1101      jlongArray imgArray, jfloatArray posArray)
1102 {
1103     unsigned char *images;


< prev index next >