diff --git a/piet-gpu-types/src/annotated.rs b/piet-gpu-types/src/annotated.rs index 0e36f62..681a7ec 100644 --- a/piet-gpu-types/src/annotated.rs +++ b/piet-gpu-types/src/annotated.rs @@ -7,6 +7,10 @@ piet_gpu! { rgba_color: u32, bbox: [f32; 4], } + struct AnnoFillMask { + mask: f32, + bbox: [f32; 4], + } struct AnnoStroke { rgba_color: u32, bbox: [f32; 4], @@ -18,6 +22,8 @@ piet_gpu! { Nop, Stroke(AnnoStroke), Fill(AnnoFill), + FillMask(AnnoFillMask), + FillMaskInv(AnnoFillMask), } } } diff --git a/piet-gpu-types/src/ptcl.rs b/piet-gpu-types/src/ptcl.rs index 1deac38..95dcdc6 100644 --- a/piet-gpu-types/src/ptcl.rs +++ b/piet-gpu-types/src/ptcl.rs @@ -25,9 +25,17 @@ piet_gpu! { backdrop: i32, rgba_color: u32, } + struct CmdFillMask { + tile_ref: u32, + backdrop: i32, + mask: f32, + } struct CmdSolid { rgba_color: u32, } + struct CmdSolidMask { + mask: f32, + } struct CmdJump { new_ref: u32, } @@ -36,8 +44,11 @@ piet_gpu! { Circle(CmdCircle), Line(CmdLine), Fill(CmdFill), + FillMask(CmdFillMask), + FillMaskInv(CmdFillMask), Stroke(CmdStroke), Solid(CmdSolid), + SolidMask(CmdSolidMask), Jump(CmdJump), } diff --git a/piet-gpu-types/src/scene.rs b/piet-gpu-types/src/scene.rs index 0d72650..1359c1b 100644 --- a/piet-gpu-types/src/scene.rs +++ b/piet-gpu-types/src/scene.rs @@ -23,6 +23,9 @@ piet_gpu! { struct Fill { rgba_color: u32, } + struct FillMask { + mask: f32, + } struct Stroke { rgba_color: u32, } @@ -50,6 +53,8 @@ piet_gpu! { Fill(Fill), SetLineWidth(SetLineWidth), Transform(Transform), + FillMask(FillMask), + FillMaskInv(FillMask), } } } diff --git a/piet-gpu/shader/annotated.h b/piet-gpu/shader/annotated.h index 5dcb4ad..847ca06 100644 --- a/piet-gpu/shader/annotated.h +++ b/piet-gpu/shader/annotated.h @@ -4,6 +4,10 @@ struct AnnoFillRef { uint offset; }; +struct AnnoFillMaskRef { + uint offset; +}; + struct AnnoStrokeRef { uint offset; }; @@ -23,6 +27,17 @@ AnnoFillRef AnnoFill_index(AnnoFillRef ref, uint index) { return AnnoFillRef(ref.offset + index * AnnoFill_size); } +struct AnnoFillMask { + float mask; + vec4 bbox; +}; + +#define AnnoFillMask_size 20 + +AnnoFillMaskRef AnnoFillMask_index(AnnoFillMaskRef ref, uint index) { + return AnnoFillMaskRef(ref.offset + index * AnnoFillMask_size); +} + struct AnnoStroke { uint rgba_color; vec4 bbox; @@ -38,6 +53,8 @@ AnnoStrokeRef AnnoStroke_index(AnnoStrokeRef ref, uint index) { #define Annotated_Nop 0 #define Annotated_Stroke 1 #define Annotated_Fill 2 +#define Annotated_FillMask 3 +#define Annotated_FillMaskInv 4 #define Annotated_size 28 AnnotatedRef Annotated_index(AnnotatedRef ref, uint index) { @@ -66,6 +83,28 @@ void AnnoFill_write(AnnoFillRef ref, AnnoFill s) { annotated[ix + 4] = floatBitsToUint(s.bbox.w); } +AnnoFillMask AnnoFillMask_read(AnnoFillMaskRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = annotated[ix + 0]; + uint raw1 = annotated[ix + 1]; + uint raw2 = annotated[ix + 2]; + uint raw3 = annotated[ix + 3]; + uint raw4 = annotated[ix + 4]; + AnnoFillMask s; + s.mask = uintBitsToFloat(raw0); + s.bbox = vec4(uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3), uintBitsToFloat(raw4)); + return s; +} + +void AnnoFillMask_write(AnnoFillMaskRef ref, AnnoFillMask s) { + uint ix = ref.offset >> 2; + annotated[ix + 0] = floatBitsToUint(s.mask); + annotated[ix + 1] = floatBitsToUint(s.bbox.x); + annotated[ix + 2] = floatBitsToUint(s.bbox.y); + annotated[ix + 3] = floatBitsToUint(s.bbox.z); + annotated[ix + 4] = floatBitsToUint(s.bbox.w); +} + AnnoStroke AnnoStroke_read(AnnoStrokeRef ref) { uint ix = ref.offset >> 2; uint raw0 = annotated[ix + 0]; @@ -103,6 +142,14 @@ AnnoFill Annotated_Fill_read(AnnotatedRef ref) { return AnnoFill_read(AnnoFillRef(ref.offset + 4)); } +AnnoFillMask Annotated_FillMask_read(AnnotatedRef ref) { + return AnnoFillMask_read(AnnoFillMaskRef(ref.offset + 4)); +} + +AnnoFillMask Annotated_FillMaskInv_read(AnnotatedRef ref) { + return AnnoFillMask_read(AnnoFillMaskRef(ref.offset + 4)); +} + void Annotated_Nop_write(AnnotatedRef ref) { annotated[ref.offset >> 2] = Annotated_Nop; } @@ -117,3 +164,13 @@ void Annotated_Fill_write(AnnotatedRef ref, AnnoFill s) { AnnoFill_write(AnnoFillRef(ref.offset + 4), s); } +void Annotated_FillMask_write(AnnotatedRef ref, AnnoFillMask s) { + annotated[ref.offset >> 2] = Annotated_FillMask; + AnnoFillMask_write(AnnoFillMaskRef(ref.offset + 4), s); +} + +void Annotated_FillMaskInv_write(AnnotatedRef ref, AnnoFillMask s) { + annotated[ref.offset >> 2] = Annotated_FillMaskInv; + AnnoFillMask_write(AnnoFillMaskRef(ref.offset + 4), s); +} + diff --git a/piet-gpu/shader/backdrop.comp b/piet-gpu/shader/backdrop.comp index beba683..20c6ce9 100644 --- a/piet-gpu/shader/backdrop.comp +++ b/piet-gpu/shader/backdrop.comp @@ -53,7 +53,10 @@ void main() { uint row_count = 0; if (element_ix < n_elements) { uint tag = Annotated_tag(ref); - if (tag == Annotated_Fill) { + switch (tag) { + case Annotated_Fill: + case Annotated_FillMask: + case Annotated_FillMaskInv: PathRef path_ref = PathRef(element_ix * Path_size); Path path = Path_read(path_ref); sh_row_width[th_ix] = path.bbox.z - path.bbox.x; diff --git a/piet-gpu/shader/backdrop.spv b/piet-gpu/shader/backdrop.spv index fdbb4f1..e2093d9 100644 Binary files a/piet-gpu/shader/backdrop.spv and b/piet-gpu/shader/backdrop.spv differ diff --git a/piet-gpu/shader/binning.comp b/piet-gpu/shader/binning.comp index 046c4fb..ee3301b 100644 --- a/piet-gpu/shader/binning.comp +++ b/piet-gpu/shader/binning.comp @@ -60,6 +60,8 @@ void main() { float my_right_edge = INFINITY; switch (tag) { case Annotated_Fill: + case Annotated_FillMask: + case Annotated_FillMaskInv: case Annotated_Stroke: // Note: we take advantage of the fact that fills and strokes // have compatible layout. diff --git a/piet-gpu/shader/binning.spv b/piet-gpu/shader/binning.spv index d1c469c..50070a1 100644 Binary files a/piet-gpu/shader/binning.spv and b/piet-gpu/shader/binning.spv differ diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 57cbc8b..16573e8 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -173,6 +173,8 @@ void main() { uint tile_count; switch (tag) { case Annotated_Fill: + case Annotated_FillMask: + case Annotated_FillMaskInv: case Annotated_Stroke: // Because the only elements we're processing right now are // paths, we can just use the element index as the path index. @@ -222,12 +224,20 @@ void main() { el_ix = probe; } } + AnnotatedRef ref = AnnotatedRef(el_ix * Annotated_size); + uint tag = Annotated_tag(ref); uint seq_ix = ix - (el_ix > 0 ? sh_tile_count[el_ix - 1] : 0); uint width = sh_tile_width[el_ix]; uint x = sh_tile_x0[el_ix] + seq_ix % width; uint y = sh_tile_y0[el_ix] + seq_ix / width; Tile tile = Tile_read(TileRef(sh_tile_base[el_ix] + (sh_tile_stride[el_ix] * y + x) * Tile_size)); - if (tile.tile.offset != 0 || tile.backdrop != 0) { + // Include the path in the tile if + // - the tile contains at least a segment (tile offset non-zero) + // - the tile is completely covered (backdrop non-zero) + // - the tile is not covered and we're filling everything outside the path (backdrop zero, inverse fills). + bool inside = tile.backdrop != 0; + bool fill = tag != Annotated_FillMaskInv; + if (tile.tile.offset != 0 || inside == fill) { uint el_slice = el_ix / 32; uint el_mask = 1 << (el_ix & 31); atomicOr(sh_bitmaps[el_slice][y * N_TILE_X + x], el_mask); @@ -281,6 +291,27 @@ void main() { } cmd_ref.offset += Cmd_size; break; + case Annotated_FillMask: + case Annotated_FillMaskInv: + tile = Tile_read(TileRef(sh_tile_base[element_ref_ix] + + (sh_tile_stride[element_ref_ix] * tile_y + tile_x) * Tile_size)); + AnnoFillMask fill_mask = Annotated_FillMask_read(ref); + alloc_cmd(cmd_ref, cmd_limit); + if (tile.tile.offset != 0) { + CmdFillMask cmd_fill; + cmd_fill.tile_ref = tile.tile.offset; + cmd_fill.backdrop = tile.backdrop; + cmd_fill.mask = fill_mask.mask; + if (tag == Annotated_FillMask) { + Cmd_FillMask_write(cmd_ref, cmd_fill); + } else { + Cmd_FillMaskInv_write(cmd_ref, cmd_fill); + } + } else { + Cmd_SolidMask_write(cmd_ref, CmdSolidMask(fill_mask.mask)); + } + cmd_ref.offset += Cmd_size; + break; case Annotated_Stroke: tile = Tile_read(TileRef(sh_tile_base[element_ref_ix] + (sh_tile_stride[element_ref_ix] * tile_y + tile_x) * Tile_size)); diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 334e1f5..7758b96 100644 Binary files a/piet-gpu/shader/coarse.spv and b/piet-gpu/shader/coarse.spv differ diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index 3c38f38..b0e4779 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -130,6 +130,8 @@ State map_element(ElementRef ref, inout bool is_fill) { c.pathseg_count = 1; break; case Element_Fill: + case Element_FillMask: + case Element_FillMaskInv: is_fill = true; // fall-through case Element_Stroke: @@ -381,6 +383,23 @@ void main() { out_ref = AnnotatedRef((st.path_count - 1) * Annotated_size); Annotated_Fill_write(out_ref, anno_fill); break; + case Element_FillMask: + FillMask fill_mask = Element_FillMask_read(this_ref); + AnnoFillMask anno_fill_mask; + anno_fill_mask.mask = fill_mask.mask; + anno_fill_mask.bbox = st.bbox; + out_ref = AnnotatedRef((st.path_count - 1) * Annotated_size); + Annotated_FillMask_write(out_ref, anno_fill_mask); + break; + case Element_FillMaskInv: + fill_mask = Element_FillMaskInv_read(this_ref); + anno_fill_mask.mask = fill_mask.mask; + // The inverse fill conceptually takes up the entire screen. + // TODO: Tighten bounds to contain only affected paths. + anno_fill_mask.bbox = vec4(0, 0, 1e9, 1e9); + out_ref = AnnotatedRef((st.path_count - 1) * Annotated_size); + Annotated_FillMaskInv_write(out_ref, anno_fill_mask); + break; } } } diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index 4b7a1c2..599465a 100644 Binary files a/piet-gpu/shader/elements.spv and b/piet-gpu/shader/elements.spv differ diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index 70c879f..d21aa87 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -27,6 +27,40 @@ layout(rgba8, set = 0, binding = 2) uniform writeonly image2D image; #include "ptcl.h" #include "tile.h" +// Calculate coverage based on backdrop + coverage of each line segment +float[CHUNK] computeArea(vec2 xy, int backdrop, uint tile_ref) { + // Probably better to store as float, but conversion is no doubt cheap. + float area[CHUNK]; + for (uint k = 0; k < CHUNK; k++) area[k] = float(backdrop); + TileSegRef tile_seg_ref = TileSegRef(tile_ref); + do { + TileSeg seg = TileSeg_read(tile_seg_ref); + for (uint k = 0; k < CHUNK; k++) { + vec2 my_xy = vec2(xy.x, xy.y + float(k * CHUNK_DY)); + vec2 start = seg.start - my_xy; + vec2 end = seg.end - my_xy; + vec2 window = clamp(vec2(start.y, end.y), 0.0, 1.0); + if (window.x != window.y) { + vec2 t = (window - start.y) / (end.y - start.y); + vec2 xs = vec2(mix(start.x, end.x, t.x), mix(start.x, end.x, t.y)); + float xmin = min(min(xs.x, xs.y), 1.0) - 1e-6; + float xmax = max(xs.x, xs.y); + float b = min(xmax, 1.0); + float c = max(b, 0.0); + float d = max(xmin, 0.0); + float a = (b + 0.5 * (d * d - c * c) - xmin) / (xmax - xmin); + area[k] += a * (window.x - window.y); + } + area[k] += sign(end.x - start.x) * clamp(my_xy.y - seg.y_edge + 1.0, 0.0, 1.0); + } + tile_seg_ref = seg.next; + } while (tile_seg_ref.offset != 0); + for (uint k = 0; k < CHUNK; k++) { + area[k] = min(abs(area[k]), 1.0); + } + return area; +} + void main() { uint tile_ix = gl_WorkGroupID.y * WIDTH_IN_TILES + gl_WorkGroupID.x; CmdRef cmd_ref = CmdRef(tile_ix * PTCL_INITIAL_ALLOC); @@ -34,8 +68,10 @@ void main() { uvec2 xy_uint = uvec2(gl_GlobalInvocationID.x, gl_LocalInvocationID.y + TILE_HEIGHT_PX * gl_WorkGroupID.y); vec2 xy = vec2(xy_uint); vec3 rgb[CHUNK]; + float mask[CHUNK]; for (uint i = 0; i < CHUNK; i++) { rgb[i] = vec3(0.5); + mask[i] = 1.0; } while (true) { @@ -52,7 +88,7 @@ void main() { float r = length(vec2(xy.x, xy.y + dy) + vec2(0.5, 0.5) - circle.center.xy); float alpha = clamp(0.5 + circle.radius - r, 0.0, 1.0); // TODO: sRGB - rgb[i] = mix(rgb[i], fg_rgba.rgb, alpha * fg_rgba.a); + rgb[i] = mix(rgb[i], fg_rgba.rgb, mask[i] * alpha * fg_rgba.a); } break; case Cmd_Stroke: @@ -75,49 +111,43 @@ void main() { fg_rgba = unpackUnorm4x8(stroke.rgba_color).wzyx; for (uint k = 0; k < CHUNK; k++) { float alpha = clamp(stroke.half_width + 0.5 - df[k], 0.0, 1.0); - rgb[k] = mix(rgb[k], fg_rgba.rgb, alpha * fg_rgba.a); + rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * alpha * fg_rgba.a); } break; case Cmd_Fill: - // Calculate coverage based on backdrop + coverage of each line segment CmdFill fill = Cmd_Fill_read(cmd_ref); - // Probably better to store as float, but conversion is no doubt cheap. float area[CHUNK]; - for (uint k = 0; k < CHUNK; k++) area[k] = float(fill.backdrop); - tile_seg_ref = TileSegRef(fill.tile_ref); - do { - TileSeg seg = TileSeg_read(tile_seg_ref); - for (uint k = 0; k < CHUNK; k++) { - vec2 my_xy = vec2(xy.x, xy.y + float(k * CHUNK_DY)); - vec2 start = seg.start - my_xy; - vec2 end = seg.end - my_xy; - vec2 window = clamp(vec2(start.y, end.y), 0.0, 1.0); - if (window.x != window.y) { - vec2 t = (window - start.y) / (end.y - start.y); - vec2 xs = vec2(mix(start.x, end.x, t.x), mix(start.x, end.x, t.y)); - float xmin = min(min(xs.x, xs.y), 1.0) - 1e-6; - float xmax = max(xs.x, xs.y); - float b = min(xmax, 1.0); - float c = max(b, 0.0); - float d = max(xmin, 0.0); - float a = (b + 0.5 * (d * d - c * c) - xmin) / (xmax - xmin); - area[k] += a * (window.x - window.y); - } - area[k] += sign(end.x - start.x) * clamp(my_xy.y - seg.y_edge + 1.0, 0.0, 1.0); - } - tile_seg_ref = seg.next; - } while (tile_seg_ref.offset != 0); + area = computeArea(xy, fill.backdrop, fill.tile_ref); fg_rgba = unpackUnorm4x8(fill.rgba_color).wzyx; for (uint k = 0; k < CHUNK; k++) { - float alpha = min(abs(area[k]), 1.0); - rgb[k] = mix(rgb[k], fg_rgba.rgb, alpha * fg_rgba.a); + rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * area[k] * fg_rgba.a); + } + break; + case Cmd_FillMask: + CmdFillMask fill_mask = Cmd_FillMask_read(cmd_ref); + area = computeArea(xy, fill_mask.backdrop, fill_mask.tile_ref); + for (uint k = 0; k < CHUNK; k++) { + mask[k] = mix(mask[k], fill_mask.mask, area[k]); + } + break; + case Cmd_FillMaskInv: + fill_mask = Cmd_FillMask_read(cmd_ref); + area = computeArea(xy, fill_mask.backdrop, fill_mask.tile_ref); + for (uint k = 0; k < CHUNK; k++) { + mask[k] = mix(mask[k], fill_mask.mask, 1.0 - area[k]); } break; case Cmd_Solid: CmdSolid solid = Cmd_Solid_read(cmd_ref); fg_rgba = unpackUnorm4x8(solid.rgba_color).wzyx; for (uint k = 0; k < CHUNK; k++) { - rgb[k] = mix(rgb[k], fg_rgba.rgb, fg_rgba.a); + rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * fg_rgba.a); + } + break; + case Cmd_SolidMask: + CmdSolidMask solid_mask = Cmd_SolidMask_read(cmd_ref); + for (uint k = 0; k < CHUNK; k++) { + mask[k] = solid_mask.mask; } break; case Cmd_Jump: diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index 84919e0..d159fe5 100644 Binary files a/piet-gpu/shader/kernel4.spv and b/piet-gpu/shader/kernel4.spv differ diff --git a/piet-gpu/shader/ptcl.h b/piet-gpu/shader/ptcl.h index c9be302..d1cc83d 100644 --- a/piet-gpu/shader/ptcl.h +++ b/piet-gpu/shader/ptcl.h @@ -16,10 +16,18 @@ struct CmdFillRef { uint offset; }; +struct CmdFillMaskRef { + uint offset; +}; + struct CmdSolidRef { uint offset; }; +struct CmdSolidMaskRef { + uint offset; +}; + struct CmdJumpRef { uint offset; }; @@ -83,6 +91,18 @@ CmdFillRef CmdFill_index(CmdFillRef ref, uint index) { return CmdFillRef(ref.offset + index * CmdFill_size); } +struct CmdFillMask { + uint tile_ref; + int backdrop; + float mask; +}; + +#define CmdFillMask_size 12 + +CmdFillMaskRef CmdFillMask_index(CmdFillMaskRef ref, uint index) { + return CmdFillMaskRef(ref.offset + index * CmdFillMask_size); +} + struct CmdSolid { uint rgba_color; }; @@ -93,6 +113,16 @@ CmdSolidRef CmdSolid_index(CmdSolidRef ref, uint index) { return CmdSolidRef(ref.offset + index * CmdSolid_size); } +struct CmdSolidMask { + float mask; +}; + +#define CmdSolidMask_size 4 + +CmdSolidMaskRef CmdSolidMask_index(CmdSolidMaskRef ref, uint index) { + return CmdSolidMaskRef(ref.offset + index * CmdSolidMask_size); +} + struct CmdJump { uint new_ref; }; @@ -107,9 +137,12 @@ CmdJumpRef CmdJump_index(CmdJumpRef ref, uint index) { #define Cmd_Circle 1 #define Cmd_Line 2 #define Cmd_Fill 3 -#define Cmd_Stroke 4 -#define Cmd_Solid 5 -#define Cmd_Jump 6 +#define Cmd_FillMask 4 +#define Cmd_FillMaskInv 5 +#define Cmd_Stroke 6 +#define Cmd_Solid 7 +#define Cmd_SolidMask 8 +#define Cmd_Jump 9 #define Cmd_size 20 CmdRef Cmd_index(CmdRef ref, uint index) { @@ -219,6 +252,25 @@ void CmdFill_write(CmdFillRef ref, CmdFill s) { ptcl[ix + 2] = s.rgba_color; } +CmdFillMask CmdFillMask_read(CmdFillMaskRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = ptcl[ix + 0]; + uint raw1 = ptcl[ix + 1]; + uint raw2 = ptcl[ix + 2]; + CmdFillMask s; + s.tile_ref = raw0; + s.backdrop = int(raw1); + s.mask = uintBitsToFloat(raw2); + return s; +} + +void CmdFillMask_write(CmdFillMaskRef ref, CmdFillMask s) { + uint ix = ref.offset >> 2; + ptcl[ix + 0] = s.tile_ref; + ptcl[ix + 1] = uint(s.backdrop); + ptcl[ix + 2] = floatBitsToUint(s.mask); +} + CmdSolid CmdSolid_read(CmdSolidRef ref) { uint ix = ref.offset >> 2; uint raw0 = ptcl[ix + 0]; @@ -232,6 +284,19 @@ void CmdSolid_write(CmdSolidRef ref, CmdSolid s) { ptcl[ix + 0] = s.rgba_color; } +CmdSolidMask CmdSolidMask_read(CmdSolidMaskRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = ptcl[ix + 0]; + CmdSolidMask s; + s.mask = uintBitsToFloat(raw0); + return s; +} + +void CmdSolidMask_write(CmdSolidMaskRef ref, CmdSolidMask s) { + uint ix = ref.offset >> 2; + ptcl[ix + 0] = floatBitsToUint(s.mask); +} + CmdJump CmdJump_read(CmdJumpRef ref) { uint ix = ref.offset >> 2; uint raw0 = ptcl[ix + 0]; @@ -261,6 +326,14 @@ CmdFill Cmd_Fill_read(CmdRef ref) { return CmdFill_read(CmdFillRef(ref.offset + 4)); } +CmdFillMask Cmd_FillMask_read(CmdRef ref) { + return CmdFillMask_read(CmdFillMaskRef(ref.offset + 4)); +} + +CmdFillMask Cmd_FillMaskInv_read(CmdRef ref) { + return CmdFillMask_read(CmdFillMaskRef(ref.offset + 4)); +} + CmdStroke Cmd_Stroke_read(CmdRef ref) { return CmdStroke_read(CmdStrokeRef(ref.offset + 4)); } @@ -269,6 +342,10 @@ CmdSolid Cmd_Solid_read(CmdRef ref) { return CmdSolid_read(CmdSolidRef(ref.offset + 4)); } +CmdSolidMask Cmd_SolidMask_read(CmdRef ref) { + return CmdSolidMask_read(CmdSolidMaskRef(ref.offset + 4)); +} + CmdJump Cmd_Jump_read(CmdRef ref) { return CmdJump_read(CmdJumpRef(ref.offset + 4)); } @@ -292,6 +369,16 @@ void Cmd_Fill_write(CmdRef ref, CmdFill s) { CmdFill_write(CmdFillRef(ref.offset + 4), s); } +void Cmd_FillMask_write(CmdRef ref, CmdFillMask s) { + ptcl[ref.offset >> 2] = Cmd_FillMask; + CmdFillMask_write(CmdFillMaskRef(ref.offset + 4), s); +} + +void Cmd_FillMaskInv_write(CmdRef ref, CmdFillMask s) { + ptcl[ref.offset >> 2] = Cmd_FillMaskInv; + CmdFillMask_write(CmdFillMaskRef(ref.offset + 4), s); +} + void Cmd_Stroke_write(CmdRef ref, CmdStroke s) { ptcl[ref.offset >> 2] = Cmd_Stroke; CmdStroke_write(CmdStrokeRef(ref.offset + 4), s); @@ -302,6 +389,11 @@ void Cmd_Solid_write(CmdRef ref, CmdSolid s) { CmdSolid_write(CmdSolidRef(ref.offset + 4), s); } +void Cmd_SolidMask_write(CmdRef ref, CmdSolidMask s) { + ptcl[ref.offset >> 2] = Cmd_SolidMask; + CmdSolidMask_write(CmdSolidMaskRef(ref.offset + 4), s); +} + void Cmd_Jump_write(CmdRef ref, CmdJump s) { ptcl[ref.offset >> 2] = Cmd_Jump; CmdJump_write(CmdJumpRef(ref.offset + 4), s); diff --git a/piet-gpu/shader/scene.h b/piet-gpu/shader/scene.h index eee8075..6823fe6 100644 --- a/piet-gpu/shader/scene.h +++ b/piet-gpu/shader/scene.h @@ -16,6 +16,10 @@ struct FillRef { uint offset; }; +struct FillMaskRef { + uint offset; +}; + struct StrokeRef { uint offset; }; @@ -78,6 +82,16 @@ FillRef Fill_index(FillRef ref, uint index) { return FillRef(ref.offset + index * Fill_size); } +struct FillMask { + float mask; +}; + +#define FillMask_size 4 + +FillMaskRef FillMask_index(FillMaskRef ref, uint index) { + return FillMaskRef(ref.offset + index * FillMask_size); +} + struct Stroke { uint rgba_color; }; @@ -120,6 +134,8 @@ TransformRef Transform_index(TransformRef ref, uint index) { #define Element_Fill 8 #define Element_SetLineWidth 9 #define Element_Transform 10 +#define Element_FillMask 11 +#define Element_FillMaskInv 12 #define Element_size 36 ElementRef Element_index(ElementRef ref, uint index) { @@ -179,6 +195,14 @@ Fill Fill_read(FillRef ref) { return s; } +FillMask FillMask_read(FillMaskRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = scene[ix + 0]; + FillMask s; + s.mask = uintBitsToFloat(raw0); + return s; +} + Stroke Stroke_read(StrokeRef ref) { uint ix = ref.offset >> 2; uint raw0 = scene[ix + 0]; @@ -253,3 +277,11 @@ Transform Element_Transform_read(ElementRef ref) { return Transform_read(TransformRef(ref.offset + 4)); } +FillMask Element_FillMask_read(ElementRef ref) { + return FillMask_read(FillMaskRef(ref.offset + 4)); +} + +FillMask Element_FillMaskInv_read(ElementRef ref) { + return FillMask_read(FillMaskRef(ref.offset + 4)); +} + diff --git a/piet-gpu/shader/tile_alloc.comp b/piet-gpu/shader/tile_alloc.comp index b0c99a5..3e1e52f 100644 --- a/piet-gpu/shader/tile_alloc.comp +++ b/piet-gpu/shader/tile_alloc.comp @@ -47,6 +47,8 @@ void main() { int x0 = 0, y0 = 0, x1 = 0, y1 = 0; switch (tag) { case Annotated_Fill: + case Annotated_FillMask: + case Annotated_FillMaskInv: case Annotated_Stroke: // Note: we take advantage of the fact that fills and strokes // have compatible layout. diff --git a/piet-gpu/shader/tile_alloc.spv b/piet-gpu/shader/tile_alloc.spv index e012b7c..af52665 100644 Binary files a/piet-gpu/shader/tile_alloc.spv and b/piet-gpu/shader/tile_alloc.spv differ