diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 731da97..39c07c6 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -148,12 +148,6 @@ void main() { uint part_start_ix = 0; uint ready_ix = 0; - // Leave room for the fine rasterizer scratch allocation. - Alloc scratch_alloc = slice_mem(cmd_alloc, 0, Alloc_size); - cmd_ref.offset += Alloc_size; - - uint num_begin_slots = 0; - uint begin_slot = 0; bool mem_ok = mem_error == NO_ERROR; while (true) { for (uint i = 0; i < N_SLICE; i++) { @@ -373,8 +367,6 @@ void main() { if (clip_depth < 32) { clip_one_mask &= ~(1 << clip_depth); } - begin_slot++; - num_begin_slots = max(num_begin_slots, begin_slot); } clip_depth++; break; @@ -386,7 +378,6 @@ void main() { } Cmd_Solid_write(cmd_alloc, cmd_ref); cmd_ref.offset += 4; - begin_slot--; Cmd_EndClip_write(cmd_alloc, cmd_ref); cmd_ref.offset += 4; } @@ -414,13 +405,5 @@ void main() { } if (bin_tile_x + tile_x < conf.width_in_tiles && bin_tile_y + tile_y < conf.height_in_tiles) { Cmd_End_write(cmd_alloc, cmd_ref); - if (num_begin_slots > 0) { - // Write scratch allocation: one state per BeginClip per rasterizer chunk. - uint scratch_size = num_begin_slots * TILE_WIDTH_PX * TILE_HEIGHT_PX * CLIP_STATE_SIZE * 4; - MallocResult scratch = malloc(scratch_size); - // Ignore scratch.failed; we don't use the allocation and kernel4 - // checks for memory overflow before using it. - alloc_write(scratch_alloc, scratch_alloc.offset, scratch.alloc); - } } } diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 5570675..4406d8f 100644 Binary files a/piet-gpu/shader/coarse.spv and b/piet-gpu/shader/coarse.spv differ diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index c613b72..61eedb9 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -37,6 +37,7 @@ layout(rgba8, set = 0, binding = 3) uniform restrict readonly image2D images[1]; #include "ptcl.h" #include "tile.h" +#define MAX_BLEND_STACK 128 mediump vec3 tosRGB(mediump vec3 rgb) { bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308)); mediump vec3 below = vec3(12.92)*rgb; @@ -90,13 +91,11 @@ void main() { Alloc cmd_alloc = slice_mem(conf.ptcl_alloc, tile_ix * PTCL_INITIAL_ALLOC, PTCL_INITIAL_ALLOC); CmdRef cmd_ref = CmdRef(cmd_alloc.offset); - // Read scrach space allocation, written first in the command list. - Alloc scratch_alloc = alloc_read(cmd_alloc, cmd_ref.offset); - cmd_ref.offset += Alloc_size; - uvec2 xy_uint = uvec2(gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_WorkGroupID.x, gl_LocalInvocationID.y + TILE_HEIGHT_PX * gl_WorkGroupID.y); vec2 xy = vec2(xy_uint); mediump vec4 rgba[CHUNK]; + uint blend_stack[MAX_BLEND_STACK][CHUNK]; + mediump float blend_alpha_stack[MAX_BLEND_STACK][CHUNK]; for (uint i = 0; i < CHUNK; i++) { rgba[i] = vec4(0.0); // TODO: remove this debug image support when the actual image method is plumbed. @@ -208,14 +207,12 @@ void main() { cmd_ref.offset += 4 + CmdImage_size; break; case Cmd_BeginClip: - uint base_ix = (scratch_alloc.offset >> 2) + CLIP_STATE_SIZE * (clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX + - gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y); for (uint k = 0; k < CHUNK; k++) { - uvec2 offset = chunk_offset(k); - uint srgb = packsRGB(vec4(rgba[k])); - mediump float alpha = clamp(abs(area[k]), 0.0, 1.0); - write_mem(scratch_alloc, base_ix + 0 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX), srgb); - write_mem(scratch_alloc, base_ix + 1 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX), floatBitsToUint(alpha)); + // We reject any inputs that might overflow in render_ctx.rs. + // The following is a sanity check so we don't corrupt memory should there be malformed inputs. + uint d = min(clip_depth, MAX_BLEND_STACK - 1); + blend_stack[d][k] = packsRGB(vec4(rgba[k])); + blend_alpha_stack[d][k] = clamp(abs(area[k]), 0.0, 1.0); rgba[k] = vec4(0.0); } clip_depth++; @@ -223,14 +220,10 @@ void main() { break; case Cmd_EndClip: clip_depth--; - base_ix = (scratch_alloc.offset >> 2) + CLIP_STATE_SIZE * (clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX + - gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y); for (uint k = 0; k < CHUNK; k++) { - uvec2 offset = chunk_offset(k); - uint srgb = read_mem(scratch_alloc, base_ix + 0 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX)); - uint alpha = read_mem(scratch_alloc, base_ix + 1 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX)); - mediump vec4 bg = unpacksRGB(srgb); - mediump vec4 fg = rgba[k] * area[k] * uintBitsToFloat(alpha); + uint d = min(clip_depth, MAX_BLEND_STACK - 1); + mediump vec4 bg = unpacksRGB(blend_stack[d][k]); + mediump vec4 fg = rgba[k] * area[k] * blend_alpha_stack[d][k]; rgba[k] = bg * (1.0 - fg.a) + fg; } cmd_ref.offset += 4; diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index 3e88494..5129b3f 100644 Binary files a/piet-gpu/shader/kernel4.spv and b/piet-gpu/shader/kernel4.spv differ diff --git a/piet-gpu/shader/kernel4_idx.spv b/piet-gpu/shader/kernel4_idx.spv index 17d2f47..953eae1 100644 Binary files a/piet-gpu/shader/kernel4_idx.spv and b/piet-gpu/shader/kernel4_idx.spv differ diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index d1c1dd6..b0e266f 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -30,6 +30,8 @@ const WIDTH_IN_TILES: usize = 128; const HEIGHT_IN_TILES: usize = 96; const PTCL_INITIAL_ALLOC: usize = 1024; +const MAX_BLEND_STACK: usize = 128; + const N_CIRCLES: usize = 0; pub fn render_svg(rc: &mut impl RenderContext, filename: &str, scale: f64) { diff --git a/piet-gpu/src/render_ctx.rs b/piet-gpu/src/render_ctx.rs index fe1c4ff..68d7508 100644 --- a/piet-gpu/src/render_ctx.rs +++ b/piet-gpu/src/render_ctx.rs @@ -8,6 +8,7 @@ use piet::{ Color, Error, FixedGradient, FontFamily, HitTestPoint, ImageFormat, InterpolationMode, IntoBrush, LineMetric, RenderContext, StrokeStyle, Text, TextLayout, TextLayoutBuilder, }; +use crate::MAX_BLEND_STACK; use piet_gpu_types::encoder::{Encode, Encoder}; use piet_gpu_types::scene::{ @@ -211,6 +212,9 @@ impl RenderContext for PietGpuRenderContext { self.elements.push(Element::BeginClip(Clip { bbox: Default::default(), })); + if self.clip_stack.len() >= MAX_BLEND_STACK { + panic!("Maximum clip/blend stack size {} exceeded", MAX_BLEND_STACK); + } self.clip_stack.push(ClipElement { bbox: None, begin_ix,