From 7fbc4ba27077b5955788af8cf02d7e0be4763c64 Mon Sep 17 00:00:00 2001 From: martinfouilleul Date: Wed, 8 Feb 2023 12:59:31 +0100 Subject: [PATCH] canvas renderer: Use clip rects to cull tiles/pixels in tiling and drawing passes --- examples/win_canvas/main.c | 8 +++++++- src/gles_canvas_shaders/gles_canvas_draw.glsl | 17 +++++++++++++---- src/gles_canvas_shaders/gles_canvas_tile.glsl | 15 +++++++++++---- src/graphics.c | 7 ++++++- src/metal_shader.metal | 4 ++-- todo.txt | 6 +++++- 6 files changed, 44 insertions(+), 13 deletions(-) diff --git a/examples/win_canvas/main.c b/examples/win_canvas/main.c index c84449e..3224366 100644 --- a/examples/win_canvas/main.c +++ b/examples/win_canvas/main.c @@ -178,10 +178,16 @@ int main() mg_set_color_rgba(0, 1, 1, 1); mg_clear(); +// mg_clip_push(100, 100, contentRect.w - 200, contentRect.h - 200); // head mg_set_color_rgba(1, 1, 0, 1); mg_circle_fill(x, y, 200); - +/* + mg_clip_pop(); + mg_set_width(2); + mg_set_color_rgba(1, 0, 0, 1); + mg_rectangle_stroke(100, 100, contentRect.w - 200, contentRect.h - 200); +*/ // smile f32 frown = frameTime > 0.033 ? 100 : 0; diff --git a/src/gles_canvas_shaders/gles_canvas_draw.glsl b/src/gles_canvas_shaders/gles_canvas_draw.glsl index 43ccd90..b6024f6 100644 --- a/src/gles_canvas_shaders/gles_canvas_draw.glsl +++ b/src/gles_canvas_shaders/gles_canvas_draw.glsl @@ -64,7 +64,7 @@ void main() uint tileCounter = tileCounterBuffer.elements[tileIndex]; const float subPixelFactor = 16.; - ivec2 centerPoint = ivec2(round((vec2(pixelCoord) + vec2(0.5, 0.5)) * subPixelFactor)); + ivec2 centerPoint = ivec2((vec2(pixelCoord) + vec2(0.5, 0.5)) * subPixelFactor); //* const int sampleCount = 8; @@ -132,12 +132,13 @@ void main() uint i1 = indexBuffer.elements[triangleIndex+1u]; uint i2 = indexBuffer.elements[triangleIndex+2u]; - ivec2 p0 = ivec2(vertexBuffer.elements[i0].pos * subPixelFactor + vec2(0.5, 0.5)); - ivec2 p1 = ivec2(vertexBuffer.elements[i1].pos * subPixelFactor + vec2(0.5, 0.5)); - ivec2 p2 = ivec2(vertexBuffer.elements[i2].pos * subPixelFactor + vec2(0.5, 0.5)); + ivec2 p0 = ivec2((vertexBuffer.elements[i0].pos) * subPixelFactor); + ivec2 p1 = ivec2((vertexBuffer.elements[i1].pos) * subPixelFactor); + ivec2 p2 = ivec2((vertexBuffer.elements[i2].pos) * subPixelFactor); int zIndex = vertexBuffer.elements[i0].zIndex; vec4 color = shapeBuffer.elements[zIndex].color; + ivec4 clip = ivec4(round((shapeBuffer.elements[zIndex].clip + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor)); //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge int cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x; @@ -164,6 +165,14 @@ void main() { ivec2 samplePoint = samplePoints[sampleIndex]; + if( samplePoint.x < clip.x + || samplePoint.x > clip.z + || samplePoint.y < clip.y + || samplePoint.y > clip.w) + { + continue; + } + int w0 = orient2d(p1, p2, samplePoint); int w1 = orient2d(p2, p0, samplePoint); int w2 = orient2d(p0, p1, samplePoint); diff --git a/src/gles_canvas_shaders/gles_canvas_tile.glsl b/src/gles_canvas_shaders/gles_canvas_tile.glsl index 3342898..f14d952 100644 --- a/src/gles_canvas_shaders/gles_canvas_tile.glsl +++ b/src/gles_canvas_shaders/gles_canvas_tile.glsl @@ -57,11 +57,18 @@ void main() vec2 p1 = vertexBuffer.elements[i1].pos; vec2 p2 = vertexBuffer.elements[i2].pos; - vec4 fbox = vec4(min(min(p0.x, p1.x), p2.x), - min(min(p0.y, p1.y), p2.y), - max(max(p0.x, p1.x), p2.x), - max(max(p0.y, p1.y), p2.y)); + int shapeIndex = vertexBuffer.elements[i0].zIndex; + vec4 clip = shapeBuffer.elements[shapeIndex].clip; + vec4 fbox = vec4(max(min(min(p0.x, p1.x), p2.x), clip.x), + max(min(min(p0.y, p1.y), p2.y), clip.y), + min(max(max(p0.x, p1.x), p2.x), clip.z), + min(max(max(p0.y, p1.y), p2.y), clip.w)); + +/* + fbox.xy = min(fbox.xy, clip.xy); + fbox.zw = max(fbox.zw, clip.zw); +*/ uvec4 box = uvec4(floor(fbox))/tileSize; uint xMin = max(0u, box.x); diff --git a/src/graphics.c b/src/graphics.c index 26aa1a6..2bc14c0 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -446,11 +446,16 @@ u32 mg_next_shape_textured(mg_canvas_data* canvas, vec2 uv, mg_color color) int index = canvas->nextZIndex; canvas->nextZIndex++; + mp_rect clip = {canvas->clip.x, + canvas->clip.y, + canvas->clip.x + canvas->clip.w - 1, + canvas->clip.y + canvas->clip.h - 1}; + mg_vertex_layout* layout = &canvas->backend->vertexLayout; *(vec2*)(((char*)layout->uvBuffer) + index*layout->uvStride) = uv; *(mg_color*)(((char*)layout->colorBuffer) + index*layout->colorStride) = color; - *(mp_rect*)(((char*)layout->clipBuffer) + index*layout->clipStride) = canvas->clip; + *(mp_rect*)(((char*)layout->clipBuffer) + index*layout->clipStride) = clip; return(index); } diff --git a/src/metal_shader.metal b/src/metal_shader.metal index a9ac950..79e238a 100644 --- a/src/metal_shader.metal +++ b/src/metal_shader.metal @@ -64,8 +64,8 @@ kernel void BoundingBoxKernel(constant mg_vertex* vertexBuffer [[buffer(0)]], float2 clipMax(clip.x + clip.z-1, clip.y + clip.w-1); //NOTE(martin): intersect with current clip - boxMin = max(boxMin, clipMin); - boxMax = min(boxMax, clipMax); + boxMin = max(boxMin, clip.xy); + boxMax = min(boxMax, clip.zw); //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x; diff --git a/todo.txt b/todo.txt index 1561ea8..0f00ba9 100644 --- a/todo.txt +++ b/todo.txt @@ -6,12 +6,16 @@ Canvas renderer perf [?] use half-floats or short fixed-point for pos and uv, packing them in two ints [?] pre-compute triangle edges/bounding boxes? +[!] Investigate artifact when shifting positions of vertices by (0.5, 0.5) before multiplying + by subpixel precision and truncating... -> ie sampling at the middle of pixels vs at integer coordinates... + [ ] What alignment gives crisp-ier lines? + [>] Add surface scaling for high dpi surfaces [x] Allow setting swap interval [!] Allow swap interval of 0 on macos -[>] Use clip rects in tiling/drawing pass +[x] Use clip rects in tiling/drawing pass [ ] Clean canvas code [ ] make zIndex implicit when calling push_vertex