[wip, win32, canvas] tiling in per-path tile queues, then merge (no backprop for now)
This commit is contained in:
parent
f0b7cf32a9
commit
7628138cee
|
@ -127,9 +127,7 @@ typedef struct mg_gl_canvas_backend
|
||||||
GLuint pathSetup;
|
GLuint pathSetup;
|
||||||
GLuint segmentSetup;
|
GLuint segmentSetup;
|
||||||
GLuint backprop;
|
GLuint backprop;
|
||||||
/*
|
|
||||||
GLuint merge;
|
GLuint merge;
|
||||||
*/
|
|
||||||
GLuint raster;
|
GLuint raster;
|
||||||
GLuint blit;
|
GLuint blit;
|
||||||
|
|
||||||
|
@ -245,12 +243,15 @@ void mg_gl_render_batch(mg_gl_canvas_backend* backend,
|
||||||
//NOTE: path setup pass
|
//NOTE: path setup pass
|
||||||
glUseProgram(backend->pathSetup);
|
glUseProgram(backend->pathSetup);
|
||||||
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->tileQueueBuffer);
|
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, backend->pathBuffer, backend->pathBufferOffset, pathCount*sizeof(mg_gl_path));
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->pathQueueBuffer);
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->tileQueueCountBuffer);
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileQueueBuffer);
|
||||||
|
|
||||||
// glUniform1i(0, tileSize);
|
glUniform1i(0, tileSize);
|
||||||
// glUniform1f(1, scale);
|
glUniform1f(1, scale);
|
||||||
|
|
||||||
glDispatchCompute(nTilesX, nTilesY, 1);
|
glDispatchCompute(pathCount, 1, 1);
|
||||||
|
|
||||||
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||||
|
|
||||||
|
@ -260,19 +261,19 @@ void mg_gl_render_batch(mg_gl_canvas_backend* backend,
|
||||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, backend->elementBuffer, backend->elementBufferOffset, eltCount*sizeof(mg_gl_path_elt));
|
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, backend->elementBuffer, backend->elementBufferOffset, eltCount*sizeof(mg_gl_path_elt));
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->segmentCountBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->segmentCountBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->segmentBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->segmentBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileOpCountBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->pathQueueBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, backend->tileOpBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, backend->tileQueueBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, backend->tileQueueBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, backend->tileOpCountBuffer);
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, backend->tileOpBuffer);
|
||||||
|
|
||||||
glUniform1f(0, scale);
|
glUniform1f(0, scale);
|
||||||
glUniform1ui(1, tileSize);
|
glUniform1ui(1, tileSize);
|
||||||
glUniform2i(2, nTilesX, nTilesY);
|
|
||||||
|
|
||||||
glDispatchCompute(eltCount, 1, 1);
|
glDispatchCompute(eltCount, 1, 1);
|
||||||
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||||
|
|
||||||
//NOTE: backprop pass
|
//NOTE: backprop pass
|
||||||
|
/*
|
||||||
glUseProgram(backend->backprop);
|
glUseProgram(backend->backprop);
|
||||||
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->tileQueueBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->tileQueueBuffer);
|
||||||
|
@ -281,23 +282,24 @@ void mg_gl_render_batch(mg_gl_canvas_backend* backend,
|
||||||
|
|
||||||
glDispatchCompute(nTilesY, 1, 1);
|
glDispatchCompute(nTilesY, 1, 1);
|
||||||
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
//NOTE: merge pass
|
//NOTE: merge pass
|
||||||
glUseProgram(backend->merge);
|
glUseProgram(backend->merge);
|
||||||
|
|
||||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, backend->pathBuffer, backend->pathBufferOffset, pathCount*sizeof(mg_gl_path));
|
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, backend->pathBuffer, backend->pathBufferOffset, pathCount*sizeof(mg_gl_path));
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->pathQueueBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->pathQueueBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->tileQueueBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->tileQueueBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileOpBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileOpCountBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, backend->tileOpCountBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, backend->tileOpBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, backend->screenTilesBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, backend->screenTilesBuffer);
|
||||||
|
|
||||||
glUniform1i(0, tileSize);
|
glUniform1i(0, tileSize);
|
||||||
glUniform1f(1, scale);
|
glUniform1f(1, scale);
|
||||||
|
glUniform1i(2, pathCount);
|
||||||
|
|
||||||
glDispatchCompute(nTilesX, nTilesY, 1);
|
glDispatchCompute(nTilesX, nTilesY, 1);
|
||||||
*/
|
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||||
|
|
||||||
//NOTE: raster pass
|
//NOTE: raster pass
|
||||||
glUseProgram(backend->raster);
|
glUseProgram(backend->raster);
|
||||||
|
@ -314,11 +316,10 @@ void mg_gl_render_batch(mg_gl_canvas_backend* backend,
|
||||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, backend->pathBuffer, backend->pathBufferOffset, pathCount*sizeof(mg_gl_path));
|
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, backend->pathBuffer, backend->pathBufferOffset, pathCount*sizeof(mg_gl_path));
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->segmentCountBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->segmentCountBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->segmentBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->segmentBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileQueueBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileOpBuffer);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, backend->tileOpBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, backend->screenTilesBuffer);
|
||||||
|
|
||||||
// glUniform1ui(0, tileSize);
|
glUniform1f(0, scale);
|
||||||
// glUniform1f(1, scale);
|
|
||||||
|
|
||||||
int err = glGetError();
|
int err = glGetError();
|
||||||
if(err)
|
if(err)
|
||||||
|
@ -751,9 +752,7 @@ mg_canvas_backend* gl_canvas_backend_create(mg_wgl_surface* surface)
|
||||||
err |= mg_gl_canvas_compile_compute_program(glsl_path_setup, &backend->pathSetup);
|
err |= mg_gl_canvas_compile_compute_program(glsl_path_setup, &backend->pathSetup);
|
||||||
err |= mg_gl_canvas_compile_compute_program(glsl_segment_setup, &backend->segmentSetup);
|
err |= mg_gl_canvas_compile_compute_program(glsl_segment_setup, &backend->segmentSetup);
|
||||||
err |= mg_gl_canvas_compile_compute_program(glsl_backprop, &backend->backprop);
|
err |= mg_gl_canvas_compile_compute_program(glsl_backprop, &backend->backprop);
|
||||||
/*
|
|
||||||
err |= mg_gl_canvas_compile_compute_program(glsl_merge, &backend->merge);
|
err |= mg_gl_canvas_compile_compute_program(glsl_merge, &backend->merge);
|
||||||
*/
|
|
||||||
err |= mg_gl_canvas_compile_compute_program(glsl_raster, &backend->raster);
|
err |= mg_gl_canvas_compile_compute_program(glsl_raster, &backend->raster);
|
||||||
err |= mg_gl_canvas_compile_render_program("blit", glsl_blit_vertex, glsl_blit_fragment, &backend->blit);
|
err |= mg_gl_canvas_compile_render_program("blit", glsl_blit_vertex, glsl_blit_fragment, &backend->blit);
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ struct mg_gl_segment
|
||||||
|
|
||||||
struct mg_gl_path_queue
|
struct mg_gl_path_queue
|
||||||
{
|
{
|
||||||
vec4 area;
|
ivec4 area;
|
||||||
int tileQueues;
|
int tileQueues;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,23 +19,116 @@ layout(binding = 2) restrict readonly buffer tileQueueBufferSSBO
|
||||||
mg_gl_tile_queue elements[];
|
mg_gl_tile_queue elements[];
|
||||||
} tileQueueBuffer;
|
} tileQueueBuffer;
|
||||||
|
|
||||||
layout(binding = 3) restrict readonly buffer tileOpBufferSSBO
|
layout(binding = 3) coherent restrict buffer tileOpCountBufferSSBO
|
||||||
{
|
|
||||||
mg_gl_tile_op elements[];
|
|
||||||
} tileOpBuffer;
|
|
||||||
|
|
||||||
layout(binding = 4) restrict readonly buffer tileOpCountBufferSSBO
|
|
||||||
{
|
{
|
||||||
int elements[];
|
int elements[];
|
||||||
} tileOpCountBuffer;
|
} tileOpCountBuffer;
|
||||||
|
|
||||||
layout(binding = 5) restrict readonly buffer screenTilesBufferSSBO
|
layout(binding = 4) restrict buffer tileOpBufferSSBO
|
||||||
{
|
{
|
||||||
mg_gl_tile_queue elements[];
|
mg_gl_tile_op elements[];
|
||||||
|
} tileOpBuffer;
|
||||||
|
|
||||||
|
layout(binding = 5) restrict writeonly buffer screenTilesBufferSSBO
|
||||||
|
{
|
||||||
|
int elements[];
|
||||||
} screenTilesBuffer;
|
} screenTilesBuffer;
|
||||||
|
|
||||||
|
layout(location = 0) uniform int tileSize;
|
||||||
|
layout(location = 1) uniform float scale;
|
||||||
|
layout(location = 2) uniform int pathCount;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
ivec2 nTiles = ivec2(gl_NumWorkGroups.xy);
|
||||||
|
ivec2 tileCoord = ivec2(gl_WorkGroupID.xy);
|
||||||
|
int tileIndex = tileCoord.y * nTiles.x + tileCoord.x;
|
||||||
|
|
||||||
|
screenTilesBuffer.elements[tileIndex] = -1;
|
||||||
|
|
||||||
|
int lastOpIndex = -1;
|
||||||
|
|
||||||
|
for(int pathIndex = 0; pathIndex < pathCount; pathIndex++)
|
||||||
|
{
|
||||||
|
mg_gl_path_queue pathQueue = pathQueueBuffer.elements[pathIndex];
|
||||||
|
ivec2 pathTileCoord = tileCoord - pathQueue.area.xy;
|
||||||
|
|
||||||
|
vec4 pathBox = pathBuffer.elements[pathIndex].box;
|
||||||
|
vec4 pathClip = pathBuffer.elements[pathIndex].clip;
|
||||||
|
|
||||||
|
float xMax = min(pathBox.z, pathClip.z);
|
||||||
|
int tileMax = int(xMax * scale) / tileSize;
|
||||||
|
int pathTileMax = tileMax - pathQueue.area.x;
|
||||||
|
|
||||||
|
if( pathTileCoord.x >= 0
|
||||||
|
&& pathTileCoord.x <= pathTileMax
|
||||||
|
&& pathTileCoord.y >= 0
|
||||||
|
&& pathTileCoord.y < pathQueue.area.w)
|
||||||
|
{
|
||||||
|
int pathTileIndex = pathQueue.tileQueues + pathTileCoord.y * pathQueue.area.z + pathTileCoord.x;
|
||||||
|
mg_gl_tile_queue tileQueue = tileQueueBuffer.elements[pathTileIndex];
|
||||||
|
|
||||||
|
int windingOffset = tileQueue.windingOffset;
|
||||||
|
int firstOpIndex = tileQueue.first;
|
||||||
|
|
||||||
|
if(firstOpIndex == -1)
|
||||||
|
{
|
||||||
|
if((windingOffset & 1) != 0)
|
||||||
|
{
|
||||||
|
//NOTE: tile is full covered. Add path start op (with winding offset).
|
||||||
|
// Additionally if color is opaque and tile is fully inside clip, trim tile list.
|
||||||
|
int pathOpIndex = atomicAdd(tileOpCountBuffer.elements[0], 1);
|
||||||
|
|
||||||
|
tileOpBuffer.elements[pathOpIndex].kind = MG_GL_OP_START;
|
||||||
|
tileOpBuffer.elements[pathOpIndex].next = -1;
|
||||||
|
tileOpBuffer.elements[pathOpIndex].index = pathIndex;
|
||||||
|
tileOpBuffer.elements[pathOpIndex].windingOffset = windingOffset;
|
||||||
|
|
||||||
|
vec4 clip = pathBuffer.elements[pathIndex].clip * scale;
|
||||||
|
vec4 tileBox = vec4(tileCoord.x, tileCoord.y, tileCoord.x+1, tileCoord.y+1);
|
||||||
|
tileBox *= tileSize;
|
||||||
|
|
||||||
|
if( lastOpIndex < 0
|
||||||
|
||(pathBuffer.elements[pathIndex].color.a == 1
|
||||||
|
&& tileBox.x >= clip.x
|
||||||
|
&& tileBox.z < clip.z
|
||||||
|
&& tileBox.y >= clip.y
|
||||||
|
&& tileBox.w < clip.w))
|
||||||
|
{
|
||||||
|
screenTilesBuffer.elements[tileIndex] = pathOpIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tileOpBuffer.elements[lastOpIndex].next = pathOpIndex;
|
||||||
|
}
|
||||||
|
lastOpIndex = pathOpIndex;
|
||||||
|
}
|
||||||
|
// else, tile is fully uncovered, skip path
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//NOTE: add path start op (with winding offset)
|
||||||
|
int pathOpIndex = atomicAdd(tileOpCountBuffer.elements[0], 1);
|
||||||
|
|
||||||
|
tileOpBuffer.elements[pathOpIndex].kind = MG_GL_OP_START;
|
||||||
|
tileOpBuffer.elements[pathOpIndex].next = -1;
|
||||||
|
tileOpBuffer.elements[pathOpIndex].index = pathIndex;
|
||||||
|
tileOpBuffer.elements[pathOpIndex].windingOffset = windingOffset;
|
||||||
|
|
||||||
|
if(lastOpIndex < 0)
|
||||||
|
{
|
||||||
|
screenTilesBuffer.elements[tileIndex] = pathOpIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tileOpBuffer.elements[lastOpIndex].next = pathOpIndex;
|
||||||
|
}
|
||||||
|
lastOpIndex = pathOpIndex;
|
||||||
|
|
||||||
|
//NOTE: chain remaining path ops to end of tile list
|
||||||
|
tileOpBuffer.elements[lastOpIndex].next = firstOpIndex;
|
||||||
|
lastOpIndex = tileQueue.last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,57 @@ layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
layout(std430) buffer;
|
layout(std430) buffer;
|
||||||
|
|
||||||
layout(binding = 0) restrict writeonly buffer tileQueueBufferSSBO
|
layout(binding = 0) restrict readonly buffer pathBufferSSBO
|
||||||
|
{
|
||||||
|
mg_gl_path elements[];
|
||||||
|
} pathBuffer;
|
||||||
|
|
||||||
|
layout(binding = 1) restrict writeonly buffer pathQueueBufferSSBO
|
||||||
|
{
|
||||||
|
mg_gl_path_queue elements[];
|
||||||
|
} pathQueueBuffer;
|
||||||
|
|
||||||
|
layout(binding = 2) coherent restrict buffer tileQueueCountBufferSSBO
|
||||||
|
{
|
||||||
|
int elements[];
|
||||||
|
} tileQueueCountBuffer;
|
||||||
|
|
||||||
|
layout(binding = 3) restrict writeonly buffer tileQueueBufferSSBO
|
||||||
{
|
{
|
||||||
mg_gl_tile_queue elements[];
|
mg_gl_tile_queue elements[];
|
||||||
} tileQueueBuffer;
|
} tileQueueBuffer;
|
||||||
|
|
||||||
|
layout(location = 0) uniform int tileSize;
|
||||||
|
layout(location = 1) uniform float scale;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
uvec2 nTiles = gl_NumWorkGroups.xy;
|
uint pathIndex = gl_WorkGroupID.x;
|
||||||
uvec2 tileCoord = gl_WorkGroupID.xy;
|
const mg_gl_path path = pathBuffer.elements[pathIndex];
|
||||||
uint tileIndex = tileCoord.y * nTiles.x + tileCoord.x;
|
|
||||||
|
|
||||||
tileQueueBuffer.elements[tileIndex].windingOffset = 0;
|
//NOTE: we don't clip on the right, since we need those tiles to accurately compute
|
||||||
tileQueueBuffer.elements[tileIndex].first = -1;
|
// the prefix sum of winding increments in the backprop pass.
|
||||||
tileQueueBuffer.elements[tileIndex].last = -1;
|
vec4 clippedBox = vec4(max(path.box.x, path.clip.x),
|
||||||
|
max(path.box.y, path.clip.y),
|
||||||
|
path.box.z,
|
||||||
|
min(path.box.w, path.clip.w));
|
||||||
|
|
||||||
|
ivec2 firstTile = ivec2(clippedBox.xy*scale)/tileSize;
|
||||||
|
ivec2 lastTile = ivec2(clippedBox.zw*scale)/tileSize;
|
||||||
|
|
||||||
|
int nTilesX = max(0, lastTile.x - firstTile.x + 1);
|
||||||
|
int nTilesY = max(0, lastTile.y - firstTile.y + 1);
|
||||||
|
int tileCount = nTilesX * nTilesY;
|
||||||
|
|
||||||
|
int tileQueuesIndex = atomicAdd(tileQueueCountBuffer.elements[0], tileCount);
|
||||||
|
|
||||||
|
pathQueueBuffer.elements[pathIndex].area = ivec4(firstTile.x, firstTile.y, nTilesX, nTilesY);
|
||||||
|
pathQueueBuffer.elements[pathIndex].tileQueues = tileQueuesIndex;
|
||||||
|
|
||||||
|
for(int i=0; i<tileCount; i++)
|
||||||
|
{
|
||||||
|
tileQueueBuffer.elements[tileQueuesIndex + i].first = -1;
|
||||||
|
tileQueueBuffer.elements[tileQueuesIndex + i].last = -1;
|
||||||
|
tileQueueBuffer.elements[tileQueuesIndex + i].windingOffset = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ layout(binding = 0) restrict readonly buffer pathBufferSSBO
|
||||||
mg_gl_path elements[];
|
mg_gl_path elements[];
|
||||||
} pathBuffer;
|
} pathBuffer;
|
||||||
|
|
||||||
layout(binding = 1) restrict readonly buffer segmentBufferCountSSBO
|
layout(binding = 1) restrict readonly buffer segmentCountBufferSSBO
|
||||||
{
|
{
|
||||||
int elements[];
|
int elements[];
|
||||||
} segmentCountBuffer;
|
} segmentCountBuffer;
|
||||||
|
@ -19,19 +19,17 @@ layout(binding = 2) restrict readonly buffer segmentBufferSSBO
|
||||||
mg_gl_segment elements[];
|
mg_gl_segment elements[];
|
||||||
} segmentBuffer;
|
} segmentBuffer;
|
||||||
|
|
||||||
layout(binding = 3) restrict readonly buffer tileQueuesBufferSSBO
|
layout(binding = 3) restrict readonly buffer tileOpBufferSSBO
|
||||||
{
|
|
||||||
mg_gl_tile_queue elements[];
|
|
||||||
} tileQueuesBuffer;
|
|
||||||
|
|
||||||
layout(binding = 4) restrict readonly buffer tileOpBufferSSBO
|
|
||||||
{
|
{
|
||||||
mg_gl_tile_op elements[];
|
mg_gl_tile_op elements[];
|
||||||
} tileOpBuffer;
|
} tileOpBuffer;
|
||||||
|
|
||||||
|
layout(binding = 4) restrict readonly buffer screenTilesBufferSSBO
|
||||||
|
{
|
||||||
|
int elements[];
|
||||||
|
} screenTilesBuffer;
|
||||||
|
|
||||||
//layout(location = 0) uniform uint tileSize; // this has to be commented until it's effectively used!!
|
layout(location = 0) uniform float scale;
|
||||||
//layout(location = 0) uniform float scale;
|
|
||||||
|
|
||||||
layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;
|
layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;
|
||||||
|
|
||||||
|
@ -139,12 +137,10 @@ void main()
|
||||||
ivec2 pixelCoord = ivec2(gl_WorkGroupID.xy*uvec2(16, 16) + gl_LocalInvocationID.xy);
|
ivec2 pixelCoord = ivec2(gl_WorkGroupID.xy*uvec2(16, 16) + gl_LocalInvocationID.xy);
|
||||||
vec2 sampleCoord = vec2(pixelCoord);
|
vec2 sampleCoord = vec2(pixelCoord);
|
||||||
|
|
||||||
|
int pathIndex = 0;
|
||||||
imageStore(outTexture, ivec2(sampleCoord), vec4(1, 1, 1, 1));
|
int opIndex = screenTilesBuffer.elements[tileIndex];
|
||||||
|
int winding = 0;
|
||||||
mg_gl_tile_queue tileQueue = tileQueuesBuffer.elements[tileIndex];
|
vec4 color = vec4(0);
|
||||||
int opIndex = tileQueue.first;
|
|
||||||
int winding = tileQueue.windingOffset;
|
|
||||||
|
|
||||||
if((pixelCoord.x % 16) == 0 || (pixelCoord.y % 16) == 0)
|
if((pixelCoord.x % 16) == 0 || (pixelCoord.y % 16) == 0)
|
||||||
{
|
{
|
||||||
|
@ -152,7 +148,6 @@ void main()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int opCount = 0;
|
|
||||||
while(opIndex >= 0)
|
while(opIndex >= 0)
|
||||||
{
|
{
|
||||||
//imageStore(outTexture, ivec2(sampleCoord), vec4(0, 1, 0, 1));
|
//imageStore(outTexture, ivec2(sampleCoord), vec4(0, 1, 0, 1));
|
||||||
|
@ -161,7 +156,30 @@ void main()
|
||||||
mg_gl_tile_op op = tileOpBuffer.elements[opIndex];
|
mg_gl_tile_op op = tileOpBuffer.elements[opIndex];
|
||||||
opIndex = op.next;
|
opIndex = op.next;
|
||||||
|
|
||||||
if(op.kind == MG_GL_OP_SEGMENT)
|
if(op.kind == MG_GL_OP_START)
|
||||||
|
{
|
||||||
|
vec4 pathColor = pathBuffer.elements[pathIndex].color;
|
||||||
|
pathColor.rgb *= pathColor.a;
|
||||||
|
|
||||||
|
vec4 clip = pathBuffer.elements[pathIndex].clip * scale;
|
||||||
|
|
||||||
|
if( sampleCoord.x >= clip.x
|
||||||
|
&& sampleCoord.x < clip.z
|
||||||
|
&& sampleCoord.y >= clip.y
|
||||||
|
&& sampleCoord.y < clip.w)
|
||||||
|
{
|
||||||
|
bool filled = (pathBuffer.elements[pathIndex].cmd == MG_GL_FILL && ((winding & 1) != 0))
|
||||||
|
||(pathBuffer.elements[pathIndex].cmd == MG_GL_STROKE && (winding != 0));
|
||||||
|
if(filled)
|
||||||
|
{
|
||||||
|
vec4 nextColor = pathColor;
|
||||||
|
color = color*(1-nextColor.a) + nextColor;
|
||||||
|
}
|
||||||
|
winding = op.windingOffset;
|
||||||
|
}
|
||||||
|
pathIndex = op.index;
|
||||||
|
}
|
||||||
|
else if(op.kind == MG_GL_OP_SEGMENT)
|
||||||
{
|
{
|
||||||
int segIndex = op.index;
|
int segIndex = op.index;
|
||||||
mg_gl_segment seg = segmentBuffer.elements[segIndex];
|
mg_gl_segment seg = segmentBuffer.elements[segIndex];
|
||||||
|
@ -188,24 +206,25 @@ void main()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int pathIndex = 0;
|
|
||||||
|
|
||||||
// vec4 clip = pathBuffer.elements[pathIndex].clip * scale;
|
vec4 pathColor = pathBuffer.elements[pathIndex].color;
|
||||||
|
pathColor.rgb *= pathColor.a;
|
||||||
|
|
||||||
/* if( sampleCoord.x >= clip.x
|
vec4 clip = pathBuffer.elements[pathIndex].clip * scale;
|
||||||
|
|
||||||
|
if( sampleCoord.x >= clip.x
|
||||||
&& sampleCoord.x < clip.z
|
&& sampleCoord.x < clip.z
|
||||||
&& sampleCoord.y >= clip.y
|
&& sampleCoord.y >= clip.y
|
||||||
&& sampleCoord.y < clip.w)
|
&& sampleCoord.y < clip.w)
|
||||||
*/ {
|
{
|
||||||
/*
|
bool filled = (pathBuffer.elements[pathIndex].cmd == MG_GL_FILL && ((winding & 1) != 0))
|
||||||
bool filled = (pathBuffer[pathIndex].cmd == MG_GL_FILL && (winding[sampleIndex] & 1))
|
||(pathBuffer.elements[pathIndex].cmd == MG_GL_STROKE && (winding != 0));
|
||||||
||(pathBuffer[pathIndex].cmd == MG_GL_STROKE && (winding[sampleIndex] != 0));
|
|
||||||
*/
|
|
||||||
bool filled = (winding & 1) != 0;
|
|
||||||
if(filled)
|
if(filled)
|
||||||
{
|
{
|
||||||
// write to texture
|
vec4 nextColor = pathColor;
|
||||||
imageStore(outTexture, ivec2(sampleCoord), vec4(1, 0, 0, 1));
|
color = color*(1-nextColor.a) + nextColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// write to texture
|
||||||
|
imageStore(outTexture, ivec2(sampleCoord), color);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,24 +19,28 @@ layout(binding = 2) restrict buffer segmentBufferSSBO
|
||||||
mg_gl_segment elements[];
|
mg_gl_segment elements[];
|
||||||
} segmentBuffer;
|
} segmentBuffer;
|
||||||
|
|
||||||
layout(binding = 3) coherent restrict buffer tileOpCountBufferSSBO
|
layout(binding = 3) restrict buffer pathQueueBufferSSBO
|
||||||
|
{
|
||||||
|
mg_gl_path_queue elements[];
|
||||||
|
} pathQueueBuffer;
|
||||||
|
|
||||||
|
layout(binding = 4) coherent restrict buffer tileQueueBufferSSBO
|
||||||
|
{
|
||||||
|
mg_gl_tile_queue elements[];
|
||||||
|
} tileQueueBuffer;
|
||||||
|
|
||||||
|
layout(binding = 5) coherent restrict buffer tileOpCountBufferSSBO
|
||||||
{
|
{
|
||||||
int elements[];
|
int elements[];
|
||||||
} tileOpCountBuffer;
|
} tileOpCountBuffer;
|
||||||
|
|
||||||
layout(binding = 4) restrict buffer tileOpBufferSSBO
|
layout(binding = 6) restrict buffer tileOpBufferSSBO
|
||||||
{
|
{
|
||||||
mg_gl_tile_op elements[];
|
mg_gl_tile_op elements[];
|
||||||
} tileOpBuffer;
|
} tileOpBuffer;
|
||||||
|
|
||||||
layout(binding = 5) coherent restrict buffer tileQueuesBufferSSBO
|
|
||||||
{
|
|
||||||
mg_gl_tile_queue elements[];
|
|
||||||
} tileQueuesBuffer;
|
|
||||||
|
|
||||||
layout(location = 0) uniform float scale;
|
layout(location = 0) uniform float scale;
|
||||||
layout(location = 1) uniform uint tileSize;
|
layout(location = 1) uniform uint tileSize;
|
||||||
layout(location = 2) uniform ivec2 nTiles;
|
|
||||||
|
|
||||||
int push_segment(in vec2 p[4], int kind)
|
int push_segment(in vec2 p[4], int kind)
|
||||||
{
|
{
|
||||||
|
@ -197,9 +201,9 @@ void bin_to_tiles(int segIndex)
|
||||||
{
|
{
|
||||||
//NOTE: add segment index to the queues of tiles it overlaps with
|
//NOTE: add segment index to the queues of tiles it overlaps with
|
||||||
const mg_gl_segment seg = segmentBuffer.elements[segIndex];
|
const mg_gl_segment seg = segmentBuffer.elements[segIndex];
|
||||||
|
const mg_gl_path_queue pathQueue = pathQueueBuffer.elements[seg.pathIndex];
|
||||||
|
|
||||||
ivec4 pathArea = ivec4(0, 0, nTiles.x, nTiles.y);
|
ivec4 pathArea = pathQueue.area;
|
||||||
|
|
||||||
ivec4 coveredTiles = ivec4(seg.box)/int(tileSize);
|
ivec4 coveredTiles = ivec4(seg.box)/int(tileSize);
|
||||||
int xMin = max(0, coveredTiles.x - pathArea.x);
|
int xMin = max(0, coveredTiles.x - pathArea.x);
|
||||||
int yMin = max(0, coveredTiles.y - pathArea.y);
|
int yMin = max(0, coveredTiles.y - pathArea.y);
|
||||||
|
@ -260,18 +264,18 @@ void bin_to_tiles(int segIndex)
|
||||||
tileOpBuffer.elements[tileOpIndex].crossRight = false;
|
tileOpBuffer.elements[tileOpIndex].crossRight = false;
|
||||||
tileOpBuffer.elements[tileOpIndex].next = -1;
|
tileOpBuffer.elements[tileOpIndex].next = -1;
|
||||||
|
|
||||||
int tileIndex = y*pathArea.z + x;
|
int tileQueueIndex = pathQueue.tileQueues + y*pathArea.z + x;
|
||||||
|
|
||||||
tileOpBuffer.elements[tileOpIndex].next = atomicExchange(tileQueuesBuffer.elements[tileIndex].first, tileOpIndex);
|
tileOpBuffer.elements[tileOpIndex].next = atomicExchange(tileQueueBuffer.elements[tileQueueIndex].first, tileOpIndex);
|
||||||
if(tileOpBuffer.elements[tileOpIndex].next == -1)
|
if(tileOpBuffer.elements[tileOpIndex].next == -1)
|
||||||
{
|
{
|
||||||
tileQueuesBuffer.elements[tileIndex].last = tileOpIndex;
|
tileQueueBuffer.elements[tileQueueIndex].last = tileOpIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: if the segment crosses the tile's bottom boundary, update the tile's winding offset
|
//NOTE: if the segment crosses the tile's bottom boundary, update the tile's winding offset
|
||||||
if(crossB)
|
if(crossB)
|
||||||
{
|
{
|
||||||
atomicAdd(tileQueuesBuffer.elements[tileIndex].windingOffset, seg.windingIncrement);
|
atomicAdd(tileQueueBuffer.elements[tileQueueIndex].windingOffset, seg.windingIncrement);
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: if the segment crosses the right boundary, mark it.
|
//NOTE: if the segment crosses the right boundary, mark it.
|
||||||
|
|
Loading…
Reference in New Issue