Initial implementation of mask cache for Text rendering metal-prototype-branch
authorjdv
Tue, 09 Jul 2019 17:05:20 +0530
branchmetal-prototype-branch
changeset 57462 db2be8544d10
parent 57458 3a7c29ba6b1c
child 57468 0cdde100278a
Initial implementation of mask cache for Text rendering
src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLTextRenderer.m
src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.h
src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.m
--- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLTextRenderer.m	Mon Jul 08 17:17:28 2019 +0530
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLTextRenderer.m	Tue Jul 09 17:05:20 2019 +0530
@@ -315,27 +315,39 @@
 MTLTR_DrawGrayscaleGlyphNoCache(MTLContext *mtlc,
                                 GlyphInfo *ginfo, jint x, jint y, BMTLSDOps *dstOps)
 {
-    jfloat dx1, dy1, dx2, dy2;
-    jint width = ginfo->width;
-    jint height = ginfo->height;
+    jint tw, th;
+    jint sx, sy, sw, sh;
+    jint x0;
+    jint w = ginfo->width;
+    jint h = ginfo->height;
 
     J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGrayscaleGlyphNoCache");
-    /*
-     * TODO : Glyph caching is not used yet we need to
-     * implement it.
-     */
     if (glyphMode != MODE_NO_CACHE_GRAY) {
+        //OGLTR_DisableGlyphModeState();
+        //CHECK_PREVIOUS_OP(OGL_STATE_MASK_OP);
         glyphMode = MODE_NO_CACHE_GRAY;
     }
 
-    dx1 = (jfloat)x;
-    dy1 = (jfloat)y;
-    dx2 = x + width;
-    dy2 = y + height;
-    J2dTraceLn4(J2D_TRACE_INFO,
-        "Destination coordinates dx1 = %f dy1 = %f dx2 = %f dy2 = %f", dx1, dy1, dx2, dy2);
-    MTLVertexCache_AddGlyphTexture(mtlc, width, height, ginfo, dstOps);
-    MTLVertexCache_AddVertexTriangles(dx1, dy1, dx2, dy2);
+    x0 = x;
+    tw = MTLVC_MASK_CACHE_TILE_WIDTH;
+    th = MTLVC_MASK_CACHE_TILE_HEIGHT;
+
+    for (sy = 0; sy < h; sy += th, y += th) {
+        x = x0;
+        sh = ((sy + th) > h) ? (h - sy) : th;
+
+        for (sx = 0; sx < w; sx += tw, x += tw) {
+            sw = ((sx + tw) > w) ? (w - sx) : tw;
+
+            J2dTraceLn7(J2D_TRACE_INFO, "sx = %d sy = %d x = %d y = %d sw = %d sh = %d w = %d", sx, sy, x, y, sw, sh, w);
+            MTLVertexCache_AddMaskQuad(mtlc,
+                                       sx, sy, x, y, sw, sh,
+                                       w, ginfo->image,
+                                       dstOps,
+                                       ginfo->width);
+        }
+    }
+
     return JNI_TRUE;
 }
 
@@ -385,7 +397,7 @@
     J2dTraceLn1(J2D_TRACE_INFO, "totalGlyphs = %d", totalGlyphs);
 
     MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps);
-    MTLVertexCache_InitVertexCache();
+    MTLVertexCache_EnableMaskCache(mtlc);
 
     for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
         J2dTraceLn(J2D_TRACE_INFO, "Entered for loop for glyph list");
@@ -424,9 +436,9 @@
             continue;
         }
 
+        J2dTraceLn2(J2D_TRACE_INFO, "Glyph width = %d height = %d", ginfo->width, ginfo->height);
         //TODO : Right now we have initial texture mapping logic
         // as we implement LCD, cache usage add new selection condition.
-
         if (grayscale) {
             // grayscale or monochrome glyph data
             if (ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&
@@ -457,7 +469,7 @@
                 ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&
                 ginfo->height <= MTLTR_CACHE_CELL_HEIGHT)
             {
-                J2dTraceLn(J2D_TRACE_INFO, "LCD cache");
+                J2dTraceLn(J2D_TRACE_INFO, "LCD cache not implemented");
                 /*ok = MTLTR_DrawLCDGlyphViaCache(oglc, dstOps,
                                                 ginfo, x, y,
                                                 glyphCounter, totalGlyphs,
@@ -465,7 +477,7 @@
                                                 dstTextureID);*/
                 ok = JNI_FALSE;
             } else {
-                J2dTraceLn(J2D_TRACE_INFO, "LCD no cache");
+                J2dTraceLn(J2D_TRACE_INFO, "LCD no cache not implemented");
                 /*ok = MTLTR_DrawLCDGlyphNoCache(oglc, dstOps,
                                                ginfo, x, y,
                                                rowBytesOffset,
--- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.h	Mon Jul 08 17:17:28 2019 +0530
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.h	Tue Jul 09 17:05:20 2019 +0530
@@ -80,14 +80,9 @@
                                 jint srcx, jint srcy,
                                 jint dstx, jint dsty,
                                 jint width, jint height,
-                                jint maskscan, void *mask);
-
-void MTLVertexCache_AddGlyphTexture(MTLContext *mtlc,
-                                    jint width, jint height,
-                                    GlyphInfo *ginfo,
-                                    BMTLSDOps *dstOps);
-void MTLVertexCache_AddVertexTriangles(jfloat dx1, jfloat dy1,
-                                       jfloat dx2, jfloat dy2);
+                                jint maskscan, void *mask,
+                                BMTLSDOps *dstOps,
+                                jint fullwidth);
 void MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps);
 
 #endif /* MTLVertexCache_h_Included */
--- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.m	Mon Jul 08 17:17:28 2019 +0530
+++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.m	Tue Jul 09 17:05:20 2019 +0530
@@ -42,12 +42,10 @@
 static J2DVertex *vertexCache = NULL;
 static jint vertexCacheIndex = 0;
 
-static jint maskCacheTexID = 0;
+id<MTLTexture> maskCacheTex = NULL;
 static jint maskCacheIndex = 0;
 
-id<MTLRenderCommandEncoder> encoder;
-id<MTLTexture> texturePool[MTLVC_MAX_TEX_INDEX];
-static jint texturePoolIndex = 0;
+id<MTLRenderCommandEncoder> encoder = NULL;
 
 #define MTLVC_ADD_VERTEX(TX, TY, DX, DY, DZ) \
     do { \
@@ -59,14 +57,14 @@
         v->position[2] = DZ; \
     } while (0)
 
-#define MTLVC_ADD_TRIANGLES(DX1, DY1, DX2, DY2) \
+#define MTLVC_ADD_TRIANGLES(TX1, TY1, TX2, TY2, DX1, DY1, DX2, DY2) \
     do { \
-        MTLVC_ADD_VERTEX(0, 0, DX1, DY1, 0); \
-        MTLVC_ADD_VERTEX(1, 0, DX2, DY1, 0); \
-        MTLVC_ADD_VERTEX(1, 1, DX2, DY2, 0); \
-        MTLVC_ADD_VERTEX(1, 1, DX2, DY2, 0); \
-        MTLVC_ADD_VERTEX(0, 1, DX1, DY2, 0); \
-        MTLVC_ADD_VERTEX(0, 0, DX1, DY1, 0); \
+        MTLVC_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \
+        MTLVC_ADD_VERTEX(TX2, TY1, DX2, DY1, 0); \
+        MTLVC_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \
+        MTLVC_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \
+        MTLVC_ADD_VERTEX(TX1, TY2, DX1, DY2, 0); \
+        MTLVC_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \
     } while (0)
 
 jboolean
@@ -90,20 +88,22 @@
     J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_FlushVertexCache");
 
     if (vertexCacheIndex > 0 ||
-        texturePoolIndex > 0) {
+        maskCacheIndex > 0) {
         id<MTLBuffer>vertexBuffer = [mtlc.device newBufferWithBytes:vertexCache
                                                  length:vertexCacheIndex * sizeof(J2DVertex)
                                                  options:MTLResourceOptionCPUCacheModeDefault];
         [encoder setVertexBuffer:vertexBuffer offset:0 atIndex:MeshVertexBuffer];
-        for (int i = 0; i < texturePoolIndex; i++) {
+        for (int i = 0; i < maskCacheIndex; i++) {
             J2dTraceLn1(J2D_TRACE_INFO, "MTLVertexCache_FlushVertexCache : draw texture at index %d", i);
-            [encoder setFragmentTexture:texturePool[i] atIndex: 0];
+            [encoder setFragmentTexture:maskCacheTex atIndex: 0];
             [encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:i*6 vertexCount:6];
         }
         [encoder endEncoding];
     }
     vertexCacheIndex = 0;
-    texturePoolIndex = 0;
+    maskCacheIndex = 0;
+    encoder = NULL;
+    maskCacheTex = NULL;
 }
 
 /**
@@ -147,18 +147,28 @@
 }
 
 static jboolean
-MTLVertexCache_InitMaskCache()
+MTLVertexCache_InitMaskCache(MTLContext *mtlc)
 {
-    // TODO
-    J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitMaskCache");
+    J2dTraceLn(J2D_TRACE_INFO, "OGLVertexCache_InitMaskCache");
+    MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatA8Unorm width:MTLVC_MASK_CACHE_WIDTH_IN_TEXELS height:MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS mipmapped:NO];
+    maskCacheTex = [mtlc.device newTextureWithDescriptor:textureDescriptor];
     return JNI_TRUE;
 }
 
 void
 MTLVertexCache_EnableMaskCache(MTLContext *mtlc)
 {
-    // TODO
     J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_EnableMaskCache");
+
+    if (!MTLVertexCache_InitVertexCache()) {
+        return;
+    }
+
+    if (maskCacheTex == NULL) {
+        if (!MTLVertexCache_InitMaskCache(mtlc)) {
+            return;
+        }
+    }
 }
 
 void
@@ -170,48 +180,101 @@
 }
 
 void
-MTLVertexCache_AddVertexTriangles(jfloat dx1, jfloat dy1,
-                                  jfloat dx2, jfloat dy2)
-{
-    J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_AddVertexTriangles");
-    MTLVC_ADD_TRIANGLES(dx1, dy1, dx2, dy2);
-}
-
-void
-MTLVertexCache_AddGlyphTexture(MTLContext *mtlc,
-                               jint width, jint height,
-                               GlyphInfo *ginfo,
-                               BMTLSDOps *dstOps)
-{
-    J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_AddGlyphTexture");
-    J2dTraceLn2(J2D_TRACE_INFO, "Glyph width = %d Glyph height = %d", width, height);
-    if (texturePoolIndex >= MTLVC_MAX_TEX_INDEX ||
-        vertexCacheIndex >= MTLVC_MAX_INDEX)
-    {
-        MTLVertexCache_FlushVertexCache(mtlc);
-        MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps);
-    }
-    MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatA8Unorm width:width height:height mipmapped:NO];
-    id <MTLTexture> texture = [mtlc.device newTextureWithDescriptor:textureDescriptor];
-    J2dTraceLn3(J2D_TRACE_INFO, "MTLVertexCache_AddGlyphTexture: created texture: tex=%p, w=%d h=%d", texture, width, height);
-    NSUInteger bytesPerRow = 1 * width;
-
-    MTLRegion region = {
-        { 0, 0, 0 },
-        {width, height, 1}
-    };
-    [texture replaceRegion:region
-             mipmapLevel:0
-             withBytes:ginfo->image
-             bytesPerRow:bytesPerRow];
-    texturePool[texturePoolIndex] = texture;
-    texturePoolIndex++;
-}
-
-void
 MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps) {
     J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_CreateSamplingEncoder");
     encoder = [mtlc createSamplingEncoderForDest:dstOps->pTexture];
 }
 
+void
+MTLVertexCache_AddMaskQuad(MTLContext *mtlc,
+                           jint srcx, jint srcy,
+                           jint dstx, jint dsty,
+                           jint width, jint height,
+                           jint maskscan, void *mask,
+                           BMTLSDOps *dstOps,
+                           jint fullwidth)
+{
+    jfloat tx1, ty1, tx2, ty2;
+    jfloat dx1, dy1, dx2, dy2;
+
+    J2dTraceLn1(J2D_TRACE_INFO, "MTLVertexCache_AddMaskQuad: %d",
+                maskCacheIndex);
+
+    if (maskCacheIndex >= MTLVC_MASK_CACHE_MAX_INDEX ||
+        vertexCacheIndex >= MTLVC_MAX_INDEX)
+    {
+        MTLVertexCache_FlushVertexCache(mtlc);
+        MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps);
+        // TODO : Since we are not committing command buffer
+        // in FlushVertexCache we need to create new maskcache
+        // after present cache is full. Check whether we can
+        // avoid multiple cache creation.
+        MTLVertexCache_EnableMaskCache(mtlc);
+    }
+
+    // TODO : Implement mask == null use case also
+    jint texx = MTLVC_MASK_CACHE_TILE_WIDTH *
+        (maskCacheIndex % MTLVC_MASK_CACHE_WIDTH_IN_TILES);
+    jint texy = MTLVC_MASK_CACHE_TILE_HEIGHT *
+        (maskCacheIndex / MTLVC_MASK_CACHE_WIDTH_IN_TILES);
+    J2dTraceLn5(J2D_TRACE_INFO, "texx = %d texy = %d width = %d height = %d fullwidth = %d", texx, texy, width, height, fullwidth);
+    NSUInteger bytesPerRow = 1 * width;
+    NSUInteger slice = bytesPerRow * srcy + srcx;
+    MTLRegion region = {
+        {texx, texy, 0 },
+        {width, height, 1}
+    };
+
+    // Whenever we have source stride bigger that destination stride
+    // we need to pick appropriate source subtexture. In repalceRegion
+    // we can give destination subtexturing properly but we can't
+    // subtexture from system memory glyph we have. So in such
+    // cases we are creating seperate tile and scan the source
+    // stride into destination using memcpy. In case of OpenGL we
+    // can update source pointers, in case of D3D we ar doing memcpy.
+    // We can use MTLBuffer and then copy source subtexture but that
+    // adds extra blitting logic.
+    // TODO : Research more and try removing memcpy logic.
+    if (fullwidth <= width) {
+        int height_offset = bytesPerRow * srcy;
+        [maskCacheTex replaceRegion:region
+                      mipmapLevel:0
+                      withBytes:mask + height_offset
+                      bytesPerRow:bytesPerRow];
+    } else {
+        int dst_offset, src_offset;
+        int size = 1 * width * height;
+        void* tile = malloc(size);
+        dst_offset = 0;
+        for (int i = srcy ; i < srcy + height; i++) {
+            J2dTraceLn2(J2D_TRACE_INFO, "srcx = %d srcy = %d", srcx, srcy);
+            src_offset = fullwidth * i + srcx;
+            J2dTraceLn2(J2D_TRACE_INFO, "src_offset = %d dst_offset = %d", src_offset, dst_offset);
+            memcpy(tile + dst_offset, mask + src_offset, width);
+            dst_offset = dst_offset + width;
+        }
+        [maskCacheTex replaceRegion:region
+                      mipmapLevel:0
+                      withBytes:tile
+                      bytesPerRow:bytesPerRow];
+    }
+
+    tx1 = ((jfloat)texx) / MTLVC_MASK_CACHE_WIDTH_IN_TEXELS;
+    ty1 = ((jfloat)texy) / MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS;
+
+    maskCacheIndex++;
+
+    tx2 = tx1 + (((jfloat)width) / MTLVC_MASK_CACHE_WIDTH_IN_TEXELS);
+    ty2 = ty1 + (((jfloat)height) / MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS);
+
+    dx1 = (jfloat)dstx;
+    dy1 = (jfloat)dsty;
+    dx2 = dx1 + width;
+    dy2 = dy1 + height;
+
+    J2dTraceLn8(J2D_TRACE_INFO, "tx1 = %f ty1 = %f tx2 = %f ty2 = %f dx1 = %f dy1 = %f dx2 = %f dy2 = %f", tx1, ty1, tx2, ty2, dx1, dy1, dx2, dy2);
+    MTLVC_ADD_TRIANGLES(tx1, ty1, tx2, ty2,
+                        dx1, dy1, dx2, dy2);
+}
+
 #endif /* !HEADLESS */