# HG changeset patch # User jdv # Date 1562672120 -19800 # Node ID db2be8544d10f734deca72bdec4ad10796333bcd # Parent 3a7c29ba6b1c3ba7dbd68f6843e44d960d16f42f Initial implementation of mask cache for Text rendering diff -r 3a7c29ba6b1c -r db2be8544d10 src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLTextRenderer.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, diff -r 3a7c29ba6b1c -r db2be8544d10 src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.h --- 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 */ diff -r 3a7c29ba6b1c -r db2be8544d10 src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.m --- 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 maskCacheTex = NULL; static jint maskCacheIndex = 0; -id encoder; -id texturePool[MTLVC_MAX_TEX_INDEX]; -static jint texturePoolIndex = 0; +id 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) { idvertexBuffer = [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 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 */