JBR-5170: improved color maskFill performance: using a new MaskColorBuffer and a specific shader (vert_txt_col)

fix crash in J2DDemo with advanced paints + artefacts with texture background
(cherry picked from commit 9c1f618e1a6239ad8c400d7b94ccd4a885ec02d7)
(cherry picked from commit c352cfb25d7f8188540b094bb484f7f438142be4)
This commit is contained in:
bourgesl
2023-04-28 11:28:17 +02:00
parent 0299eb6198
commit ac7bb70044
8 changed files with 312 additions and 135 deletions

View File

@@ -73,6 +73,7 @@
@property jint textureFunction;
@property jboolean vertexCacheEnabled;
@property jboolean aaEnabled;
@property jboolean useMaskColor;
@property (readonly, strong) id<MTLDevice> device;
@property (strong) id<MTLCommandQueue> commandQueue;

View File

@@ -136,7 +136,8 @@ MTLTransform* tempTransform = nil;
}
@synthesize textureFunction,
vertexCacheEnabled, aaEnabled, device, pipelineStateStorage,
vertexCacheEnabled, aaEnabled, useMaskColor,
device, pipelineStateStorage,
commandQueue, blitCommandQueue, vertexBuffer,
texturePool, paint=_paint, encoderManager=_encoderManager,
samplerManager=_samplerManager, stencilManager=_stencilManager,

View File

@@ -51,18 +51,19 @@
static MTLRenderPipelineDescriptor * templateRenderPipelineDesc = nil;
static MTLRenderPipelineDescriptor * templateTexturePipelineDesc = nil;
static MTLRenderPipelineDescriptor * templateColorTexturePipelineDesc = nil;
static MTLRenderPipelineDescriptor * templateAATexturePipelineDesc = nil;
static MTLRenderPipelineDescriptor * templateLCDPipelineDesc = nil;
static MTLRenderPipelineDescriptor * templateAAPipelineDesc = nil;
static void
setTxtUniforms(MTLContext *mtlc, int color, id <MTLRenderCommandEncoder> encoder, int interpolation, bool repeat,
jfloat extraAlpha, const SurfaceRasterFlags *srcFlags, int mode,
bool gmcText);
bool gmcText, bool useMaskColor);
static void initTemplatePipelineDescriptors() {
if (templateRenderPipelineDesc != nil && templateTexturePipelineDesc != nil &&
templateAATexturePipelineDesc != nil && templateLCDPipelineDesc != nil &&
templateAAPipelineDesc != nil)
templateColorTexturePipelineDesc != nil && templateAATexturePipelineDesc != nil &&
templateLCDPipelineDesc != nil && templateAAPipelineDesc != nil)
return;
MTLVertexDescriptor *vertDesc = [[MTLVertexDescriptor new] autorelease];
@@ -97,6 +98,9 @@ static void initTemplatePipelineDescriptors() {
templateAATexturePipelineDesc = [templateTexturePipelineDesc copy];
templateAATexturePipelineDesc.label = @"template_aa_texture";
templateColorTexturePipelineDesc = [templateTexturePipelineDesc copy];
templateColorTexturePipelineDesc.label = @"template_col_texture";
templateLCDPipelineDesc = [MTLRenderPipelineDescriptor new];
templateLCDPipelineDesc.sampleCount = 1;
templateLCDPipelineDesc.vertexDescriptor = vertDesc;
@@ -211,28 +215,38 @@ jint _color;
NSString *vertShader = @"vert_col";
NSString *fragShader = @"frag_col";
bool gmcText = NO;
if (renderOptions->isTexture) {
bool gmcText = NO;
bool colorBuffer = YES;
vertShader = @"vert_txt";
fragShader = @"frag_txt";
rpDesc = templateTexturePipelineDesc;
if (renderOptions->isAA) {
fragShader = @"aa_frag_txt";
rpDesc = templateAATexturePipelineDesc;
colorBuffer = NO;
}
if (renderOptions->isGMCText) {
fragShader = @"frag_gmc_text";
gmcText = YES;
colorBuffer = NO;
}
if (renderOptions->isLCD) {
vertShader = @"vert_txt_lcd";
fragShader = @"lcd_color";
rpDesc = templateLCDPipelineDesc;
colorBuffer = NO;
}
if (colorBuffer) {
vertShader = @"vert_txt_col";
fragShader = @"frag_txt_col";
rpDesc = templateColorTexturePipelineDesc;
}
setTxtUniforms(mtlc, _color, encoder,
renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha],
&renderOptions->srcFlags, 1, gmcText);
&renderOptions->srcFlags, 1, gmcText, colorBuffer);
} else if (renderOptions->isAAShader) {
vertShader = @"vert_col_aa";
fragShader = @"frag_col_aa";
@@ -273,7 +287,7 @@ jint _color;
setTxtUniforms(mtlc, col, encoder,
renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha],
&renderOptions->srcFlags, 1, NO);
&renderOptions->srcFlags, 1, NO, NO);
[encoder setFragmentBytes:&xorColor length:sizeof(xorColor) atIndex:0];
[encoder setFragmentTexture:dstOps->pTexture atIndex:1];
@@ -814,7 +828,7 @@ jint _color;
const SurfaceRasterFlags srcFlags = {_isOpaque, renderOptions->srcFlags.isPremultiplied};
setTxtUniforms(mtlc, 0, encoder,
renderOptions->interpolation, YES, [mtlc.composite getExtraAlpha],
&srcFlags, 0, NO);
&srcFlags, 0, NO, NO);
id <MTLRenderPipelineState> pipelineState = [pipelineStateStorage getPipelineState:rpDesc
vertexShaderId:vertShader
@@ -897,46 +911,47 @@ jint _color;
static void
setTxtUniforms(MTLContext *mtlc, int color, id <MTLRenderCommandEncoder> encoder, int interpolation, bool repeat,
jfloat extraAlpha, const SurfaceRasterFlags *srcFlags, int mode,
bool gmcText)
bool gmcText, bool useMaskColor)
{
if (gmcText) {
float ca = (((color) >> 24) & 0xFF)/255.0f;
float cr = (((color) >> 16) & (0xFF))/255.0f;
float cg = (((color) >> 8) & 0xFF)/255.0f;
float cb = ((color) & 0xFF)/255.0f;
// Convert from ARGB_PRE
if (ca > 0.0f) {
cr /= ca;
cg /= ca;
cb /= ca;
}
float inv_light_gamma = 1.666f;
float inv_dark_gamma = 0.333f;
float inv_light_exp = 0.454f;
float inv_dark_exp = 1.4f;
float ca = (((color) >> 24) & 0xFF)/255.0f;
float cr = (((color) >> 16) & (0xFF))/255.0f;
float cg = (((color) >> 8) & 0xFF)/255.0f;
float cb = ((color) & 0xFF)/255.0f;
// Convert from ARGB_PRE
if (ca > 0.0f) {
cr /= ca;
cg /= ca;
cb /= ca;
}
float inv_light_gamma = 1.666f;
float inv_dark_gamma = 0.333f;
float inv_light_exp = 0.454f;
float inv_dark_exp = 1.4f;
// calculate brightness of the fragment
float b = (cr/3.0f + cg/3.0f + cb/3.0f)*ca;
// calculate brightness of the fragment
float b = (cr/3.0f + cg/3.0f + cb/3.0f)*ca;
// adjust fragment coverage
float exp = inv_dark_exp*(1.0f - b) + inv_light_exp*b;
// adjust fragment coverage
float exp = inv_dark_exp*(1.0f - b) + inv_light_exp*b;
// adjust fragment color and alpha for alpha < 1.0
if (ca < 1.0f) {
float g = inv_dark_gamma*(1.0f - b) + inv_light_gamma*b;
cr = pow(cr, g);
cg = pow(cg, g);
cb = pow(cb, g);
ca = pow(ca, exp);
}
// adjust fragment color and alpha for alpha < 1.0
if (ca < 1.0f) {
float g = inv_dark_gamma*(1.0f - b) + inv_light_gamma*b;
cr = pow(cr, g);
cg = pow(cg, g);
cb = pow(cb, g);
ca = pow(ca, exp);
}
struct GMCFrameUniforms uf = {{cr, cg, cb, ca}, exp};
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
struct GMCFrameUniforms uf = {{cr, cg, cb, ca}, exp};
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
} else {
struct TxtFrameUniforms uf =
{RGBA_TO_V4(color), mode, srcFlags->isOpaque, extraAlpha};
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
struct TxtFrameUniforms uf =
{RGBA_TO_V4(color), mode, srcFlags->isOpaque, extraAlpha};
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
}
[mtlc setUseMaskColor: useMaskColor ? JNI_TRUE : JNI_FALSE];
[mtlc.samplerManager setSamplerWithEncoder:encoder interpolation:interpolation repeat:repeat];
}
@@ -997,8 +1012,7 @@ setTxtUniforms(MTLContext *mtlc, int color, id <MTLRenderCommandEncoder> encoder
} else {
setTxtUniforms(mtlc, 0, encoder,
renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha],
&renderOptions->srcFlags, 0, NO);
&renderOptions->srcFlags, 0, NO, NO);
}
id <MTLRenderPipelineState> pipelineState = [pipelineStateStorage getPipelineState:rpDesc
vertexShaderId:vertShader
@@ -1038,7 +1052,7 @@ setTxtUniforms(MTLContext *mtlc, int color, id <MTLRenderCommandEncoder> encoder
const int col = 0 ^ xorColor;
setTxtUniforms(mtlc, col, encoder,
renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha],
&renderOptions->srcFlags, 0, NO);
&renderOptions->srcFlags, 0, NO, NO);
[encoder setFragmentBytes:&xorColor length:sizeof(xorColor) atIndex: 0];
BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
@@ -1046,7 +1060,7 @@ setTxtUniforms(MTLContext *mtlc, int color, id <MTLRenderCommandEncoder> encoder
setTxtUniforms(mtlc, 0, encoder,
renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha],
&renderOptions->srcFlags, 0, NO);
&renderOptions->srcFlags, 0, NO, NO);
id <MTLRenderPipelineState> pipelineState = [pipelineStateStorage getPipelineState:rpDesc
vertexShaderId:vertShader

View File

@@ -56,8 +56,9 @@ void MTLRenderQueue_CheckPreviousOp(jint op) {
}
if (op == MTL_OP_SET_COLOR) {
if (mtlPreviousOp != MTL_OP_MASK_OP) {
return; // SET_COLOR should not cause endEncoder
// MTL_OP_MASK_OP: switching from advanced paints to SET_COLOR must cause endEncoder:
if ((mtlPreviousOp != MTL_OP_MASK_OP) || (mtlc == NULL) || [mtlc useMaskColor]) {
return;
}
} else if (op == MTL_OP_MASK_OP) {
MTLVertexCache_EnableMaskCache(mtlc, dstOps);
@@ -75,6 +76,8 @@ void MTLRenderQueue_CheckPreviousOp(jint op) {
case MTL_OP_MASK_OP :
MTLVertexCache_DisableMaskCache(mtlc);
break;
default:
break;
}
if (mtlc != NULL) {

View File

@@ -29,17 +29,32 @@
#include "MTLContext.h"
#include "fontscalerdefs.h"
// Next define should exactly match to the amount
// of MTLVC_ADD_VERTEX in MTLVC_ADD_TRIANGLES
#define VERTS_FOR_A_QUAD 6
/**
* MTLBuffer.setVertexBytes() is limited to 4K buffer size
*/
#define MTLVC_MAX_VERTEX_SIZE 4096
/**
* sizeof(J2DVertex) = 2 x 2 float values = 16 bytes (aligned)
*/
#define MTLVC_SIZE_J2DVertex 16
/**
* The max size of the vertex cache.
*
* Note:
* This is the max number of vertices (of struct J2DVertex - 16 bytes)
* This is the max number of vertices (of struct J2DVertex)
* that can be accommodated in 4KB.
*
* [MTLRenderCommandEncoder setVertexBytes] expects the data size
* to be less than or equal to 4KB.
*/
#define MTLVC_MAX_INDEX 250
#define MTLVC_MAX_QUAD ((MTLVC_MAX_VERTEX_SIZE / MTLVC_SIZE_J2DVertex) / VERTS_FOR_A_QUAD)
#define MTLVC_MAX_INDEX (MTLVC_MAX_QUAD * VERTS_FOR_A_QUAD)
/**
* Constants that control the size of the texture tile cache used for
@@ -50,8 +65,9 @@
#define MTLVC_MASK_CACHE_TILE_SIZE \
(MTLVC_MASK_CACHE_TILE_WIDTH * MTLVC_MASK_CACHE_TILE_HEIGHT)
/* 1 texture contains 8 x 5 = 40 tiles (~ max quad) */
#define MTLVC_MASK_CACHE_WIDTH_IN_TILES 8
#define MTLVC_MASK_CACHE_HEIGHT_IN_TILES 4
#define MTLVC_MASK_CACHE_HEIGHT_IN_TILES 5
#define MTLVC_MASK_CACHE_WIDTH_IN_TEXELS \
(MTLVC_MASK_CACHE_TILE_WIDTH * MTLVC_MASK_CACHE_WIDTH_IN_TILES)
@@ -63,7 +79,9 @@
* operations where the mask is null.
*/
#define MTLVC_MASK_CACHE_MAX_INDEX \
((MTLVC_MASK_CACHE_WIDTH_IN_TILES * MTLVC_MASK_CACHE_HEIGHT_IN_TILES) - 1)
(MTLVC_MASK_CACHE_WIDTH_IN_TILES * MTLVC_MASK_CACHE_HEIGHT_IN_TILES)
#define MTLVC_MASK_CACHE_MAX_INDEX_RESERVED \
(MTLVC_MASK_CACHE_MAX_INDEX - 1)
#define MTLVC_MASK_CACHE_SPECIAL_TILE_X \
(MTLVC_MASK_CACHE_WIDTH_IN_TEXELS - MTLVC_MASK_CACHE_TILE_WIDTH)
#define MTLVC_MASK_CACHE_SPECIAL_TILE_Y \

View File

@@ -30,44 +30,66 @@
#include "MTLPaints.h"
#include "MTLVertexCache.h"
#include "MTLTexturePool.h"
#include "MTLTextRenderer.h"
#include "common.h"
typedef struct _J2DVertex {
float position[2];
float txtpos[2];
} J2DVertex;
typedef struct MaskFillColor sMaskFillColor;
static J2DVertex *vertexCache = NULL;
static jint vertexCacheIndex = 0;
static MTLPooledTextureHandle * maskCacheTex = NULL;
static sMaskFillColor *maskColorCache = NULL;
static jint maskColorCacheIndex = 0;
static MTLPooledTextureHandle *maskCacheTex = nil;
static jint maskCacheIndex = 0;
static id<MTLRenderCommandEncoder> encoder = NULL;
static jint maskCacheLastIndex = MTLVC_MASK_CACHE_MAX_INDEX;
static id<MTLRenderCommandEncoder> encoder = nil;
#define MTLVC_ADD_VERTEX(TX, TY, DX, DY, DZ) \
do { \
#define MTLVC_ADD_VERTEX(TX, TY, DX, DY) \
do { \
J2DVertex *v = &vertexCache[vertexCacheIndex++]; \
v->txtpos[0] = TX; \
v->txtpos[1] = TY; \
v->position[0]= DX; \
v->position[1] = DY; \
v->txtpos[0] = TX; \
v->txtpos[1] = TY; \
v->position[0] = DX; \
v->position[1] = DY; \
} while (0)
/*
* 1 quad = 2 triangles, 6 vertices
*/
#define MTLVC_ADD_TRIANGLES(TX1, TY1, TX2, TY2, DX1, DY1, DX2, DY2) \
do { \
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); \
do { \
MTLVC_ADD_VERTEX(TX1, TY1, DX1, DY1); \
MTLVC_ADD_VERTEX(TX2, TY1, DX2, DY1); \
MTLVC_ADD_VERTEX(TX2, TY2, DX2, DY2); \
MTLVC_ADD_VERTEX(TX2, TY2, DX2, DY2); \
MTLVC_ADD_VERTEX(TX1, TY2, DX1, DY2); \
MTLVC_ADD_VERTEX(TX1, TY1, DX1, DY1); \
} while (0)
// Next define should exactly match to the amount
// of MTLVC_ADD_VERTEX in MTLVC_ADD_TRIANGLES
#define VERTS_FOR_A_QUAD 6
#define RGBA_COMP 4
#define MTLVC_COPY_COLOR(DST, COL) \
memcpy(DST, COL, RGBA_COMP);
#define MTLVC_ADD_QUAD_COLOR(COL) \
do { \
sMaskFillColor *uf = &maskColorCache[maskColorCacheIndex++]; \
MTLVC_COPY_COLOR(uf->color, COL); \
} while (0)
#define RGBA_TO_U4(c) \
{ \
(unsigned char) (((c) >> 16) & 0xFF), \
(unsigned char) (((c) >> 8) & 0xFF), \
(unsigned char) ((c) & 0xFF), \
(unsigned char) (((c) >> 24) & 0xFF) \
}
jboolean
MTLVertexCache_InitVertexCache()
@@ -76,12 +98,41 @@ MTLVertexCache_InitVertexCache()
if (vertexCache == NULL) {
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitVertexCache : vertexCache == NULL");
vertexCache = (J2DVertex *)malloc(MTLVC_MAX_INDEX * sizeof(J2DVertex));
size_t len = sizeof(J2DVertex);
if (len != MTLVC_SIZE_J2DVertex) {
J2dRlsTraceLn2(J2D_TRACE_ERROR, "MTLVertexCache_InitVertexCache : sizeof(J2DVertex) = %lu != %d bytes !",
len, MTLVC_SIZE_J2DVertex);
return JNI_FALSE;
}
len *= MTLVC_MAX_INDEX;
if (len > MTLVC_MAX_VERTEX_SIZE) {
J2dRlsTraceLn2(J2D_TRACE_ERROR, "MTLVertexCache_InitVertexCache : J2DVertex buffer size = %lu > %d bytes !",
len, MTLVC_MAX_VERTEX_SIZE);
return JNI_FALSE;
}
vertexCache = (J2DVertex *)malloc(len);
if (vertexCache == NULL) {
return JNI_FALSE;
}
}
if (maskColorCache == NULL) {
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitVertexCache : maskColorCache == NULL");
size_t len = MTLVC_MAX_QUAD * sizeof(sMaskFillColor);
if (len > MTLVC_MAX_VERTEX_SIZE) {
J2dRlsTraceLn2(J2D_TRACE_ERROR, "MTLVertexCache_InitVertexCache : MaskFillColor buffer size = %lu > %d bytes !",
len, MTLVC_MAX_VERTEX_SIZE);
return JNI_FALSE;
}
maskColorCache = (sMaskFillColor *)malloc(len);
if (maskColorCache == NULL) {
return JNI_FALSE;
}
}
return JNI_TRUE;
}
@@ -91,17 +142,29 @@ MTLVertexCache_FlushVertexCache(MTLContext *mtlc)
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_FlushVertexCache");
if (vertexCacheIndex > 0) {
[encoder setVertexBytes: vertexCache length:vertexCacheIndex * sizeof(J2DVertex)
atIndex:MeshVertexBuffer];
[encoder setVertexBytes:vertexCache
length:vertexCacheIndex * MTLVC_SIZE_J2DVertex
atIndex:MeshVertexBuffer];
if (maskColorCacheIndex > 0) {
[encoder setVertexBytes:maskColorCache
length:maskColorCacheIndex * sizeof(sMaskFillColor)
atIndex:MaskColorBuffer];
}
[encoder setFragmentTexture:maskCacheTex.texture atIndex:0];
[encoder setFragmentTexture:maskCacheTex.texture atIndex: 0];
J2dTraceLn1(J2D_TRACE_INFO,
"MTLVertexCache_FlushVertexCache : encode %d characters", (vertexCacheIndex / 6));
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:vertexCacheIndex];
}
vertexCacheIndex = 0;
maskCacheIndex = 0;
"MTLVertexCache_FlushVertexCache : encode %d tiles", (vertexCacheIndex / VERTS_FOR_A_QUAD));
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:vertexCacheIndex];
vertexCacheIndex = 0;
maskColorCacheIndex = 0;
maskCacheIndex = 0;
maskCacheLastIndex = MTLVC_MASK_CACHE_MAX_INDEX;
}
// register texture to be released once encoder is completed:
if (maskCacheTex != nil) {
[[mtlc getCommandBufferWrapper] registerPooledTexture:maskCacheTex];
[maskCacheTex release];
@@ -120,8 +183,10 @@ MTLVertexCache_FlushGlyphVertexCache()
atIndex:MeshVertexBuffer];
id<MTLTexture> glyphCacheTex = MTLTR_GetGlyphCacheTexture();
[gcEncoder setFragmentTexture:glyphCacheTex atIndex: 0];
J2dTraceLn1(J2D_TRACE_INFO,
"MTLVertexCache_FlushGlyphVertexCache : encode %d characters", (vertexCacheIndex / 6));
"MTLVertexCache_FlushGlyphVertexCache : encode %d characters", (vertexCacheIndex / VERTS_FOR_A_QUAD));
[gcEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:vertexCacheIndex];
}
vertexCacheIndex = 0;
@@ -129,14 +194,52 @@ MTLVertexCache_FlushGlyphVertexCache()
void MTLVertexCache_FreeVertexCache()
{
free(vertexCache);
vertexCache = NULL;
if (vertexCache != NULL) {
free(vertexCache);
vertexCache = NULL;
}
if (maskColorCache != NULL) {
free(maskColorCache);
maskColorCache = NULL;
}
}
static jboolean
MTLVertexCache_InitMaskCache(MTLContext *mtlc) {
static void MTLVertexCache_InitFullTile()
{
if (maskCacheLastIndex == MTLVC_MASK_CACHE_MAX_INDEX) {
// init special fully opaque tile in the upper-right corner of
// the mask cache texture
static char tile[MTLVC_MASK_CACHE_TILE_SIZE];
static char* pTile = NULL;
if (!pTile) {
memset(tile, 0xff, MTLVC_MASK_CACHE_TILE_SIZE);
pTile = tile;
}
jint texx = MTLVC_MASK_CACHE_TILE_WIDTH * (MTLVC_MASK_CACHE_WIDTH_IN_TILES - 1);
jint texy = MTLVC_MASK_CACHE_TILE_HEIGHT * (MTLVC_MASK_CACHE_HEIGHT_IN_TILES - 1);
NSUInteger bytesPerRow = MTLVC_MASK_CACHE_TILE_WIDTH;
MTLRegion region = {
{texx, texy, 0},
{MTLVC_MASK_CACHE_TILE_WIDTH, MTLVC_MASK_CACHE_TILE_HEIGHT, 1}
};
[maskCacheTex.texture replaceRegion:region
mipmapLevel:0
withBytes:tile
bytesPerRow:bytesPerRow];
maskCacheLastIndex = MTLVC_MASK_CACHE_MAX_INDEX_RESERVED;
}
}
static jboolean MTLVertexCache_InitMaskCache(MTLContext *mtlc)
{
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitMaskCache");
if (maskCacheTex == NULL) {
if (maskCacheTex == nil) {
maskCacheTex = [mtlc.texturePool getTexture:MTLVC_MASK_CACHE_WIDTH_IN_TEXELS
height:MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS
format:MTLPixelFormatA8Unorm];
@@ -146,33 +249,6 @@ MTLVertexCache_InitMaskCache(MTLContext *mtlc) {
return JNI_FALSE;
}
}
// init special fully opaque tile in the upper-right corner of
// the mask cache texture
static char tile[MTLVC_MASK_CACHE_TILE_SIZE];
static char* pTile = NULL;
if (!pTile) {
memset(tile, 0xff, MTLVC_MASK_CACHE_TILE_SIZE);
pTile = tile;
}
jint texx = MTLVC_MASK_CACHE_TILE_WIDTH * (MTLVC_MASK_CACHE_WIDTH_IN_TILES - 1);
jint texy = MTLVC_MASK_CACHE_TILE_HEIGHT * (MTLVC_MASK_CACHE_HEIGHT_IN_TILES - 1);
NSUInteger bytesPerRow = 1 * MTLVC_MASK_CACHE_TILE_WIDTH;
MTLRegion region = {
{texx, texy, 0},
{MTLVC_MASK_CACHE_TILE_WIDTH, MTLVC_MASK_CACHE_TILE_HEIGHT, 1}
};
// do we really need this??
[maskCacheTex.texture replaceRegion:region
mipmapLevel:0
withBytes:tile
bytesPerRow:bytesPerRow];
return JNI_TRUE;
}
@@ -181,11 +257,17 @@ MTLVertexCache_EnableMaskCache(MTLContext *mtlc, BMTLSDOps *dstOps)
{
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_EnableMaskCache");
if (!MTLVertexCache_InitVertexCache()) {
return;
if ([mtlc useMaskColor]
&& ![mtlc.paint isKindOfClass:[MTLColorPaint class]]) {
// Reset useMaskColor flag for advanced paints:
[mtlc setUseMaskColor: JNI_FALSE];
}
if (maskCacheTex == NULL) {
if (vertexCache == NULL) {
if (!MTLVertexCache_InitVertexCache()) {
return;
}
}
if (maskCacheTex == nil) {
if (!MTLVertexCache_InitMaskCache(mtlc)) {
return;
}
@@ -196,14 +278,9 @@ MTLVertexCache_EnableMaskCache(MTLContext *mtlc, BMTLSDOps *dstOps)
void
MTLVertexCache_DisableMaskCache(MTLContext *mtlc)
{
// TODO : Once we enable check_previous_op
// we will start using DisableMaskCache until then
// we are force flushing vertexcache.
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_DisableMaskCache");
MTLVertexCache_FlushVertexCache(mtlc);
maskCacheIndex = 0;
free(vertexCache);
vertexCache = NULL;
MTLVertexCache_FreeVertexCache();
}
void
@@ -231,13 +308,15 @@ MTLVertexCache_AddMaskQuad(MTLContext *mtlc,
// MTLVC_ADD_TRIANGLES at the end of this function
// will place VERTS_FOR_A_QUAD vertexes to the vertex cache
// check free space and flush if needed.
if ((maskCacheIndex >= MTLVC_MASK_CACHE_MAX_INDEX) ||
if ((maskCacheIndex >= maskCacheLastIndex) ||
((vertexCacheIndex + VERTS_FOR_A_QUAD) >= MTLVC_MAX_INDEX))
{
J2dTraceLn2(J2D_TRACE_INFO, "maskCacheIndex = %d, vertexCacheIndex = %d", maskCacheIndex, vertexCacheIndex);
MTLVertexCache_FlushVertexCache(mtlc);
// Initialize texture & encoder again
// as MTLVertexCache_FlushVertexCache cleared texture
MTLVertexCache_EnableMaskCache(mtlc, dstOps);
maskCacheIndex = 0;
}
if (mask != NULL) {
@@ -247,8 +326,7 @@ MTLVertexCache_AddMaskQuad(MTLContext *mtlc,
(maskCacheIndex / MTLVC_MASK_CACHE_WIDTH_IN_TILES);
J2dTraceLn5(J2D_TRACE_INFO, "texx = %d texy = %d width = %d height = %d maskscan = %d", texx, texy, width,
height, maskscan);
NSUInteger bytesPerRow = 1 * width;
NSUInteger slice = bytesPerRow * srcy + srcx;
NSUInteger bytesPerRow = width;
MTLRegion region = {
{texx, texy, 0},
{width, height, 1}
@@ -272,7 +350,7 @@ MTLVertexCache_AddMaskQuad(MTLContext *mtlc,
bytesPerRow:bytesPerRow];
} else {
int dst_offset, src_offset;
int size = 1 * width * height;
int size = width * height;
char tile[size];
dst_offset = 0;
for (int i = srcy; i < srcy + height; i++) {
@@ -290,13 +368,18 @@ MTLVertexCache_AddMaskQuad(MTLContext *mtlc,
tx1 = ((jfloat) texx) / MTLVC_MASK_CACHE_WIDTH_IN_TEXELS;
ty1 = ((jfloat) texy) / MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS;
// count added masks:
maskCacheIndex++;
} else {
if (maskCacheLastIndex == MTLVC_MASK_CACHE_MAX_INDEX) {
MTLVertexCache_InitFullTile();
}
tx1 = ((jfloat)MTLVC_MASK_CACHE_SPECIAL_TILE_X) /
MTLVC_MASK_CACHE_WIDTH_IN_TEXELS;
ty1 = ((jfloat)MTLVC_MASK_CACHE_SPECIAL_TILE_Y) /
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);
@@ -306,6 +389,23 @@ MTLVertexCache_AddMaskQuad(MTLContext *mtlc,
dx2 = dx1 + width;
dy2 = dy1 + height;
if ([mtlc useMaskColor]) {
// ColorPaint class is already checked in MTLVertexCache_EnableMaskCache:
MTLColorPaint* cPaint = (MTLColorPaint *) mtlc.paint;
jint color = cPaint.color;
static jint lastColor = 0;
static unsigned char last_uColor[RGBA_COMP] = {0, 0, 0, 0};
if (color != lastColor) {
lastColor = color;
unsigned char uColor[RGBA_COMP] = RGBA_TO_U4(color);
MTLVC_COPY_COLOR(last_uColor, uColor);
}
// add only 1 color per quad:
MTLVC_ADD_QUAD_COLOR(last_uColor);
}
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);

View File

@@ -31,6 +31,7 @@
#define PGRAM_VERTEX_COUNT 6
#define QUAD_VERTEX_COUNT 4
#define GRAD_MAX_FRACTIONS 12
#define QUAD_VERTEX_COUNT_PER_COLOR 6
enum GradCycleMethod {
GradNoCycle = 0,
@@ -46,7 +47,8 @@ enum VertexAttributes {
enum BufferIndex {
MeshVertexBuffer = 0,
FrameUniformBuffer = 1,
MatrixBuffer = 2
MatrixBuffer = 2,
MaskColorBuffer = 3
};
struct FrameUniforms {
@@ -96,6 +98,10 @@ struct TxtVertex {
float txtpos[2];
};
struct MaskFillColor {
unsigned char color[4];
};
struct AAVertex {
float position[2];
float otxtpos[2];

View File

@@ -69,6 +69,13 @@ struct TxtShaderInOut {
float2 tpCoords;
};
struct TxtColShaderInOut {
float4 position [[position]];
float2 texCoords;
float2 tpCoords;
float4 color [[flat]];
};
struct LCDShaderInOut {
float4 position [[position]];
float2 orig_pos;
@@ -210,6 +217,19 @@ vertex TxtShaderInOut vert_txt(TxtVertexInput in [[stage_in]], constant Transfor
return out;
}
vertex TxtColShaderInOut vert_txt_col(TxtVertexInput in [[stage_in]],
constant TransformMatrix& transform [[buffer(MatrixBuffer)]],
const device uchar4* maskColors [[buffer(MaskColorBuffer)]],
uint vertexID [[vertex_id]]) {
TxtColShaderInOut out;
const float4 pos4 = float4(in.position, 0.0, 1.0);
out.position = transform.transformMatrix*pos4;
out.texCoords = in.texCoords;
const uint maskIdx = vertexID / QUAD_VERTEX_COUNT_PER_COLOR; // quad color index
out.color = float4(maskColors[maskIdx]) / 255.0f;
return out;
}
vertex LCDShaderInOut vert_txt_lcd(TxtVertexInput in [[stage_in]], constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) {
LCDShaderInOut out;
float4 pos4 = float4(in.position, 0.0, 1.0);
@@ -311,15 +331,29 @@ fragment half4 frag_txt(
float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords);
float srcA = uniforms.isSrcOpaque ? 1 : pixelColor.a;
if (uniforms.mode) {
float3 c = mix(pixelColor.rgb, uniforms.color.rgb, srcA);
return half4(c.r, c.g, c.b ,
(uniforms.isSrcOpaque) ?
uniforms.color.a : pixelColor.a*uniforms.color.a);
float4 in_col = uniforms.color;
float3 c = mix(pixelColor.rgb, in_col.rgb, srcA);
return half4(c.r, c.g, c.b,
(uniforms.isSrcOpaque) ? in_col.a : pixelColor.a * in_col.a);
}
return half4(pixelColor.r,
pixelColor.g,
pixelColor.b, srcA)*uniforms.extraAlpha;
pixelColor.b, srcA) * uniforms.extraAlpha;
}
fragment half4 frag_txt_col(
TxtColShaderInOut vert [[stage_in]],
texture2d<float, access::sample> renderTexture [[texture(0)]],
constant TxtFrameUniforms& uniforms [[buffer(1)]],
sampler textureSampler [[sampler(0)]]
) {
float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords);
float srcA = uniforms.isSrcOpaque ? 1 : pixelColor.a;
float4 in_col = vert.color;
float3 c = mix(pixelColor.rgb, in_col.rgb, srcA);
return half4(c.r, c.g, c.b,
(uniforms.isSrcOpaque) ? in_col.a : pixelColor.a * in_col.a);
}
fragment half4 frag_text(