1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifndef HEADLESS
  27 
  28 #include <stdlib.h>
  29 #include <limits.h>
  30 #include <math.h>
  31 #include <jlong.h>
  32 
  33 #include "sun_java2d_metal_MTLTextRenderer.h"
  34 
  35 #include "SurfaceData.h"
  36 #include "MTLContext.h"
  37 #include "MTLRenderQueue.h"
  38 #include "MTLTextRenderer.h"
  39 #include "MTLVertexCache.h"
  40 #include "AccelGlyphCache.h"
  41 
  42 /**
  43  * The following constants define the inner and outer bounds of the
  44  * accelerated glyph cache.
  45  */
  46 #define MTLTR_CACHE_WIDTH       1024
  47 #define MTLTR_CACHE_HEIGHT      1024
  48 #define MTLTR_CACHE_CELL_WIDTH  64
  49 #define MTLTR_CACHE_CELL_HEIGHT 64
  50 
  51 /**
  52  * The current "glyph mode" state.  This variable is used to track the
  53  * codepath used to render a particular glyph.  This variable is reset to
  54  * MODE_NOT_INITED at the beginning of every call to MTLTR_DrawGlyphList().
  55  * As each glyph is rendered, the glyphMode variable is updated to reflect
  56  * the current mode, so if the current mode is the same as the mode used
  57  * to render the previous glyph, we can avoid doing costly setup operations
  58  * each time.
  59  */
  60 typedef enum {
  61     MODE_NOT_INITED,
  62     MODE_USE_CACHE_GRAY,
  63     MODE_USE_CACHE_LCD,
  64     MODE_NO_CACHE_GRAY,
  65     MODE_NO_CACHE_LCD,
  66     MODE_NO_CACHE_COLOR
  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.
 102  */
 103 static jboolean lastRGBOrder = JNI_TRUE;
 104 
 105 /**
 106  * This constant defines the size of the tile to use in the
 107  * MTLTR_DrawLCDGlyphNoCache() method.  See below for more on why we
 108  * restrict this value to a particular size.
 109  */
 110 #define MTLTR_NOCACHE_TILE_SIZE 64
 111 
 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  *     (MTLTR_CACHED_DEST_WIDTH  >= MTLTR_CACHE_CELL_WIDTH)  &&
 127  *     (MTLTR_CACHED_DEST_WIDTH  >= MTLTR_NOCACHE_TILE_SIZE) &&
 128  *     (MTLTR_CACHED_DEST_HEIGHT >= MTLTR_CACHE_CELL_HEIGHT) &&
 129  *     (MTLTR_CACHED_DEST_HEIGHT >= MTLTR_NOCACHE_TILE_SIZE)
 130  */
 131 #define MTLTR_CACHED_DEST_WIDTH  1024
 132 #define MTLTR_CACHED_DEST_HEIGHT (MTLTR_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  * MTLTR_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 MTLTR_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
 153  * very costly operation.
 154  */
 155 static jboolean isCachedDestValid = JNI_FALSE;
 156 
 157 /**
 158  * The bounds of the previously rendered LCD glyph, in destination
 159  * coordinate space.  We use these bounds to determine whether the glyph
 160  * currently being rendered overlaps the previously rendered glyph (i.e.
 161  * its bounding box intersects that of the previously rendered glyph).  If
 162  * so, we need to re-read the destination area associated with that previous
 163  * glyph so that we can correctly blend with the actual destination data.
 164  */
 165 static SurfaceDataBounds previousGlyphBounds;
 166 
 167 /**
 168  * Initializes the one glyph cache (texture and data structure).
 169  * If lcdCache is JNI_TRUE, the texture will contain RGB data,
 170  * otherwise we will simply store the grayscale/monochrome glyph images
 171  * as intensity values (which work well with the GL_MODULATE function).
 172  */
 173 static jboolean
 174 MTLTR_InitGlyphCache(jboolean lcdCache)
 175 {
 176     //TODO
 177     J2dTraceNotImplPrimitive("MTLTR_InitGlyphCache");
 178 
 179     return JNI_TRUE;
 180 }
 181 
 182 /**
 183  * Adds the given glyph to the glyph cache (texture and data structure)
 184  * associated with the given MTLContext.
 185  */
 186 static void
 187 MTLTR_AddTmTLyphCache(GlyphInfo *glyph, GLenum pixelFormat)
 188 {
 189     //TODO
 190     J2dTraceNotImplPrimitive("MTLTR_AddTmTLyphCache");
 191 
 192     CacheCellInfo *ccinfo;
 193     GlyphCacheInfo *gcinfo;
 194 
 195     J2dTraceLn(J2D_TRACE_INFO, "MTLTR_AddTmTLyphCache");
 196     J2dTracePrimitive("MTLTR_InitGlyphCache");
 197 }
 198 
 199 /**
 200  * (Re)Initializes the gamma related uniforms.
 201  *
 202  * The given contrast value is an int in the range [100, 250] which we will
 203  * then scale to fit in the range [1.0, 2.5].
 204  */
 205 static jboolean
 206 MTLTR_UpdateLCDTextContrast(jint contrast)
 207 {
 208     //TODO
 209     J2dTraceNotImplPrimitive("MTLTR_UpdateLCDTextContrast");
 210     return JNI_TRUE;
 211 }
 212 
 213 /**
 214  * Updates the current gamma-adjusted source color ("src_adj") of the LCD
 215  * text shader program.  Note that we could calculate this value in the
 216  * shader (e.g. just as we do for "dst_adj"), but would be unnecessary work
 217  * (and a measurable performance hit, maybe around 5%) since this value is
 218  * constant over the entire glyph list.  So instead we just calculate the
 219  * gamma-adjusted value once and update the uniform parameter of the LCD
 220  * shader as needed.
 221  */
 222 static jboolean
 223 MTLTR_UpdateLCDTextColor(jint contrast)
 224 {
 225     //TODO
 226     J2dTraceNotImplPrimitive("MTLTR_UpdateLCDTextColor");
 227     return JNI_TRUE;
 228 }
 229 
 230 /**
 231  * Enables the LCD text shader and updates any related state, such as the
 232  * gamma lookup table textures.
 233  */
 234 static jboolean
 235 MTLTR_EnableLCDGlyphModeState(GLuint glyphTextureID,
 236                               GLuint dstTextureID,
 237                               jint contrast)
 238 {
 239     //TODO
 240     J2dTraceNotImplPrimitive("MTLTR_EnableLCDGlyphModeState");
 241     return JNI_TRUE;
 242 }
 243 
 244 void
 245 MTLTR_EnableGlyphVertexCache(MTLContext *mtlc)
 246 {
 247     //TODO
 248     J2dTraceNotImplPrimitive("MTLTR_EnableGlyphVertexCache");
 249 }
 250 
 251 void
 252 MTLTR_DisableGlyphVertexCache(MTLContext *mtlc)
 253 {
 254     //TODO
 255     J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DisableGlyphVertexCache");
 256     J2dTraceNotImplPrimitive("MTLTR_DisableGlyphVertexCache");
 257 
 258 }
 259 
 260 /**
 261  * Disables any pending state associated with the current "glyph mode".
 262  */
 263 void
 264 MTLTR_DisableGlyphModeState()
 265 {
 266     //TODO
 267     J2dTraceNotImplPrimitive("MTLTR_DisableGlyphModeState");
 268     J2dTraceLn1(J2D_TRACE_VERBOSE,
 269                 "MTLTR_DisableGlyphModeState: mode=%d", glyphMode);
 270 }
 271 
 272 static jboolean
 273 MTLTR_DrawGrayscaleGlyphViaCache(MTLContext *mtlc,
 274                                  GlyphInfo *ginfo, jint x, jint y)
 275 {
 276     //TODO
 277     J2dTraceNotImplPrimitive("MTLTR_DisableGlyphVertexCache");
 278     return JNI_TRUE;
 279 }
 280 
 281 /**
 282  * Evaluates to true if the rectangle defined by gx1/gy1/gx2/gy2 is
 283  * inside outerBounds.
 284  */
 285 #define INSIDE(gx1, gy1, gx2, gy2, outerBounds) \
 286     (((gx1) >= outerBounds.x1) && ((gy1) >= outerBounds.y1) && \
 287      ((gx2) <= outerBounds.x2) && ((gy2) <= outerBounds.y2))
 288 
 289 /**
 290  * Evaluates to true if the rectangle defined by gx1/gy1/gx2/gy2 intersects
 291  * the rectangle defined by bounds.
 292  */
 293 #define INTERSECTS(gx1, gy1, gx2, gy2, bounds) \
 294     ((bounds.x2 > (gx1)) && (bounds.y2 > (gy1)) && \
 295      (bounds.x1 < (gx2)) && (bounds.y1 < (gy2)))
 296 
 297 /**
 298  * This method checks to see if the given LCD glyph bounds fall within the
 299  * cached destination texture bounds.  If so, this method can return
 300  * immediately.  If not, this method will copy a chunk of framebuffer data
 301  * into the cached destination texture and then update the current cached
 302  * destination bounds before returning.
 303  */
 304 static void
 305 MTLTR_UpdateCachedDestination(MTLSDOps *dstOps, GlyphInfo *ginfo,
 306                               jint gx1, jint gy1, jint gx2, jint gy2,
 307                               jint glyphIndex, jint totalGlyphs)
 308 {
 309     //TODO
 310     J2dTraceNotImplPrimitive("MTLTR_UpdateCachedDestination");
 311 }
 312 
 313 static jboolean
 314 MTLTR_DrawLCDGlyphViaCache(MTLContext *mtlc, MTLSDOps *dstOps,
 315                            GlyphInfo *ginfo, jint x, jint y,
 316                            jint glyphIndex, jint totalGlyphs,
 317                            jboolean rgbOrder, jint contrast,
 318                            jint dstTextureID, jboolean * opened)
 319 {
 320     //TODO
 321     J2dTraceNotImplPrimitive("MTLTR_DrawLCDGlyphViaCache");
 322     return JNI_TRUE;
 323 }
 324 
 325 static jboolean
 326 MTLTR_DrawGrayscaleGlyphNoCache(MTLContext *mtlc,
 327                                 GlyphInfo *ginfo, jint x, jint y)
 328 {
 329     //TODO
 330     J2dTraceNotImplPrimitive("MTLTR_DrawGrayscaleGlyphNoCache");
 331     return JNI_TRUE;
 332 }
 333 
 334 static jboolean
 335 MTLTR_DrawLCDGlyphNoCache(MTLContext *mtlc, MTLSDOps *dstOps,
 336                           GlyphInfo *ginfo, jint x, jint y,
 337                           jint rowBytesOffset,
 338                           jboolean rgbOrder, jint contrast,
 339                           jint dstTextureID)
 340 {
 341     //TODO
 342     J2dTraceNotImplPrimitive("MTLTR_DrawLCDGlyphNoCache");
 343     return JNI_TRUE;
 344 }
 345 
 346 static jboolean
 347 MTLTR_DrawColorGlyphNoCache(MTLContext *mtlc, GlyphInfo *ginfo, jint x, jint y)
 348 {
 349     //TODO
 350     J2dTraceNotImplPrimitive("MTLTR_DrawColorGlyphNoCache");
 351     return JNI_TRUE;
 352 }
 353 
 354 
 355 // see DrawGlyphList.c for more on this macro...
 356 #define FLOOR_ASSIGN(l, r) \
 357     if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
 358 
 359 void
 360 MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, MTLSDOps *dstOps,
 361                     jint totalGlyphs, jboolean usePositions,
 362                     jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
 363                     jfloat glyphListOrigX, jfloat glyphListOrigY,
 364                     unsigned char *images, unsigned char *positions)
 365 {
 366     //TODO
 367     J2dTraceNotImplPrimitive("MTLTR_DrawGlyphList");
 368 }
 369 
 370 JNIEXPORT void JNICALL
 371 Java_sun_java2d_metal_MTLTextRenderer_drawGlyphList
 372     (JNIEnv *env, jobject self,
 373      jint numGlyphs, jboolean usePositions,
 374      jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
 375      jfloat glyphListOrigX, jfloat glyphListOrigY,
 376      jlongArray imgArray, jfloatArray posArray)
 377 {
 378     //TODO
 379     J2dTraceNotImplPrimitive("MTLTextRenderer_drawGlyphList");
 380 }
 381 
 382 #endif /* !HEADLESS */