diff --git a/piet-gpu-types/src/pathseg.rs b/piet-gpu-types/src/pathseg.rs index a679e44..c6067fa 100644 --- a/piet-gpu-types/src/pathseg.rs +++ b/piet-gpu-types/src/pathseg.rs @@ -3,32 +3,20 @@ use piet_gpu_derive::piet_gpu; piet_gpu! { #[gpu_write] mod pathseg { - struct PathFillCubic { + struct PathCubic { p0: [f32; 2], p1: [f32; 2], p2: [f32; 2], p3: [f32; 2], path_ix: u32, - // trans_ix is 1-based, 0 means no transformation. + // trans_ix is the transform index. It is 1-based, 0 means no transformation. trans_ix: u32, - // A note: the layout of this struct is shared with - // PathStrokeCubic. In that case, we actually write - // [0.0, 0.0] as the stroke field, to minimize divergence. - } - struct PathStrokeCubic { - p0: [f32; 2], - p1: [f32; 2], - p2: [f32; 2], - p3: [f32; 2], - path_ix: u32, - trans_ix: u32, - // halfwidth in both x and y for binning + // Halfwidth in both x and y for binning. For strokes only. stroke: [f32; 2], } enum PathSeg { Nop, - FillCubic(PathFillCubic), - StrokeCubic(PathStrokeCubic), + Cubic(TagFlags, PathCubic), } } } diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index 1289cc2..b33ed66 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -293,7 +293,7 @@ void main() { switch (tag.tag) { case Element_Line: LineSeg line = Element_Line_read(this_ref); - PathStrokeCubic path_cubic; + PathCubic path_cubic; path_cubic.p0 = line.p0; path_cubic.p1 = mix(line.p0, line.p1, 1.0 / 3.0); path_cubic.p2 = mix(line.p1, line.p0, 1.0 / 3.0); @@ -305,12 +305,8 @@ void main() { } else { path_cubic.stroke = vec2(0.0); } - // We do encoding a bit by hand to minimize divergence. Another approach - // would be to have a fill/stroke bool. PathSegRef path_out_ref = PathSegRef(conf.pathseg_alloc.offset + (st.pathseg_count - 1) * PathSeg_size); - uint out_tag = !is_stroke ? PathSeg_FillCubic : PathSeg_StrokeCubic; - write_mem(conf.pathseg_alloc, path_out_ref.offset >> 2, out_tag); - PathStrokeCubic_write(conf.pathseg_alloc, PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic); + PathSeg_Cubic_write(conf.pathseg_alloc, path_out_ref, fill_mode, path_cubic); break; case Element_Quad: QuadSeg quad = Element_Quad_read(this_ref); @@ -325,12 +321,8 @@ void main() { } else { path_cubic.stroke = vec2(0.0); } - // We do encoding a bit by hand to minimize divergence. Another approach - // would be to have a fill/stroke bool. path_out_ref = PathSegRef(conf.pathseg_alloc.offset + (st.pathseg_count - 1) * PathSeg_size); - out_tag = !is_stroke ? PathSeg_FillCubic : PathSeg_StrokeCubic; - write_mem(conf.pathseg_alloc, path_out_ref.offset >> 2, out_tag); - PathStrokeCubic_write(conf.pathseg_alloc, PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic); + PathSeg_Cubic_write(conf.pathseg_alloc, path_out_ref, fill_mode, path_cubic); break; case Element_Cubic: CubicSeg cubic = Element_Cubic_read(this_ref); @@ -345,12 +337,8 @@ void main() { } else { path_cubic.stroke = vec2(0.0); } - // We do encoding a bit by hand to minimize divergence. Another approach - // would be to have a fill/stroke bool. path_out_ref = PathSegRef(conf.pathseg_alloc.offset + (st.pathseg_count - 1) * PathSeg_size); - out_tag = !is_stroke ? PathSeg_FillCubic : PathSeg_StrokeCubic; - write_mem(conf.pathseg_alloc, path_out_ref.offset >> 2, out_tag); - PathStrokeCubic_write(conf.pathseg_alloc, PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic); + PathSeg_Cubic_write(conf.pathseg_alloc, path_out_ref, fill_mode, path_cubic); break; case Element_FillColor: FillColor fill = Element_FillColor_read(this_ref); diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index b83e065..a49255b 100644 Binary files a/piet-gpu/shader/elements.spv and b/piet-gpu/shader/elements.spv differ diff --git a/piet-gpu/shader/path_coarse.comp b/piet-gpu/shader/path_coarse.comp index 663fe45..51264bf 100644 --- a/piet-gpu/shader/path_coarse.comp +++ b/piet-gpu/shader/path_coarse.comp @@ -94,14 +94,13 @@ void main() { uint element_ix = gl_GlobalInvocationID.x; PathSegRef ref = PathSegRef(conf.pathseg_alloc.offset + element_ix * PathSeg_size); - uint tag = PathSeg_Nop; + PathSegTag tag = PathSegTag(PathSeg_Nop, 0); if (element_ix < conf.n_pathseg) { - tag = PathSeg_tag(conf.pathseg_alloc, ref).tag; + tag = PathSeg_tag(conf.pathseg_alloc, ref); } - switch (tag) { - case PathSeg_FillCubic: - case PathSeg_StrokeCubic: - PathStrokeCubic cubic = PathSeg_StrokeCubic_read(conf.pathseg_alloc, ref); + switch (tag.tag) { + case PathSeg_Cubic: + PathCubic cubic = PathSeg_Cubic_read(conf.pathseg_alloc, ref); uint trans_ix = cubic.trans_ix; if (trans_ix > 0) { @@ -133,6 +132,7 @@ void main() { } uint n = max(uint(ceil(val * 0.5 / sqrt(REM_ACCURACY))), 1); + bool is_stroke = fill_mode_from_flags(tag.flags) == MODE_STROKE; uint path_ix = cubic.path_ix; Path path = Path_read(conf.tile_alloc, PathRef(conf.tile_alloc.offset + path_ix * Path_size)); Alloc path_alloc = new_alloc(path.tiles.offset, (path.bbox.z - path.bbox.x) * (path.bbox.w - path.bbox.y) * Tile_size); @@ -212,7 +212,7 @@ void main() { for (int y = y0; y < y1; y++) { float tile_y0 = float(y * TILE_HEIGHT_PX); int xbackdrop = max(xray + 1, bbox.x); - if (tag == PathSeg_FillCubic && min(p0.y, p1.y) < tile_y0 && xbackdrop < bbox.z) { + if (!is_stroke && min(p0.y, p1.y) < tile_y0 && xbackdrop < bbox.z) { int backdrop = p1.y < p0.y ? 1 : -1; TileRef tile_ref = Tile_index(path.tiles, uint(base + xbackdrop)); uint tile_el = tile_ref.offset >> 2; @@ -248,7 +248,7 @@ void main() { tile_seg.origin = p0; tile_seg.vector = p1 - p0; float y_edge = 0.0; - if (tag == PathSeg_FillCubic) { + if (!is_stroke) { y_edge = mix(p0.y, p1.y, (tile_x0 - p0.x) / dx); if (min(p0.x, p1.x) < tile_x0) { vec2 p = vec2(tile_x0, y_edge); diff --git a/piet-gpu/shader/path_coarse.spv b/piet-gpu/shader/path_coarse.spv index 16eb64c..b4cd985 100644 Binary files a/piet-gpu/shader/path_coarse.spv and b/piet-gpu/shader/path_coarse.spv differ diff --git a/piet-gpu/shader/pathseg.h b/piet-gpu/shader/pathseg.h index f3b2dec..749771e 100644 --- a/piet-gpu/shader/pathseg.h +++ b/piet-gpu/shader/pathseg.h @@ -2,11 +2,7 @@ // Code auto-generated by piet-gpu-derive -struct PathFillCubicRef { - uint offset; -}; - -struct PathStrokeCubicRef { +struct PathCubicRef { uint offset; }; @@ -14,22 +10,7 @@ struct PathSegRef { uint offset; }; -struct PathFillCubic { - vec2 p0; - vec2 p1; - vec2 p2; - vec2 p3; - uint path_ix; - uint trans_ix; -}; - -#define PathFillCubic_size 40 - -PathFillCubicRef PathFillCubic_index(PathFillCubicRef ref, uint index) { - return PathFillCubicRef(ref.offset + index * PathFillCubic_size); -} - -struct PathStrokeCubic { +struct PathCubic { vec2 p0; vec2 p1; vec2 p2; @@ -39,15 +20,14 @@ struct PathStrokeCubic { vec2 stroke; }; -#define PathStrokeCubic_size 48 +#define PathCubic_size 48 -PathStrokeCubicRef PathStrokeCubic_index(PathStrokeCubicRef ref, uint index) { - return PathStrokeCubicRef(ref.offset + index * PathStrokeCubic_size); +PathCubicRef PathCubic_index(PathCubicRef ref, uint index) { + return PathCubicRef(ref.offset + index * PathCubic_size); } #define PathSeg_Nop 0 -#define PathSeg_FillCubic 1 -#define PathSeg_StrokeCubic 2 +#define PathSeg_Cubic 1 #define PathSeg_size 52 PathSegRef PathSeg_index(PathSegRef ref, uint index) { @@ -59,43 +39,7 @@ struct PathSegTag { uint flags; }; -PathFillCubic PathFillCubic_read(Alloc a, PathFillCubicRef ref) { - uint ix = ref.offset >> 2; - uint raw0 = read_mem(a, ix + 0); - uint raw1 = read_mem(a, ix + 1); - uint raw2 = read_mem(a, ix + 2); - uint raw3 = read_mem(a, ix + 3); - uint raw4 = read_mem(a, ix + 4); - uint raw5 = read_mem(a, ix + 5); - uint raw6 = read_mem(a, ix + 6); - uint raw7 = read_mem(a, ix + 7); - uint raw8 = read_mem(a, ix + 8); - uint raw9 = read_mem(a, ix + 9); - PathFillCubic s; - s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); - s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); - s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); - s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7)); - s.path_ix = raw8; - s.trans_ix = raw9; - return s; -} - -void PathFillCubic_write(Alloc a, PathFillCubicRef ref, PathFillCubic s) { - uint ix = ref.offset >> 2; - write_mem(a, ix + 0, floatBitsToUint(s.p0.x)); - write_mem(a, ix + 1, floatBitsToUint(s.p0.y)); - write_mem(a, ix + 2, floatBitsToUint(s.p1.x)); - write_mem(a, ix + 3, floatBitsToUint(s.p1.y)); - write_mem(a, ix + 4, floatBitsToUint(s.p2.x)); - write_mem(a, ix + 5, floatBitsToUint(s.p2.y)); - write_mem(a, ix + 6, floatBitsToUint(s.p3.x)); - write_mem(a, ix + 7, floatBitsToUint(s.p3.y)); - write_mem(a, ix + 8, s.path_ix); - write_mem(a, ix + 9, s.trans_ix); -} - -PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) { +PathCubic PathCubic_read(Alloc a, PathCubicRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); uint raw1 = read_mem(a, ix + 1); @@ -109,7 +53,7 @@ PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) { uint raw9 = read_mem(a, ix + 9); uint raw10 = read_mem(a, ix + 10); uint raw11 = read_mem(a, ix + 11); - PathStrokeCubic s; + PathCubic s; s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); @@ -120,7 +64,7 @@ PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) { return s; } -void PathStrokeCubic_write(Alloc a, PathStrokeCubicRef ref, PathStrokeCubic s) { +void PathCubic_write(Alloc a, PathCubicRef ref, PathCubic s) { uint ix = ref.offset >> 2; write_mem(a, ix + 0, floatBitsToUint(s.p0.x)); write_mem(a, ix + 1, floatBitsToUint(s.p0.y)); @@ -141,25 +85,16 @@ PathSegTag PathSeg_tag(Alloc a, PathSegRef ref) { return PathSegTag(tag_and_flags & 0xffff, tag_and_flags >> 16); } -PathFillCubic PathSeg_FillCubic_read(Alloc a, PathSegRef ref) { - return PathFillCubic_read(a, PathFillCubicRef(ref.offset + 4)); -} - -PathStrokeCubic PathSeg_StrokeCubic_read(Alloc a, PathSegRef ref) { - return PathStrokeCubic_read(a, PathStrokeCubicRef(ref.offset + 4)); +PathCubic PathSeg_Cubic_read(Alloc a, PathSegRef ref) { + return PathCubic_read(a, PathCubicRef(ref.offset + 4)); } void PathSeg_Nop_write(Alloc a, PathSegRef ref) { write_mem(a, ref.offset >> 2, PathSeg_Nop); } -void PathSeg_FillCubic_write(Alloc a, PathSegRef ref, PathFillCubic s) { - write_mem(a, ref.offset >> 2, PathSeg_FillCubic); - PathFillCubic_write(a, PathFillCubicRef(ref.offset + 4), s); -} - -void PathSeg_StrokeCubic_write(Alloc a, PathSegRef ref, PathStrokeCubic s) { - write_mem(a, ref.offset >> 2, PathSeg_StrokeCubic); - PathStrokeCubic_write(a, PathStrokeCubicRef(ref.offset + 4), s); +void PathSeg_Cubic_write(Alloc a, PathSegRef ref, uint flags, PathCubic s) { + write_mem(a, ref.offset >> 2, (flags << 16) | PathSeg_Cubic); + PathCubic_write(a, PathCubicRef(ref.offset + 4), s); }