mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
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:
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user