[osx, canvas]
- Only super sample coverage at 8x rate, and accumulate pixel color in a single color value - Super sample images at lower 2x rate - Cull tiles outside clip - Bypass coverage for fully covered tiles
This commit is contained in:
parent
a65b0cc1bb
commit
bfc7530bcf
|
@ -70,7 +70,10 @@ typedef struct mg_mtl_path_queue
|
|||
using namespace metal;
|
||||
#endif
|
||||
|
||||
typedef enum { MG_MTL_OP_START,
|
||||
typedef enum { MG_MTL_OP_FILL,
|
||||
MG_MTL_OP_CLIP_FILL,
|
||||
MG_MTL_OP_START,
|
||||
MG_MTL_OP_END,
|
||||
MG_MTL_OP_SEGMENT } mg_mtl_tile_op_kind;
|
||||
|
||||
typedef struct mg_mtl_tile_op
|
||||
|
|
|
@ -1364,7 +1364,18 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
|
|||
int windingOffset = atomic_load_explicit(&tileQueue->windingOffset, memory_order_relaxed);
|
||||
int firstOpIndex = atomic_load_explicit(&tileQueue->first, memory_order_relaxed);
|
||||
|
||||
if(firstOpIndex == -1)
|
||||
float4 tileBox = float4(tileCoord.x, tileCoord.y, tileCoord.x+1, tileCoord.y+1);
|
||||
tileBox *= tileSize[0];
|
||||
float4 clip = pathBuffer[pathIndex].clip * scale[0];
|
||||
|
||||
if( tileBox.x >= clip.z
|
||||
|| tileBox.z < clip.x
|
||||
|| tileBox.y >= clip.w
|
||||
|| tileBox.w < clip.y)
|
||||
{
|
||||
//NOTE: tile is fully outside clip, cull it
|
||||
}
|
||||
else if(firstOpIndex == -1)
|
||||
{
|
||||
if(windingOffset & 1)
|
||||
{
|
||||
|
@ -1372,26 +1383,24 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
|
|||
// Additionally if color is opaque and tile is fully inside clip, trim tile list.
|
||||
int pathOpIndex = atomic_fetch_add_explicit(tileOpCount, 1, memory_order_relaxed);
|
||||
device mg_mtl_tile_op* pathOp = &tileOpBuffer[pathOpIndex];
|
||||
pathOp->kind = MG_MTL_OP_START;
|
||||
pathOp->kind = MG_MTL_OP_CLIP_FILL;
|
||||
pathOp->next = -1;
|
||||
pathOp->index = pathIndex;
|
||||
pathOp->windingOffset = windingOffset;
|
||||
|
||||
float4 clip = pathBuffer[pathIndex].clip * scale[0];
|
||||
float4 tileBox = float4(tileCoord.x, tileCoord.y, tileCoord.x+1, tileCoord.y+1);
|
||||
tileBox *= tileSize[0];
|
||||
*nextLink = pathOpIndex;
|
||||
|
||||
if(pathBuffer[pathIndex].color.a == 1
|
||||
&& tileBox.x >= clip.x
|
||||
if(tileBox.x >= clip.x
|
||||
&& tileBox.z < clip.z
|
||||
&& tileBox.y >= clip.y
|
||||
&& tileBox.w < clip.w)
|
||||
{
|
||||
pathOp->kind = MG_MTL_OP_FILL;
|
||||
|
||||
if(pathBuffer[pathIndex].color.a == 1)
|
||||
{
|
||||
screenTilesBuffer[tileIndex] = pathOpIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
*nextLink = pathOpIndex;
|
||||
}
|
||||
nextLink = &pathOp->next;
|
||||
}
|
||||
|
@ -1400,21 +1409,33 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
|
|||
else
|
||||
{
|
||||
//NOTE: add path start op (with winding offset)
|
||||
int pathOpIndex = atomic_fetch_add_explicit(tileOpCount, 1, memory_order_relaxed);
|
||||
device mg_mtl_tile_op* pathOp = &tileOpBuffer[pathOpIndex];
|
||||
pathOp->kind = MG_MTL_OP_START;
|
||||
pathOp->next = -1;
|
||||
pathOp->index = pathIndex;
|
||||
pathOp->windingOffset = windingOffset;
|
||||
int startOpIndex = atomic_fetch_add_explicit(tileOpCount, 1, memory_order_relaxed);
|
||||
device mg_mtl_tile_op* startOp = &tileOpBuffer[startOpIndex];
|
||||
startOp->kind = MG_MTL_OP_START;
|
||||
startOp->next = -1;
|
||||
startOp->index = pathIndex;
|
||||
startOp->windingOffset = windingOffset;
|
||||
|
||||
*nextLink = pathOpIndex;
|
||||
nextLink = &pathOp->next;
|
||||
*nextLink = startOpIndex;
|
||||
nextLink = &startOp->next;
|
||||
|
||||
//NOTE: chain remaining path ops to end of tile list
|
||||
int lastOpIndex = tileQueue->last;
|
||||
device mg_mtl_tile_op* lastOp = &tileOpBuffer[lastOpIndex];
|
||||
*nextLink = firstOpIndex;
|
||||
nextLink = &lastOp->next;
|
||||
|
||||
|
||||
//NOTE: add path end op
|
||||
int endOpIndex = atomic_fetch_add_explicit(tileOpCount, 1, memory_order_relaxed);
|
||||
device mg_mtl_tile_op* endOp = &tileOpBuffer[endOpIndex];
|
||||
endOp->kind = MG_MTL_OP_END;
|
||||
endOp->next = -1;
|
||||
endOp->index = pathIndex;
|
||||
|
||||
*nextLink = endOpIndex;
|
||||
nextLink = &endOp->next;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1445,9 +1466,6 @@ kernel void mtl_raster(const device int* screenTilesBuffer [[buffer(0)]],
|
|||
int nTilesX = (int(gridSize.x) + tileSize[0] - 1)/tileSize[0];
|
||||
int tileIndex = tileCoord.y * nTilesX + tileCoord.x;
|
||||
|
||||
int pathIndex = 0;
|
||||
int opIndex = screenTilesBuffer[tileIndex];
|
||||
|
||||
const int MG_MTL_MAX_SAMPLE_COUNT = 8;
|
||||
float2 sampleCoords[MG_MTL_MAX_SAMPLE_COUNT];
|
||||
int sampleCount = sampleCountBuffer[0];
|
||||
|
@ -1471,50 +1489,30 @@ kernel void mtl_raster(const device int* screenTilesBuffer [[buffer(0)]],
|
|||
sampleCoords[0] = centerCoord;
|
||||
}
|
||||
|
||||
float4 color[MG_MTL_MAX_SAMPLE_COUNT] = {0};
|
||||
const int MG_MTL_MAX_SRC_SAMPLE_COUNT = 4;
|
||||
const int srcSampleCount = 2;
|
||||
|
||||
const float2 imgSampleCoords[MG_MTL_MAX_SRC_SAMPLE_COUNT] = {
|
||||
centerCoord + float2(-0.25, 0.25),
|
||||
centerCoord + float2(+0.25, +0.25),
|
||||
centerCoord + float2(+0.25, -0.25),
|
||||
centerCoord + float2(-0.25, +0.25)};
|
||||
|
||||
float4 color = {0};
|
||||
int winding[MG_MTL_MAX_SAMPLE_COUNT] = {0};
|
||||
int opIndex = screenTilesBuffer[tileIndex];
|
||||
|
||||
while(opIndex != -1)
|
||||
{
|
||||
const device mg_mtl_tile_op* op = &tileOpBuffer[opIndex];
|
||||
int pathIndex = op->index;
|
||||
|
||||
if(op->kind == MG_MTL_OP_START)
|
||||
{
|
||||
float4 pathColor = pathBuffer[pathIndex].color;
|
||||
pathColor.rgb *= pathColor.a;
|
||||
|
||||
for(int sampleIndex=0; sampleIndex<sampleCount; sampleIndex++)
|
||||
{
|
||||
float2 sampleCoord = sampleCoords[sampleIndex];
|
||||
float4 clip = pathBuffer[pathIndex].clip * scale[0];
|
||||
|
||||
if( sampleCoord.x >= clip.x
|
||||
&& sampleCoord.x < clip.z
|
||||
&& sampleCoord.y >= clip.y
|
||||
&& sampleCoord.y < clip.w)
|
||||
{
|
||||
bool filled = (pathBuffer[pathIndex].cmd == MG_MTL_FILL && (winding[sampleIndex] & 1))
|
||||
||(pathBuffer[pathIndex].cmd == MG_MTL_STROKE && (winding[sampleIndex] != 0));
|
||||
if(filled)
|
||||
{
|
||||
float4 nextColor = pathColor;
|
||||
if(useTexture[0])
|
||||
{
|
||||
float3 ph = float3(sampleCoords[sampleIndex].xy, 1);
|
||||
float2 uv = (pathBuffer[pathIndex].uvTransform * ph).xy;
|
||||
|
||||
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
|
||||
float4 texColor = srcTexture.sample(smp, uv);
|
||||
texColor.rgb *= texColor.a;
|
||||
|
||||
nextColor *= texColor;
|
||||
}
|
||||
color[sampleIndex] = color[sampleIndex]*(1-nextColor.a) + nextColor;
|
||||
}
|
||||
}
|
||||
winding[sampleIndex] = op->windingOffset;
|
||||
}
|
||||
pathIndex = op->index;
|
||||
}
|
||||
else if(op->kind == MG_MTL_OP_SEGMENT)
|
||||
{
|
||||
|
@ -1524,7 +1522,6 @@ kernel void mtl_raster(const device int* screenTilesBuffer [[buffer(0)]],
|
|||
{
|
||||
float2 sampleCoord = sampleCoords[sampleIndex];
|
||||
|
||||
//TODO: shouldn't this be redundant with mtl_side_of_segment()?
|
||||
if( (sampleCoord.y > seg->box.y)
|
||||
&&(sampleCoord.y <= seg->box.w)
|
||||
&&(mtl_side_of_segment(sampleCoord, seg) < 0))
|
||||
|
@ -1547,56 +1544,64 @@ kernel void mtl_raster(const device int* screenTilesBuffer [[buffer(0)]],
|
|||
}
|
||||
}
|
||||
}
|
||||
opIndex = op->next;
|
||||
else
|
||||
{
|
||||
float4 nextColor = pathBuffer[pathIndex].color;
|
||||
nextColor.rgb *= nextColor.a;
|
||||
|
||||
if(useTexture[0])
|
||||
{
|
||||
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
|
||||
|
||||
float4 texColor = {0};
|
||||
for(int sampleIndex=0; sampleIndex<srcSampleCount; sampleIndex++)
|
||||
{
|
||||
float2 sampleCoord = imgSampleCoords[sampleIndex];
|
||||
float3 ph = float3(sampleCoord.xy, 1);
|
||||
float2 uv = (pathBuffer[pathIndex].uvTransform * ph).xy;
|
||||
|
||||
texColor += srcTexture.sample(smp, uv);
|
||||
}
|
||||
texColor /= srcSampleCount;
|
||||
texColor.rgb *= texColor.a;
|
||||
nextColor *= texColor;
|
||||
}
|
||||
|
||||
float4 pixelColor = float4(0, 0, 0, 0);
|
||||
float4 pathColor = pathBuffer[pathIndex].color;
|
||||
pathColor.rgb *= pathColor.a;
|
||||
if(op->kind == MG_MTL_OP_FILL)
|
||||
{
|
||||
color = color*(1-nextColor.a) + nextColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
float4 clip = pathBuffer[pathIndex].clip * scale[0];
|
||||
float coverage = 0;
|
||||
|
||||
for(int sampleIndex=0; sampleIndex<sampleCount; sampleIndex++)
|
||||
{
|
||||
float2 sampleCoord = sampleCoords[sampleIndex];
|
||||
float4 clip = pathBuffer[pathIndex].clip * scale[0];
|
||||
|
||||
if( sampleCoord.x >= clip.x
|
||||
&& sampleCoord.x < clip.z
|
||||
&& sampleCoord.y >= clip.y
|
||||
&& sampleCoord.y < clip.w)
|
||||
{
|
||||
bool filled = (pathBuffer[pathIndex].cmd == MG_MTL_FILL && (winding[sampleIndex] & 1))
|
||||
bool filled = op->kind == MG_MTL_OP_CLIP_FILL
|
||||
||(pathBuffer[pathIndex].cmd == MG_MTL_FILL && (winding[sampleIndex] & 1))
|
||||
||(pathBuffer[pathIndex].cmd == MG_MTL_STROKE && (winding[sampleIndex] != 0));
|
||||
if(filled)
|
||||
{
|
||||
float4 nextColor = pathColor;
|
||||
if(useTexture[0])
|
||||
{
|
||||
float3 sampleCoord = float3(sampleCoords[sampleIndex].xy, 1);
|
||||
float2 uv = (pathBuffer[pathIndex].uvTransform * sampleCoord).xy;
|
||||
coverage++;
|
||||
}
|
||||
}
|
||||
}
|
||||
coverage /= sampleCount;
|
||||
color = coverage*(color*(1-nextColor.a) + nextColor) + (1-coverage)*color;
|
||||
}
|
||||
}
|
||||
opIndex = op->next;
|
||||
}
|
||||
|
||||
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
|
||||
float4 texColor = srcTexture.sample(smp, uv);
|
||||
texColor.rgb *= texColor.a;
|
||||
|
||||
nextColor *= texColor;
|
||||
}
|
||||
color[sampleIndex] = color[sampleIndex]*(1-nextColor.a) + nextColor;
|
||||
}
|
||||
}
|
||||
pixelColor += color[sampleIndex];
|
||||
}
|
||||
pixelColor /= sampleCount;
|
||||
|
||||
/*
|
||||
if( (int(pixelCoord.x) % tileSize[0] == 0)
|
||||
||(int(pixelCoord.y) % tileSize[0] == 0))
|
||||
{
|
||||
outTexture.write(float4(0, 0, 0, 1), uint2(pixelCoord));
|
||||
return;
|
||||
}
|
||||
//*/
|
||||
|
||||
outTexture.write(pixelColor, pixelCoord);
|
||||
outTexture.write(color, pixelCoord);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue