JBR-4883 macOS: SIGSEGV at MTLVertexCache_FlushGlyphVertexCache

Use separate glyph cache for each MTLContext instance. Refactored MTLGlyphCache
This commit is contained in:
Alexey Ushakov
2023-03-02 13:23:19 +01:00
committed by jbrbot
parent 4d909bae68
commit 0c97d2f11d
9 changed files with 171 additions and 286 deletions

View File

@@ -39,6 +39,7 @@
#include "MTLClip.h"
#include "EncoderManager.h"
#include "MTLSamplerManager.h"
#import "MTLGlyphCache.h"
@class MTLStencilManager;
@class MTLLayer;
@@ -68,6 +69,16 @@
@property (readonly) MTLTransform * transform;
@property (readonly) MTLClip * clip;
/**
* There are two separate glyph caches: for AA and for LCD.
* Once one of them is initialized as either GRAY or LCD, it
* stays in that mode for the duration of the MTLContext (it is not safe
* to use this one glyph cache for all screens in a multi-monitor
* environment)
*/
@property (readonly) MTLGlyphCache *glyphCacheLCD;
@property (readonly) MTLGlyphCache *glyphCacheAA;
@property jint textureFunction;
@property jboolean vertexCacheEnabled;
@property jboolean aaEnabled;

View File

@@ -181,6 +181,8 @@ extern void initSamplers(id<MTLDevice> device);
CVDisplayLinkCreateWithCGDisplay(displayID, &_displayLink);
CVDisplayLinkSetOutputCallback(_displayLink, &mtlDisplayLinkCallback, (__bridge void *) self);
}
_glyphCacheLCD = [[MTLGlyphCache alloc] initWithContext:self];
_glyphCacheAA = [[MTLGlyphCache alloc] initWithContext:self];
}
return self;
}
@@ -191,6 +193,9 @@ extern void initSamplers(id<MTLDevice> device);
// TODO : Check that texturePool is completely released.
// texturePool content is released in MTLCommandBufferWrapper.onComplete()
//self.texturePool = nil;
[_glyphCacheLCD release];
[_glyphCacheAA release];
self.vertexBuffer = nil;
self.commandQueue = nil;
self.pipelineStateStorage = nil;

View File

@@ -35,12 +35,13 @@ extern "C" {
#import <Metal/Metal.h>
@class MTLContext;
typedef void (MTLFlushFunc)();
typedef void (MTLFlushFunc)(MTLContext* mtlc);
typedef struct _MTLCacheCellInfo MTLCacheCellInfo;
typedef struct {
MTLContext* mtlc;
id<MTLRenderCommandEncoder> encoder;
MTLCacheCellInfo *head;
MTLCacheCellInfo *tail;
id<MTLTexture> texture;
@@ -72,26 +73,29 @@ struct _MTLCacheCellInfo {
jfloat ty2;
};
MTLGlyphCacheInfo *
MTLGlyphCache_Init(MTLContext* mtlc, jint width, jint height,
jint cellWidth, jint cellHeight, MTLFlushFunc *func);
MTLCacheCellInfo *
MTLGlyphCache_AddGlyph(MTLGlyphCacheInfo *cache, struct GlyphInfo *glyph);
bool
MTLGlyphCache_IsCacheFull(MTLGlyphCacheInfo *cache, GlyphInfo *glyph);
void
MTLGlyphCache_Invalidate(MTLGlyphCacheInfo *cache);
void
MTLGlyphCache_AddCellInfo(struct GlyphInfo *glyph, MTLCacheCellInfo *cellInfo);
void
MTLGlyphCache_RemoveCellInfo(struct GlyphInfo *glyph, MTLCacheCellInfo *cellInfo);
MTLCacheCellInfo *
MTLGlyphCache_GetCellInfoForCache(struct GlyphInfo *glyph,
MTLGlyphCacheInfo *cache);
JNIEXPORT void
MTLGlyphCache_RemoveAllCellInfos(struct GlyphInfo *glyph);
void
MTLGlyphCache_Free(MTLGlyphCacheInfo *cache);
@interface MTLGlyphCache : NSObject
- (id)initWithContext:(MTLContext*)ctx;
- (void) dealloc;
- (BOOL) glyphCacheInitWidth:(jint)width
height:(jint)height
cellWidth:(jint)cellWidth
cellHeight:(jint)cellHeight
pixelFormat:(NSUInteger)pixelFormat
func:(MTLFlushFunc*)func;
- (MTLCacheCellInfo*) addGlyph:(GlyphInfo*)glyph;
- (BOOL) isCacheFull:(GlyphInfo*)glyph;
- (void) invalidate;
- (void) free;
@property (readwrite) MTLGlyphCacheInfo *cacheInfo;
@end
#ifdef __cplusplus
}

View File

@@ -36,6 +36,19 @@
*/
#define TIMES_RENDERED_THRESHOLD 5
@implementation MTLGlyphCache {
MTLContext* _ctx;
}
- (id) initWithContext:(MTLContext*) ctx {
self = [super init];
if (self) {
_ctx = ctx;
_cacheInfo = NULL;
}
return self;
}
/**
* Creates a new GlyphCacheInfo structure, fills in the initial values, and
* then returns a pointer to the GlyphCacheInfo record.
@@ -60,32 +73,40 @@
* for retrieving cell info for the glyph, but instead just use the struct's
* field directly.
*/
MTLGlyphCacheInfo *
MTLGlyphCache_Init(MTLContext* mtlc, jint width, jint height,
jint cellWidth, jint cellHeight,
MTLFlushFunc *func)
- (BOOL) glyphCacheInitWidth:(jint)width
height:(jint)height
cellWidth:(jint)cellWidth
cellHeight:(jint)cellHeight
pixelFormat:(NSUInteger)pixelFormat
func:(MTLFlushFunc *)func
{
MTLGlyphCacheInfo *gcinfo;
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache.glyphCacheInitWidth");
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Init");
gcinfo = (MTLGlyphCacheInfo *)malloc(sizeof(MTLGlyphCacheInfo));
if (gcinfo == NULL) {
_cacheInfo = (MTLGlyphCacheInfo *)malloc(sizeof(MTLGlyphCacheInfo));
if (_cacheInfo == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR,
"MTLGlyphCache_Init: could not allocate MTLGlyphCacheInfo");
return NULL;
"MTLGlyphCache.glyphCacheInitWidth: could not allocate MTLGlyphCacheInfo");
return NO;
}
gcinfo->head = NULL;
gcinfo->tail = NULL;
gcinfo->width = width;
gcinfo->height = height;
gcinfo->cellWidth = cellWidth;
gcinfo->cellHeight = cellHeight;
gcinfo->Flush = func;
gcinfo->mtlc = mtlc;
_cacheInfo->head = NULL;
_cacheInfo->tail = NULL;
_cacheInfo->width = width;
_cacheInfo->height = height;
_cacheInfo->cellWidth = cellWidth;
_cacheInfo->cellHeight = cellHeight;
_cacheInfo->Flush = func;
_cacheInfo->mtlc = _ctx;
_cacheInfo->encoder = nil;
MTLTextureDescriptor *textureDescriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixelFormat
width:width
height:height
mipmapped:NO];
_cacheInfo->texture = [_ctx.device newTextureWithDescriptor:textureDescriptor];
return gcinfo;
return YES;
}
/**
@@ -104,32 +125,31 @@ MTLGlyphCache_Init(MTLContext* mtlc, jint width, jint height,
* Returns created cell info if it was successfully created and added to the
* cache and glyph's cell lists, NULL otherwise.
*/
MTLCacheCellInfo *
MTLGlyphCache_AddGlyph(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)
- (MTLCacheCellInfo*) addGlyph:(GlyphInfo*) glyph
{
MTLCacheCellInfo *cellinfo = NULL;
jint w = glyph->width;
jint h = glyph->height;
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_AddGlyph");
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache.addGlyph");
if ((glyph->width > cache->cellWidth) ||
(glyph->height > cache->cellHeight))
if ((glyph->width > _cacheInfo->cellWidth) ||
(glyph->height > _cacheInfo->cellHeight))
{
return NULL;
}
jint x, y;
if (cache->head == NULL) {
if (_cacheInfo->head == NULL) {
x = 0;
y = 0;
} else {
x = cache->tail->x + cache->cellWidth;
y = cache->tail->y;
if ((x + cache->cellWidth) > cache->width) {
x = _cacheInfo->tail->x + _cacheInfo->cellWidth;
y = _cacheInfo->tail->y;
if ((x + _cacheInfo->cellWidth) > _cacheInfo->width) {
x = 0;
y += cache->cellHeight;
y += _cacheInfo->cellHeight;
}
}
@@ -140,28 +160,28 @@ MTLGlyphCache_AddGlyph(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)
return NULL;
}
cellinfo->cacheInfo = cache;
cellinfo->cacheInfo = _cacheInfo;
cellinfo->glyphInfo = glyph;
cellinfo->timesRendered = 0;
cellinfo->x = x;
cellinfo->y = y;
cellinfo->leftOff = 0;
cellinfo->rightOff = 0;
cellinfo->tx1 = (jfloat)cellinfo->x / cache->width;
cellinfo->ty1 = (jfloat)cellinfo->y / cache->height;
cellinfo->tx2 = cellinfo->tx1 + ((jfloat)w / cache->width);
cellinfo->ty2 = cellinfo->ty1 + ((jfloat)h / cache->height);
cellinfo->tx1 = (jfloat)cellinfo->x / _cacheInfo->width;
cellinfo->ty1 = (jfloat)cellinfo->y / _cacheInfo->height;
cellinfo->tx2 = cellinfo->tx1 + ((jfloat)w / _cacheInfo->width);
cellinfo->ty2 = cellinfo->ty1 + ((jfloat)h / _cacheInfo->height);
if (cache->head == NULL) {
if (_cacheInfo->head == NULL) {
// initialize the head cell
cache->head = cellinfo;
_cacheInfo->head = cellinfo;
} else {
// update existing tail cell
cache->tail->next = cellinfo;
_cacheInfo->tail->next = cellinfo;
}
// add the new cell to the end of the list
cache->tail = cellinfo;
_cacheInfo->tail = cellinfo;
cellinfo->next = NULL;
cellinfo->nextGCI = NULL;
@@ -170,26 +190,24 @@ MTLGlyphCache_AddGlyph(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)
return cellinfo;
}
bool
MTLGlyphCache_IsCacheFull(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)
- (BOOL) isCacheFull:(GlyphInfo*) glyph
{
jint w = glyph->width;
jint h = glyph->height;
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_IsCacheFull");
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache.isCacheFull");
jint x, y;
if (cache->head == NULL) {
if (_cacheInfo->head == NULL) {
return JNI_FALSE;
} else {
x = cache->tail->x + cache->cellWidth;
y = cache->tail->y;
if ((x + cache->cellWidth) > cache->width) {
x = _cacheInfo->tail->x + _cacheInfo->cellWidth;
y = _cacheInfo->tail->y;
if ((x + _cacheInfo->cellWidth) > _cacheInfo->width) {
x = 0;
y += cache->cellHeight;
if ((y + cache->cellHeight) > cache->height) {
y += _cacheInfo->cellHeight;
if ((y + _cacheInfo->cellHeight) > _cacheInfo->height) {
return JNI_TRUE;
}
}
@@ -201,24 +219,23 @@ MTLGlyphCache_IsCacheFull(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)
* attempt to compact the cache in any way; it just invalidates any cells
* that already exist.
*/
void
MTLGlyphCache_Invalidate(MTLGlyphCacheInfo *cache)
- (void) invalidate
{
MTLCacheCellInfo *cellinfo;
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Invalidate");
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache.invalidate");
if (cache == NULL) {
if (_cacheInfo == NULL) {
return;
}
// flush any pending vertices that may be depending on the current
// glyph cache layout
if (cache->Flush != NULL) {
cache->Flush();
if (_cacheInfo->Flush != NULL) {
_cacheInfo->Flush(_cacheInfo->mtlc);
}
cellinfo = cache->head;
cellinfo = _cacheInfo->head;
while (cellinfo != NULL) {
if (cellinfo->glyphInfo != NULL) {
// if the cell is occupied, notify the base glyph that its
@@ -233,36 +250,40 @@ MTLGlyphCache_Invalidate(MTLGlyphCacheInfo *cache)
* Invalidates and frees all cells and the cache itself. The "cache" pointer
* becomes invalid after this function returns.
*/
void
MTLGlyphCache_Free(MTLGlyphCacheInfo *cache)
- (void) free
{
MTLCacheCellInfo *cellinfo;
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Free");
if (cache == NULL) {
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache.free");
if (_cacheInfo == NULL) {
return;
}
// flush any pending vertices that may be depending on the current
// glyph cache
if (cache->Flush != NULL) {
cache->Flush();
if (_cacheInfo->Flush != NULL) {
_cacheInfo->Flush(_cacheInfo->mtlc);
}
[_cacheInfo->texture release];
while (cache->head != NULL) {
cellinfo = cache->head;
while (_cacheInfo->head != NULL) {
MTLCacheCellInfo *cellinfo = _cacheInfo->head;
if (cellinfo->glyphInfo != NULL) {
// if the cell is occupied, notify the base glyph that its
// cached version for this cache is about to be invalidated
MTLGlyphCache_RemoveCellInfo(cellinfo->glyphInfo, cellinfo);
}
cache->head = cellinfo->next;
_cacheInfo->head = cellinfo->next;
free(cellinfo);
}
free(cache);
free(_cacheInfo);
_cacheInfo = NULL;
}
- (void) dealloc {
[self free];
[super dealloc];
}
@end
/**
* Add cell info to the head of the glyph's list of cached cells.
*/
@@ -310,57 +331,4 @@ MTLGlyphCache_RemoveCellInfo(GlyphInfo *glyph, MTLCacheCellInfo *cellInfo)
J2dTraceLn2(J2D_TRACE_WARNING, "MTLGlyphCache_RemoveCellInfo: "\
"no cell 0x%x in glyph 0x%x's cell list",
cellInfo, glyph);
}
/**
* Removes cell info from the glyph's list of cached cells.
*/
JNIEXPORT void
MTLGlyphCache_RemoveAllCellInfos(GlyphInfo *glyph)
{
MTLCacheCellInfo *currCell, *prevCell;
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_RemoveAllCellInfos");
if (glyph == NULL || glyph->cellInfo == NULL) {
return;
}
// invalidate all of this glyph's accelerated cache cells
currCell = glyph->cellInfo;
do {
currCell->glyphInfo = NULL;
prevCell = currCell;
currCell = currCell->nextGCI;
prevCell->nextGCI = NULL;
} while (currCell != NULL);
glyph->cellInfo = NULL;
}
/**
* Returns cell info associated with particular cache from the glyph's list of
* cached cells.
*/
MTLCacheCellInfo *
MTLGlyphCache_GetCellInfoForCache(GlyphInfo *glyph, MTLGlyphCacheInfo *cache)
{
// assert (glyph != NULL && cache != NULL)
J2dTraceLn(J2D_TRACE_VERBOSE2, "MTLGlyphCache_GetCellInfoForCache");
if (glyph->cellInfo != NULL) {
MTLCacheCellInfo *cellInfo = glyph->cellInfo;
do {
if (cellInfo->cacheInfo == cache) {
J2dTraceLn3(J2D_TRACE_VERBOSE2,
" glyph 0x%x: found cell 0x%x for cache 0x%x",
glyph, cellInfo, cache);
return cellInfo;
}
cellInfo = cellInfo->nextGCI;
} while (cellInfo != NULL);
}
J2dTraceLn2(J2D_TRACE_VERBOSE2, " glyph 0x%x: no cell for cache 0x%x",
glyph, cache);
return NULL;
}
}

View File

@@ -576,10 +576,8 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
jlong pDst = NEXT_LONG(b);
if (mtlc != NULL) {
if (dstOps != NULL && dstOps->pTexture != NULL) {
MTLTR_FreeGlyphCacheAA();
MTLTR_FreeGlyphCacheLCD();
}
[mtlc.glyphCacheAA free];
[mtlc.glyphCacheLCD free];
[mtlc commitCommandBuffer:NO display:NO];
}
mtlc = [MTLContext setSurfacesEnv:env src:pSrc dst:pDst];
@@ -594,10 +592,8 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
(MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
if (mtlc != NULL) {
if (dstOps != NULL && dstOps->pTexture != NULL) {
MTLTR_FreeGlyphCacheAA();
MTLTR_FreeGlyphCacheLCD();
}
[mtlc.glyphCacheAA free];
[mtlc.glyphCacheLCD free];
[mtlc commitCommandBuffer:NO display:NO];
}
@@ -616,8 +612,8 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
BMTLSDOps *mtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
if (mtlsdo != NULL) {
CONTINUE_IF_NULL(mtlc);
MTLTR_FreeGlyphCacheAA();
MTLTR_FreeGlyphCacheLCD();
[mtlc.glyphCacheAA free];
[mtlc.glyphCacheLCD free];
MTLSD_Delete(env, mtlsdo);
}
break;
@@ -641,8 +637,8 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
CHECK_PREVIOUS_OP(MTL_OP_OTHER);
jlong pConfigInfo = NEXT_LONG(b);
CONTINUE_IF_NULL(mtlc);
MTLTR_FreeGlyphCacheAA();
MTLTR_FreeGlyphCacheLCD();
[mtlc.glyphCacheAA free];
[mtlc.glyphCacheLCD free];
[mtlc.encoderManager endEncoder];
MTLGC_DestroyMTLGraphicsConfig(pConfigInfo);
mtlc = NULL;

View File

@@ -46,10 +46,6 @@
void MTLTR_EnableGlyphVertexCache(MTLContext *mtlc, BMTLSDOps *dstOps);
void MTLTR_DisableGlyphVertexCache(MTLContext *mtlc);
id<MTLTexture> MTLTR_GetGlyphCacheTexture();
id<MTLRenderCommandEncoder> MTLTR_GetGlyphCacheEncoder();
void MTLTR_FreeGlyphCacheAA();
void MTLTR_FreeGlyphCacheLCD();
void MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, BMTLSDOps *dstOps,
jint totalGlyphs, jboolean usePositions,

View File

@@ -66,19 +66,6 @@ typedef enum {
} GlyphMode;
static GlyphMode glyphMode = MODE_NOT_INITED;
/**
* There are two separate glyph caches: for AA and for LCD.
* Once one of them is initialized as either GRAY or LCD, it
* stays in that mode for the duration of the application. It should
* be safe to use this one glyph cache for all screens in a multimon
* environment, since the glyph cache texture is shared between all contexts,
* and (in theory) Metal drivers should be smart enough to manage that
* texture across all screens.
*/
static MTLGlyphCacheInfo *glyphCacheLCD = NULL;
static MTLGlyphCacheInfo *glyphCacheAA = NULL;
/**
* This value tracks the previous LCD rgbOrder setting, so if the rgbOrder
* value has changed since the last time, it indicates that we need to
@@ -98,8 +85,6 @@ static jboolean lastRGBOrder = JNI_TRUE;
static struct TxtVertex txtVertices[6];
static jint vertexCacheIndex = 0;
static id<MTLRenderCommandEncoder> aaCacheEncoder = nil;
static id<MTLRenderCommandEncoder> lcdCacheEncoder = nil;
#define LCD_ADD_VERTEX(TX, TY, DX, DY, DZ) \
do { \
@@ -127,88 +112,28 @@ static id<MTLRenderCommandEncoder> lcdCacheEncoder = nil;
* as intensity values.
*/
static jboolean
MTLTR_InitGlyphCache(MTLContext *mtlc, BMTLSDOps *dstOps, jboolean lcdCache)
MTLTR_ValidateGlyphCache(MTLContext *mtlc, BMTLSDOps *dstOps, jboolean lcdCache)
{
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_InitGlyphCache");
// TODO : Need to verify RGB order in case of LCD
MTLPixelFormat pixelFormat =
lcdCache ? MTLPixelFormatBGRA8Unorm : MTLPixelFormatA8Unorm;
MTLGlyphCacheInfo *gcinfo;
// init glyph cache data structure
gcinfo = MTLGlyphCache_Init(mtlc, MTLTR_CACHE_WIDTH,
MTLTR_CACHE_HEIGHT,
MTLTR_CACHE_CELL_WIDTH,
MTLTR_CACHE_CELL_HEIGHT,
MTLVertexCache_FlushGlyphVertexCache);
if (gcinfo == NULL) {
MTLGlyphCache* glyphCache = (lcdCache)?mtlc.glyphCacheLCD:mtlc.glyphCacheAA;
if (glyphCache.cacheInfo == NULL && ![glyphCache glyphCacheInitWidth:MTLTR_CACHE_WIDTH
height:MTLTR_CACHE_HEIGHT
cellWidth:MTLTR_CACHE_CELL_WIDTH
cellHeight:MTLTR_CACHE_CELL_HEIGHT
pixelFormat:(lcdCache)?MTLPixelFormatBGRA8Unorm:MTLPixelFormatA8Unorm
func:MTLVertexCache_FlushGlyphVertexCache])
{
J2dRlsTraceLn(J2D_TRACE_ERROR,
"MTLTR_InitGlyphCache: could not init MTL glyph cache");
return JNI_FALSE;
}
MTLTextureDescriptor *textureDescriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixelFormat
width:MTLTR_CACHE_WIDTH
height:MTLTR_CACHE_HEIGHT
mipmapped:NO];
gcinfo->texture = [mtlc.device newTextureWithDescriptor:textureDescriptor];
if (lcdCache) {
glyphCacheLCD = gcinfo;
} else {
glyphCacheAA = gcinfo;
}
glyphCache.cacheInfo->encoder = (lcdCache)?
[mtlc.encoderManager getLCDEncoder:dstOps->pTexture isSrcOpaque:YES isDstOpaque:YES]:
[mtlc.encoderManager getTextEncoder:dstOps isSrcOpaque:NO gammaCorrection:YES];
return JNI_TRUE;
}
static jboolean
MTLTR_ValidateGlyphCache(MTLContext *mtlc, BMTLSDOps *dstOps, jboolean lcdCache)
{
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_ValidateGlyphCache");
if (lcdCache) {
if (glyphCacheLCD == NULL && !MTLTR_InitGlyphCache(mtlc, dstOps, JNI_TRUE)) {
return JNI_FALSE;
}
lcdCacheEncoder = [mtlc.encoderManager getLCDEncoder:dstOps->pTexture
isSrcOpaque:YES
isDstOpaque:YES];
} else {
if (glyphCacheAA == NULL && !MTLTR_InitGlyphCache(mtlc, dstOps, JNI_FALSE)) {
return JNI_FALSE;
}
aaCacheEncoder = [mtlc.encoderManager getTextEncoder:dstOps
isSrcOpaque:NO
gammaCorrection:YES];
}
return JNI_TRUE;
}
id<MTLRenderCommandEncoder>
MTLTR_GetGlyphCacheEncoder()
{
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_GetGlyphCacheEncoder");
if (glyphCacheAA != NULL) {
return aaCacheEncoder;
}
return NULL;
}
id<MTLTexture>
MTLTR_GetGlyphCacheTexture()
{
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_GetGlyphCacheTexture");
if (glyphCacheAA != NULL) {
return glyphCacheAA->texture;
}
return NULL;
}
/**
* Adds the given glyph to the glyph cache (texture and data structure)
* associated with the given MTLContext.
@@ -218,32 +143,30 @@ MTLTR_AddToGlyphCache(GlyphInfo *glyph, MTLContext *mtlc,
BMTLSDOps *dstOps, jboolean lcdCache)
{
MTLCacheCellInfo *ccinfo;
MTLGlyphCacheInfo *gcinfo;
MTLGlyphCache* gc;
jint w = glyph->width;
jint h = glyph->height;
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_AddToGlyphCache");
if (!lcdCache) {
gcinfo = glyphCacheAA;
gc = mtlc.glyphCacheAA;
} else {
gcinfo = glyphCacheLCD;
gc = mtlc.glyphCacheLCD;
}
if ((gcinfo == NULL) || (glyph->image == NULL)) {
if ((gc.cacheInfo == NULL) || (glyph->image == NULL)) {
return;
}
bool isCacheFull = MTLGlyphCache_IsCacheFull(gcinfo, glyph);
if (isCacheFull) {
if ([gc isCacheFull:glyph]) {
if (lcdCache) {
MTLTR_FreeGlyphCacheLCD();
[mtlc.glyphCacheLCD free];
} else {
MTLTR_FreeGlyphCacheAA();
[mtlc.glyphCacheAA free];
}
MTLTR_ValidateGlyphCache(mtlc, dstOps, lcdCache);
gcinfo = lcdCache ? glyphCacheLCD : glyphCacheAA;
}
MTLGlyphCache_AddGlyph(gcinfo, glyph);
[gc addGlyph:glyph];
ccinfo = (MTLCacheCellInfo *) glyph->cellInfo;
if (ccinfo != NULL) {
@@ -254,7 +177,7 @@ MTLTR_AddToGlyphCache(GlyphInfo *glyph, MTLContext *mtlc,
};
if (!lcdCache) {
NSUInteger bytesPerRow = 1 * w;
[gcinfo->texture replaceRegion:region
[gc.cacheInfo->texture replaceRegion:region
mipmapLevel:0
withBytes:glyph->image
bytesPerRow:bytesPerRow];
@@ -273,7 +196,7 @@ MTLTR_AddToGlyphCache(GlyphInfo *glyph, MTLContext *mtlc,
}
NSUInteger bytesPerRow = 4 * w;
[gcinfo->texture replaceRegion:region
[gc.cacheInfo->texture replaceRegion:region
mipmapLevel:0
withBytes:imageData
bytesPerRow:bytesPerRow];
@@ -335,28 +258,10 @@ void
MTLTR_DisableGlyphVertexCache(MTLContext *mtlc)
{
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DisableGlyphVertexCache");
MTLVertexCache_FlushGlyphVertexCache();
MTLVertexCache_FlushGlyphVertexCache(mtlc);
MTLVertexCache_FreeVertexCache();
}
void MTLTR_FreeGlyphCacheAA() {
if (glyphCacheAA != NULL) {
id<MTLTexture> txt = glyphCacheAA->texture;
MTLGlyphCache_Free(glyphCacheAA);
[txt release];
glyphCacheAA = NULL;
}
}
void MTLTR_FreeGlyphCacheLCD() {
if (glyphCacheLCD != NULL) {
id<MTLTexture> txt = glyphCacheLCD->texture;
MTLGlyphCache_Free(glyphCacheLCD);
[txt release];
glyphCacheLCD = NULL;
}
}
static MTLPaint* storedPaint = nil;
static void EnableColorGlyphPainting(MTLContext *mtlc) {
@@ -443,7 +348,7 @@ MTLTR_DrawLCDGlyphViaCache(MTLContext *mtlc, BMTLSDOps *dstOps,
if (rgbOrder != lastRGBOrder) {
// need to invalidate the cache in this case; see comments
// for lastRGBOrder above
MTLGlyphCache_Invalidate(glyphCacheLCD);
[mtlc.glyphCacheLCD invalidate];
lastRGBOrder = rgbOrder;
}
@@ -463,7 +368,7 @@ MTLTR_DrawLCDGlyphViaCache(MTLContext *mtlc, BMTLSDOps *dstOps,
cell = (MTLCacheCellInfo *) (ginfo->cellInfo);
cell->timesRendered++;
MTLTR_SetLCDContrast(mtlc, contrast, lcdCacheEncoder);
MTLTR_SetLCDContrast(mtlc, contrast, mtlc.glyphCacheLCD.cacheInfo->encoder);
tx1 = cell->tx1;
ty1 = cell->ty1;
tx2 = cell->tx2;
@@ -474,11 +379,11 @@ MTLTR_DrawLCDGlyphViaCache(MTLContext *mtlc, BMTLSDOps *dstOps,
LCD_ADD_TRIANGLES(tx1, ty1, tx2, ty2, x, y, x+w, y+h);
[lcdCacheEncoder setVertexBytes:txtVertices length:sizeof(txtVertices) atIndex:MeshVertexBuffer];
[lcdCacheEncoder setFragmentTexture:glyphCacheLCD->texture atIndex:0];
[lcdCacheEncoder setFragmentTexture:dstOps->pTexture atIndex:1];
[mtlc.glyphCacheLCD.cacheInfo->encoder setVertexBytes:txtVertices length:sizeof(txtVertices) atIndex:MeshVertexBuffer];
[mtlc.glyphCacheLCD.cacheInfo->encoder setFragmentTexture:mtlc.glyphCacheLCD.cacheInfo->texture atIndex:0];
[mtlc.glyphCacheLCD.cacheInfo->encoder setFragmentTexture:dstOps->pTexture atIndex:1];
[lcdCacheEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
[mtlc.glyphCacheLCD.cacheInfo->encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
vertexCacheIndex = 0;

View File

@@ -74,7 +74,7 @@
*/
jboolean MTLVertexCache_InitVertexCache();
void MTLVertexCache_FlushVertexCache(MTLContext *mtlc);
void MTLVertexCache_FlushGlyphVertexCache();
void MTLVertexCache_FlushGlyphVertexCache(MTLContext *mtlc);
void MTLVertexCache_FreeVertexCache();
void MTLVertexCache_EnableMaskCache(MTLContext *mtlc, BMTLSDOps *dstOps);

View File

@@ -110,15 +110,15 @@ MTLVertexCache_FlushVertexCache(MTLContext *mtlc)
}
void
MTLVertexCache_FlushGlyphVertexCache()
MTLVertexCache_FlushGlyphVertexCache(MTLContext *mtlc)
{
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_FlushGlyphVertexCache");
if (vertexCacheIndex > 0) {
id<MTLRenderCommandEncoder> gcEncoder = MTLTR_GetGlyphCacheEncoder();
if (vertexCacheIndex > 0 && mtlc.glyphCacheAA.cacheInfo != NULL) {
id<MTLRenderCommandEncoder> gcEncoder = mtlc.glyphCacheAA.cacheInfo->encoder;
[gcEncoder setVertexBytes: vertexCache length:vertexCacheIndex * sizeof(J2DVertex)
atIndex:MeshVertexBuffer];
id<MTLTexture> glyphCacheTex = MTLTR_GetGlyphCacheTexture();
id<MTLTexture> glyphCacheTex = mtlc.glyphCacheAA.cacheInfo->texture;
[gcEncoder setFragmentTexture:glyphCacheTex atIndex: 0];
J2dTraceLn1(J2D_TRACE_INFO,
"MTLVertexCache_FlushGlyphVertexCache : encode %d characters", (vertexCacheIndex / 6));
@@ -323,7 +323,7 @@ MTLVertexCache_AddGlyphQuad(MTLContext *mtlc,
if ((vertexCacheIndex + VERTS_FOR_A_QUAD) >= MTLVC_MAX_INDEX)
{
J2dTraceLn2(J2D_TRACE_INFO, "maskCacheIndex = %d, vertexCacheIndex = %d", maskCacheIndex, vertexCacheIndex);
MTLVertexCache_FlushGlyphVertexCache();
MTLVertexCache_FlushGlyphVertexCache(mtlc);
}
MTLVC_ADD_TRIANGLES(tx1, ty1, tx2, ty2,