Path: blob/master/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLTextRenderer.m
41159 views
/*1* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <stdlib.h>26#include <limits.h>27#include <math.h>28#include <jlong.h>2930#include "sun_java2d_metal_MTLTextRenderer.h"3132#include "SurfaceData.h"33#include "MTLContext.h"34#include "MTLRenderQueue.h"35#include "MTLTextRenderer.h"36#include "MTLVertexCache.h"37#include "MTLGlyphCache.h"38#include "MTLBlitLoops.h"3940/**41* The following constants define the inner and outer bounds of the42* accelerated glyph cache.43*/44#define MTLTR_CACHE_WIDTH 51245#define MTLTR_CACHE_HEIGHT 51246#define MTLTR_CACHE_CELL_WIDTH 3247#define MTLTR_CACHE_CELL_HEIGHT 324849/**50* The current "glyph mode" state. This variable is used to track the51* codepath used to render a particular glyph. This variable is reset to52* MODE_NOT_INITED at the beginning of every call to MTLTR_DrawGlyphList().53* As each glyph is rendered, the glyphMode variable is updated to reflect54* the current mode, so if the current mode is the same as the mode used55* to render the previous glyph, we can avoid doing costly setup operations56* each time.57*/58typedef enum {59MODE_NOT_INITED,60MODE_USE_CACHE_GRAY,61MODE_USE_CACHE_LCD,62MODE_NO_CACHE_GRAY,63MODE_NO_CACHE_LCD,64MODE_NO_CACHE_COLOR65} GlyphMode;66static GlyphMode glyphMode = MODE_NOT_INITED;6768/**69* There are two separate glyph caches: for AA and for LCD.70* Once one of them is initialized as either GRAY or LCD, it71* stays in that mode for the duration of the application. It should72* be safe to use this one glyph cache for all screens in a multimon73* environment, since the glyph cache texture is shared between all contexts,74* and (in theory) Metal drivers should be smart enough to manage that75* texture across all screens.76*/7778static MTLGlyphCacheInfo *glyphCacheLCD = NULL;79static MTLGlyphCacheInfo *glyphCacheAA = NULL;8081/**82* This value tracks the previous LCD rgbOrder setting, so if the rgbOrder83* value has changed since the last time, it indicates that we need to84* invalidate the cache, which may already store glyph images in the reverse85* order. Note that in most real world applications this value will not86* change over the course of the application, but tests like Font2DTest87* allow for changing the ordering at runtime, so we need to handle that case.88*/89static jboolean lastRGBOrder = JNI_TRUE;9091/**92* This constant defines the size of the tile to use in the93* MTLTR_DrawLCDGlyphNoCache() method. See below for more on why we94* restrict this value to a particular size.95*/96#define MTLTR_NOCACHE_TILE_SIZE 329798static struct TxtVertex txtVertices[6];99static jint vertexCacheIndex = 0;100static id<MTLRenderCommandEncoder> lcdCacheEncoder = nil;101102#define LCD_ADD_VERTEX(TX, TY, DX, DY, DZ) \103do { \104struct TxtVertex *v = &txtVertices[vertexCacheIndex++]; \105v->txtpos[0] = TX; \106v->txtpos[1] = TY; \107v->position[0]= DX; \108v->position[1] = DY; \109} while (0)110111#define LCD_ADD_TRIANGLES(TX1, TY1, TX2, TY2, DX1, DY1, DX2, DY2) \112do { \113LCD_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \114LCD_ADD_VERTEX(TX2, TY1, DX2, DY1, 0); \115LCD_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \116LCD_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \117LCD_ADD_VERTEX(TX1, TY2, DX1, DY2, 0); \118LCD_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \119} while (0)120121/**122* Initializes the one glyph cache (texture and data structure).123* If lcdCache is JNI_TRUE, the texture will contain RGB data,124* otherwise we will simply store the grayscale/monochrome glyph images125* as intensity values.126*/127static jboolean128MTLTR_InitGlyphCache(MTLContext *mtlc, jboolean lcdCache)129{130J2dTraceLn(J2D_TRACE_INFO, "MTLTR_InitGlyphCache");131// TODO : Need to verify RGB order in case of LCD132MTLPixelFormat pixelFormat =133lcdCache ? MTLPixelFormatBGRA8Unorm : MTLPixelFormatA8Unorm;134135MTLGlyphCacheInfo *gcinfo;136// init glyph cache data structure137gcinfo = MTLGlyphCache_Init(MTLTR_CACHE_WIDTH,138MTLTR_CACHE_HEIGHT,139MTLTR_CACHE_CELL_WIDTH,140MTLTR_CACHE_CELL_HEIGHT,141MTLVertexCache_FlushGlyphVertexCache);142143if (gcinfo == NULL) {144J2dRlsTraceLn(J2D_TRACE_ERROR,145"MTLTR_InitGlyphCache: could not init MTL glyph cache");146return JNI_FALSE;147}148149MTLTextureDescriptor *textureDescriptor =150[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixelFormat151width:MTLTR_CACHE_WIDTH152height:MTLTR_CACHE_HEIGHT153mipmapped:NO];154155gcinfo->texture = [mtlc.device newTextureWithDescriptor:textureDescriptor];156157if (lcdCache) {158glyphCacheLCD = gcinfo;159} else {160glyphCacheAA = gcinfo;161}162163return JNI_TRUE;164}165166id<MTLTexture>167MTLTR_GetGlyphCacheTexture()168{169J2dTraceLn(J2D_TRACE_INFO, "MTLTR_GetGlyphCacheTexture");170if (glyphCacheAA != NULL) {171return glyphCacheAA->texture;172}173return NULL;174}175176/**177* Adds the given glyph to the glyph cache (texture and data structure)178* associated with the given MTLContext.179*/180static void181MTLTR_AddToGlyphCache(GlyphInfo *glyph, MTLContext *mtlc,182jboolean lcdCache)183{184MTLCacheCellInfo *ccinfo;185MTLGlyphCacheInfo *gcinfo;186jint w = glyph->width;187jint h = glyph->height;188189J2dTraceLn(J2D_TRACE_INFO, "MTLTR_AddToGlyphCache");190if (!lcdCache) {191gcinfo = glyphCacheAA;192} else {193gcinfo = glyphCacheLCD;194}195196if ((gcinfo == NULL) || (glyph->image == NULL)) {197return;198}199200bool isCacheFull = MTLGlyphCache_IsCacheFull(gcinfo, glyph);201if (isCacheFull) {202MTLGlyphCache_Free(gcinfo);203if (!lcdCache) {204MTLTR_InitGlyphCache(mtlc, JNI_FALSE);205gcinfo = glyphCacheAA;206} else {207MTLTR_InitGlyphCache(mtlc, JNI_TRUE);208gcinfo = glyphCacheLCD;209}210}211MTLGlyphCache_AddGlyph(gcinfo, glyph);212ccinfo = (MTLCacheCellInfo *) glyph->cellInfo;213214if (ccinfo != NULL) {215// store glyph image in texture cell216MTLRegion region = {217{ccinfo->x, ccinfo->y, 0},218{w, h, 1}219};220if (!lcdCache) {221NSUInteger bytesPerRow = 1 * w;222[gcinfo->texture replaceRegion:region223mipmapLevel:0224withBytes:glyph->image225bytesPerRow:bytesPerRow];226} else {227unsigned int imageBytes = w * h * 4;228unsigned char imageData[imageBytes];229memset(&imageData, 0, sizeof(imageData));230231int srcIndex = 0;232int dstIndex = 0;233for (int i = 0; i < (w * h); i++) {234imageData[dstIndex++] = glyph->image[srcIndex++];235imageData[dstIndex++] = glyph->image[srcIndex++];236imageData[dstIndex++] = glyph->image[srcIndex++];237imageData[dstIndex++] = 0xFF;238}239240NSUInteger bytesPerRow = 4 * w;241[gcinfo->texture replaceRegion:region242mipmapLevel:0243withBytes:imageData244bytesPerRow:bytesPerRow];245}246}247}248249static jboolean250MTLTR_SetLCDContrast(MTLContext *mtlc,251jint contrast,252id<MTLRenderCommandEncoder> encoder)253{254if (![mtlc.paint isKindOfClass:[MTLColorPaint class]]) {255return JNI_FALSE;256}257MTLColorPaint* cPaint = (MTLColorPaint *) mtlc.paint;258// update the current color settings259double gamma = ((double)contrast) / 100.0;260double invgamma = 1.0/gamma;261jfloat radj, gadj, badj;262jfloat clr[4];263jint col = cPaint.color;264265J2dTraceLn2(J2D_TRACE_INFO, "primary color %x, contrast %d", col, contrast);266J2dTraceLn2(J2D_TRACE_INFO, "gamma %f, invgamma %f", gamma, invgamma);267268clr[0] = ((col >> 16) & 0xFF)/255.0f;269clr[1] = ((col >> 8) & 0xFF)/255.0f;270clr[2] = ((col) & 0xFF)/255.0f;271272// gamma adjust the primary color273radj = (float)pow(clr[0], gamma);274gadj = (float)pow(clr[1], gamma);275badj = (float)pow(clr[2], gamma);276277struct LCDFrameUniforms uf = {278{radj, gadj, badj},279{gamma, gamma, gamma},280{invgamma, invgamma, invgamma}};281[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];282return JNI_TRUE;283}284285void286MTLTR_EnableGlyphVertexCache(MTLContext *mtlc, BMTLSDOps *dstOps)287{288J2dTraceLn(J2D_TRACE_INFO, "MTLTR_EnableGlyphVertexCache");289290if (!MTLVertexCache_InitVertexCache()) {291return;292}293294if (glyphCacheAA == NULL) {295if (!MTLTR_InitGlyphCache(mtlc, JNI_FALSE)) {296return;297}298}299MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps);300}301302void303MTLTR_DisableGlyphVertexCache(MTLContext *mtlc)304{305J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DisableGlyphVertexCache");306MTLVertexCache_FlushGlyphVertexCache();307MTLVertexCache_FreeVertexCache();308}309310void MTLTR_FreeGlyphCaches() {311J2dTraceLn(J2D_TRACE_INFO, "MTLTR_FreeGlyphCaches : freeing glyph caches.");312313if (glyphCacheAA != NULL) {314[glyphCacheAA->texture release];315MTLGlyphCache_Free(glyphCacheAA);316glyphCacheAA = NULL;317}318319if (glyphCacheLCD != NULL) {320[glyphCacheLCD->texture release];321MTLGlyphCache_Free(glyphCacheLCD);322glyphCacheLCD = NULL;323}324}325326static MTLPaint* storedPaint = nil;327328static void EnableColorGlyphPainting(MTLContext *mtlc) {329storedPaint = mtlc.paint;330mtlc.paint = [[MTLPaint alloc] init];331}332333static void DisableColorGlyphPainting(MTLContext *mtlc) {334[mtlc.paint release];335mtlc.paint = storedPaint;336storedPaint = nil;337}338339static jboolean340MTLTR_DrawGrayscaleGlyphViaCache(MTLContext *mtlc,341GlyphInfo *ginfo, jint x, jint y, BMTLSDOps *dstOps)342{343MTLCacheCellInfo *cell;344jfloat x1, y1, x2, y2;345346if (glyphMode != MODE_USE_CACHE_GRAY) {347if (glyphMode == MODE_NO_CACHE_GRAY) {348MTLVertexCache_DisableMaskCache(mtlc);349} else if (glyphMode == MODE_USE_CACHE_LCD) {350[mtlc.encoderManager endEncoder];351lcdCacheEncoder = nil;352} else if (glyphMode == MODE_NO_CACHE_COLOR) {353DisableColorGlyphPainting(mtlc);354}355MTLTR_EnableGlyphVertexCache(mtlc, dstOps);356glyphMode = MODE_USE_CACHE_GRAY;357}358359if (ginfo->cellInfo == NULL) {360// attempt to add glyph to accelerated glyph cache361MTLTR_AddToGlyphCache(ginfo, mtlc, JNI_FALSE);362363if (ginfo->cellInfo == NULL) {364// we'll just no-op in the rare case that the cell is NULL365return JNI_TRUE;366}367}368369cell = (MTLCacheCellInfo *) (ginfo->cellInfo);370cell->timesRendered++;371372x1 = (jfloat)x;373y1 = (jfloat)y;374x2 = x1 + ginfo->width;375y2 = y1 + ginfo->height;376377MTLVertexCache_AddGlyphQuad(mtlc,378cell->tx1, cell->ty1,379cell->tx2, cell->ty2,380x1, y1, x2, y2);381382return JNI_TRUE;383}384385static jboolean386MTLTR_DrawLCDGlyphViaCache(MTLContext *mtlc, BMTLSDOps *dstOps,387GlyphInfo *ginfo, jint x, jint y,388jboolean rgbOrder, jint contrast)389{390CacheCellInfo *cell;391jfloat tx1, ty1, tx2, ty2;392jint w = ginfo->width;393jint h = ginfo->height;394395if (glyphMode != MODE_USE_CACHE_LCD) {396if (glyphMode == MODE_NO_CACHE_GRAY) {397MTLVertexCache_DisableMaskCache(mtlc);398} else if (glyphMode == MODE_USE_CACHE_GRAY) {399MTLTR_DisableGlyphVertexCache(mtlc);400} else if (glyphMode == MODE_NO_CACHE_COLOR) {401DisableColorGlyphPainting(mtlc);402}403404if (glyphCacheLCD == NULL) {405if (!MTLTR_InitGlyphCache(mtlc, JNI_TRUE)) {406return JNI_FALSE;407}408}409if (lcdCacheEncoder == nil) {410lcdCacheEncoder = [mtlc.encoderManager getLCDEncoder:dstOps->pTexture isSrcOpaque:YES isDstOpaque:YES];411}412if (rgbOrder != lastRGBOrder) {413// need to invalidate the cache in this case; see comments414// for lastRGBOrder above415MTLGlyphCache_Invalidate(glyphCacheLCD);416lastRGBOrder = rgbOrder;417}418419glyphMode = MODE_USE_CACHE_LCD;420}421422if (ginfo->cellInfo == NULL) {423// attempt to add glyph to accelerated glyph cache424// TODO : Handle RGB order425MTLTR_AddToGlyphCache(ginfo, mtlc, JNI_TRUE);426427if (ginfo->cellInfo == NULL) {428// we'll just no-op in the rare case that the cell is NULL429return JNI_TRUE;430}431}432cell = (CacheCellInfo *) (ginfo->cellInfo);433cell->timesRendered++;434435MTLTR_SetLCDContrast(mtlc, contrast, lcdCacheEncoder);436tx1 = cell->tx1;437ty1 = cell->ty1;438tx2 = cell->tx2;439ty2 = cell->ty2;440441J2dTraceLn4(J2D_TRACE_INFO, "tx1 = %f, ty1 = %f, tx2 = %f, ty2 = %f", tx1, ty1, tx2, ty2);442J2dTraceLn2(J2D_TRACE_INFO, "width = %d height = %d", dstOps->width, dstOps->height);443444LCD_ADD_TRIANGLES(tx1, ty1, tx2, ty2, x, y, x+w, y+h);445446[lcdCacheEncoder setVertexBytes:txtVertices length:sizeof(txtVertices) atIndex:MeshVertexBuffer];447[lcdCacheEncoder setFragmentTexture:glyphCacheLCD->texture atIndex:0];448[lcdCacheEncoder setFragmentTexture:dstOps->pTexture atIndex:1];449450[lcdCacheEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];451452vertexCacheIndex = 0;453454return JNI_TRUE;455}456457static jboolean458MTLTR_DrawGrayscaleGlyphNoCache(MTLContext *mtlc,459GlyphInfo *ginfo, jint x, jint y, BMTLSDOps *dstOps)460{461jint tw, th;462jint sx, sy, sw, sh;463jint x0;464jint w = ginfo->width;465jint h = ginfo->height;466467J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGrayscaleGlyphNoCache");468if (glyphMode != MODE_NO_CACHE_GRAY) {469if (glyphMode == MODE_USE_CACHE_GRAY) {470MTLTR_DisableGlyphVertexCache(mtlc);471} else if (glyphMode == MODE_USE_CACHE_LCD) {472[mtlc.encoderManager endEncoder];473lcdCacheEncoder = nil;474} else if (glyphMode == MODE_NO_CACHE_COLOR) {475DisableColorGlyphPainting(mtlc);476}477MTLVertexCache_EnableMaskCache(mtlc, dstOps);478glyphMode = MODE_NO_CACHE_GRAY;479}480481x0 = x;482tw = MTLVC_MASK_CACHE_TILE_WIDTH;483th = MTLVC_MASK_CACHE_TILE_HEIGHT;484485for (sy = 0; sy < h; sy += th, y += th) {486x = x0;487sh = ((sy + th) > h) ? (h - sy) : th;488489for (sx = 0; sx < w; sx += tw, x += tw) {490sw = ((sx + tw) > w) ? (w - sx) : tw;491492J2dTraceLn7(J2D_TRACE_INFO, "sx = %d sy = %d x = %d y = %d sw = %d sh = %d w = %d", sx, sy, x, y, sw, sh, w);493MTLVertexCache_AddMaskQuad(mtlc,494sx, sy, x, y, sw, sh,495w, ginfo->image,496dstOps);497}498}499500return JNI_TRUE;501}502503504static jboolean505MTLTR_DrawLCDGlyphNoCache(MTLContext *mtlc, BMTLSDOps *dstOps,506GlyphInfo *ginfo, jint x, jint y,507jint rowBytesOffset,508jboolean rgbOrder, jint contrast)509{510jfloat tx1, ty1, tx2, ty2;511jint tw, th;512jint w = ginfo->width;513jint h = ginfo->height;514id<MTLTexture> blitTexture = nil;515516J2dTraceLn2(J2D_TRACE_INFO, "MTLTR_DrawLCDGlyphNoCache x %d, y%d", x, y);517J2dTraceLn3(J2D_TRACE_INFO, "MTLTR_DrawLCDGlyphNoCache rowBytesOffset=%d, rgbOrder=%d, contrast=%d", rowBytesOffset, rgbOrder, contrast);518519520id<MTLRenderCommandEncoder> encoder = nil;521522MTLTextureDescriptor *textureDescriptor =523[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm524width:w525height:h526mipmapped:NO];527528blitTexture = [mtlc.device newTextureWithDescriptor:textureDescriptor];529530if (glyphMode != MODE_NO_CACHE_LCD) {531if (glyphMode == MODE_NO_CACHE_GRAY) {532MTLVertexCache_DisableMaskCache(mtlc);533} else if (glyphMode == MODE_USE_CACHE_GRAY) {534MTLTR_DisableGlyphVertexCache(mtlc);535} else if (glyphMode == MODE_USE_CACHE_LCD) {536[mtlc.encoderManager endEncoder];537lcdCacheEncoder = nil;538} else if (glyphMode == MODE_NO_CACHE_COLOR) {539DisableColorGlyphPainting(mtlc);540}541542if (blitTexture == nil) {543J2dTraceLn(J2D_TRACE_ERROR, "can't obtain temporary texture object from pool");544return JNI_FALSE;545}546547548glyphMode = MODE_NO_CACHE_LCD;549}550encoder = [mtlc.encoderManager getLCDEncoder:dstOps->pTexture isSrcOpaque:YES isDstOpaque:YES];551MTLTR_SetLCDContrast(mtlc, contrast, encoder);552553unsigned int imageBytes = w * h * 4;554unsigned char imageData[imageBytes];555memset(&imageData, 0, sizeof(imageData));556557int srcIndex = 0;558int dstIndex = 0;559for (int i = 0; i < (w * h); i++) {560imageData[dstIndex++] = ginfo->image[srcIndex++ + rowBytesOffset];561imageData[dstIndex++] = ginfo->image[srcIndex++ + rowBytesOffset];562imageData[dstIndex++] = ginfo->image[srcIndex++ + rowBytesOffset];563imageData[dstIndex++] = 0xFF;564}565566// copy LCD mask into glyph texture tile567MTLRegion region = MTLRegionMake2D(0, 0, w, h);568569NSUInteger bytesPerRow = 4 * ginfo->width;570[blitTexture replaceRegion:region571mipmapLevel:0572withBytes:imageData573bytesPerRow:bytesPerRow];574575tx1 = 0.0f;576ty1 = 0.0f;577tx2 = 1.0f;578ty2 = 1.0f;579580J2dTraceLn2(J2D_TRACE_INFO, "MTLTR_DrawLCDGlyphNoCache : dstOps->width = %d, dstOps->height = %d", dstOps->width, dstOps->height);581582LCD_ADD_TRIANGLES(tx1, ty1, tx2, ty2, x, y, x+w, y+h);583584[encoder setVertexBytes:txtVertices length:sizeof(txtVertices) atIndex:MeshVertexBuffer];585[encoder setFragmentTexture:blitTexture atIndex:0];586[encoder setFragmentTexture:dstOps->pTexture atIndex:1];587588[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];589590vertexCacheIndex = 0;591[mtlc.encoderManager endEncoder];592[blitTexture release];593594MTLCommandBufferWrapper* cbwrapper = [mtlc pullCommandBufferWrapper];595596id<MTLCommandBuffer> commandbuf = [cbwrapper getCommandBuffer];597[commandbuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {598[cbwrapper release];599}];600601[commandbuf commit];602[commandbuf waitUntilCompleted];603604return JNI_TRUE;605}606607static jboolean608MTLTR_DrawColorGlyphNoCache(MTLContext *mtlc,609GlyphInfo *ginfo, jint x, jint y, BMTLSDOps *dstOps)610{611id<MTLTexture> dest = dstOps->pTexture;612const void *src = ginfo->image;613jint w = ginfo->width;614jint h = ginfo->height;615jint rowBytes = ginfo->rowBytes;616unsigned int imageSize = rowBytes * h;617618J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawColorGlyphNoCache");619620if (glyphMode != MODE_NO_CACHE_COLOR) {621if (glyphMode == MODE_NO_CACHE_GRAY) {622MTLVertexCache_DisableMaskCache(mtlc);623} else if (glyphMode == MODE_USE_CACHE_GRAY) {624MTLTR_DisableGlyphVertexCache(mtlc);625} else if (glyphMode == MODE_USE_CACHE_LCD) {626[mtlc.encoderManager endEncoder];627lcdCacheEncoder = nil;628}629glyphMode = MODE_NO_CACHE_COLOR;630EnableColorGlyphPainting(mtlc);631}632633MTLPooledTextureHandle* texHandle = [mtlc.texturePool getTexture:w height:h format:MTLPixelFormatBGRA8Unorm];634if (texHandle == nil) {635J2dTraceLn(J2D_TRACE_ERROR, "MTLTR_DrawColorGlyphNoCache: can't obtain temporary texture object from pool");636return JNI_FALSE;637}638639[[mtlc getCommandBufferWrapper] registerPooledTexture:texHandle];640641[texHandle.texture replaceRegion:MTLRegionMake2D(0, 0, w, h)642mipmapLevel:0643withBytes:src644bytesPerRow:rowBytes];645646drawTex2Tex(mtlc, texHandle.texture, dest, JNI_FALSE, dstOps->isOpaque, INTERPOLATION_NEAREST_NEIGHBOR,6470, 0, w, h, x, y, x + w, y + h);648649return JNI_TRUE;650}651652// see DrawGlyphList.c for more on this macro...653#define FLOOR_ASSIGN(l, r) \654if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))655656void657MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, BMTLSDOps *dstOps,658jint totalGlyphs, jboolean usePositions,659jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,660jfloat glyphListOrigX, jfloat glyphListOrigY,661unsigned char *images, unsigned char *positions)662{663int glyphCounter;664665J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList");666667RETURN_IF_NULL(mtlc);668RETURN_IF_NULL(dstOps);669RETURN_IF_NULL(images);670if (usePositions) {671RETURN_IF_NULL(positions);672}673674glyphMode = MODE_NOT_INITED;675J2dTraceLn1(J2D_TRACE_INFO, "totalGlyphs = %d", totalGlyphs);676jboolean flushBeforeLCD = JNI_FALSE;677678for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {679J2dTraceLn(J2D_TRACE_INFO, "Entered for loop for glyph list");680jint x, y;681jfloat glyphx, glyphy;682jboolean ok;683GlyphInfo *ginfo = (GlyphInfo *)jlong_to_ptr(NEXT_LONG(images));684685if (ginfo == NULL) {686// this shouldn't happen, but if it does we'll just break out...687J2dRlsTraceLn(J2D_TRACE_ERROR,688"MTLTR_DrawGlyphList: glyph info is null");689break;690}691692if (usePositions) {693jfloat posx = NEXT_FLOAT(positions);694jfloat posy = NEXT_FLOAT(positions);695glyphx = glyphListOrigX + posx + ginfo->topLeftX;696glyphy = glyphListOrigY + posy + ginfo->topLeftY;697FLOOR_ASSIGN(x, glyphx);698FLOOR_ASSIGN(y, glyphy);699} else {700glyphx = glyphListOrigX + ginfo->topLeftX;701glyphy = glyphListOrigY + ginfo->topLeftY;702FLOOR_ASSIGN(x, glyphx);703FLOOR_ASSIGN(y, glyphy);704glyphListOrigX += ginfo->advanceX;705glyphListOrigY += ginfo->advanceY;706}707708if (ginfo->image == NULL) {709J2dTraceLn(J2D_TRACE_INFO, "Glyph image is null");710continue;711}712713J2dTraceLn2(J2D_TRACE_INFO, "Glyph width = %d height = %d", ginfo->width, ginfo->height);714J2dTraceLn1(J2D_TRACE_INFO, "rowBytes = %d", ginfo->rowBytes);715if (ginfo->rowBytes == ginfo->width) {716// grayscale or monochrome glyph data717if (ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&718ginfo->height <= MTLTR_CACHE_CELL_HEIGHT)719{720J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList Grayscale cache");721ok = MTLTR_DrawGrayscaleGlyphViaCache(mtlc, ginfo, x, y, dstOps);722} else {723J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList Grayscale no cache");724ok = MTLTR_DrawGrayscaleGlyphNoCache(mtlc, ginfo, x, y, dstOps);725}726} else if (ginfo->rowBytes == ginfo->width * 4) {727J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList color glyph no cache");728ok = MTLTR_DrawColorGlyphNoCache(mtlc, ginfo, x, y, dstOps);729flushBeforeLCD = JNI_FALSE;730} else {731if (!flushBeforeLCD) {732[mtlc.encoderManager endEncoder];733MTLCommandBufferWrapper* cbwrapper = [mtlc pullCommandBufferWrapper];734735id<MTLCommandBuffer> commandbuf = [cbwrapper getCommandBuffer];736[commandbuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {737[cbwrapper release];738}];739740[commandbuf commit];741flushBeforeLCD = JNI_TRUE;742}743744// LCD-optimized glyph data745jint rowBytesOffset = 0;746747if (subPixPos) {748jint frac = (jint)((glyphx - x) * 3);749if (frac != 0) {750rowBytesOffset = 3 - frac;751x += 1;752}753}754755if (rowBytesOffset == 0 &&756ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&757ginfo->height <= MTLTR_CACHE_CELL_HEIGHT)758{759J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList LCD cache");760ok = MTLTR_DrawLCDGlyphViaCache(mtlc, dstOps,761ginfo, x, y,762rgbOrder, lcdContrast);763} else {764J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList LCD no cache");765ok = MTLTR_DrawLCDGlyphNoCache(mtlc, dstOps,766ginfo, x, y,767rowBytesOffset,768rgbOrder, lcdContrast);769}770}771772if (!ok) {773break;774}775}776/*777* Only in case of grayscale text drawing we need to flush778* cache. Still in case of LCD we are not using any intermediate779* cache.780*/781if (glyphMode == MODE_NO_CACHE_GRAY) {782MTLVertexCache_DisableMaskCache(mtlc);783} else if (glyphMode == MODE_USE_CACHE_GRAY) {784MTLTR_DisableGlyphVertexCache(mtlc);785} else if (glyphMode == MODE_USE_CACHE_LCD) {786[mtlc.encoderManager endEncoder];787lcdCacheEncoder = nil;788} else if (glyphMode == MODE_NO_CACHE_COLOR) {789DisableColorGlyphPainting(mtlc);790}791}792793JNIEXPORT void JNICALL794Java_sun_java2d_metal_MTLTextRenderer_drawGlyphList795(JNIEnv *env, jobject self,796jint numGlyphs, jboolean usePositions,797jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,798jfloat glyphListOrigX, jfloat glyphListOrigY,799jlongArray imgArray, jfloatArray posArray)800{801unsigned char *images;802803J2dTraceLn(J2D_TRACE_INFO, "MTLTextRenderer_drawGlyphList");804805images = (unsigned char *)806(*env)->GetPrimitiveArrayCritical(env, imgArray, NULL);807if (images != NULL) {808MTLContext *mtlc = MTLRenderQueue_GetCurrentContext();809BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();810811if (usePositions) {812unsigned char *positions = (unsigned char *)813(*env)->GetPrimitiveArrayCritical(env, posArray, NULL);814if (positions != NULL) {815MTLTR_DrawGlyphList(env, mtlc, dstOps,816numGlyphs, usePositions,817subPixPos, rgbOrder, lcdContrast,818glyphListOrigX, glyphListOrigY,819images, positions);820(*env)->ReleasePrimitiveArrayCritical(env, posArray,821positions, JNI_ABORT);822}823} else {824MTLTR_DrawGlyphList(env, mtlc, dstOps,825numGlyphs, usePositions,826subPixPos, rgbOrder, lcdContrast,827glyphListOrigX, glyphListOrigY,828images, NULL);829}830if (mtlc != NULL) {831RESET_PREVIOUS_OP();832[mtlc.encoderManager endEncoder];833MTLCommandBufferWrapper * cbwrapper = [mtlc pullCommandBufferWrapper];834id<MTLCommandBuffer> commandbuf = [cbwrapper getCommandBuffer];835[commandbuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {836[cbwrapper release];837}];838[commandbuf commit];839}840841(*env)->ReleasePrimitiveArrayCritical(env, imgArray,842images, JNI_ABORT);843}844}845846847