From 03da52cff839a47d811c66c996d4e36a1dd0f953 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Tue, 19 May 2020 08:21:09 -0700 Subject: [PATCH 1/5] Start implementing fills This should get the "right_edge" value for each segment plumbed through to the binning phase. It also needs to be plumbed to coarse raster and wired up there. Also considering WIP because none of this logic has been tested yet. --- piet-gpu-types/src/state.rs | 1 + piet-gpu/shader/binning.comp | 52 ++++++++++++++++++++++++++++++++-- piet-gpu/shader/binning.spv | Bin 16812 -> 21800 bytes piet-gpu/shader/elements.comp | 10 +++++-- piet-gpu/shader/elements.spv | Bin 43780 -> 45068 bytes piet-gpu/shader/setup.h | 5 ++++ piet-gpu/shader/state.h | 10 +++++-- piet-gpu/src/lib.rs | 4 +-- 8 files changed, 73 insertions(+), 9 deletions(-) diff --git a/piet-gpu-types/src/state.rs b/piet-gpu-types/src/state.rs index 35076f0..b93e9f3 100644 --- a/piet-gpu-types/src/state.rs +++ b/piet-gpu-types/src/state.rs @@ -8,6 +8,7 @@ piet_gpu! { translate: [f32; 2], bbox: [f32; 4], linewidth: f32, + right_edge: f32, flags: u32, } } diff --git a/piet-gpu/shader/binning.comp b/piet-gpu/shader/binning.comp index c3067e7..cba0217 100644 --- a/piet-gpu/shader/binning.comp +++ b/piet-gpu/shader/binning.comp @@ -11,24 +11,33 @@ layout(set = 0, binding = 0) buffer AnnotatedBuf { uint[] annotated; }; -layout(set = 0, binding = 1) buffer AllocBuf { +// This is for scanning forward for right_edge data. +layout(set = 0, binding = 1) buffer StateBuf { + uint[] state; +}; + +layout(set = 0, binding = 2) buffer AllocBuf { uint n_elements; // Will be incremented atomically to claim tiles uint tile_ix; uint alloc; }; -layout(set = 0, binding = 2) buffer BinsBuf { +layout(set = 0, binding = 3) buffer BinsBuf { uint[] bins; }; #include "annotated.h" +#include "state.h" #include "bins.h" // scale factors useful for converting coordinates to bins #define SX (1.0 / float(N_TILE_X * TILE_WIDTH_PX)) #define SY (1.0 / float(N_TILE_Y * TILE_HEIGHT_PX)) +// Constant not available in GLSL. Also consider uintBitsToFloat(0x7f800000) +#define INFINITY (1.0 / 0.0) + // Note: cudaraster has N_TILE + 1 to cut down on bank conflicts. shared uint bitmaps[N_SLICE][N_TILE]; shared uint count[N_SLICE][N_TILE]; @@ -37,6 +46,14 @@ shared uint sh_chunk_start[N_TILE]; shared uint sh_chunk_end[N_TILE]; shared uint sh_chunk_jump[N_TILE]; +shared float sh_right_edge[N_TILE]; + +#define StateBuf_stride (4 + 2 * State_size) + +StateRef state_aggregate_ref(uint partition_ix) { + return StateRef(8 + partition_ix * StateBuf_stride); +} + void main() { BinChunkRef chunk_ref = BinChunkRef((gl_LocalInvocationID.x * N_WG + gl_WorkGroupID.x) * BIN_INITIAL_ALLOC); uint wr_limit = chunk_ref.offset + BIN_INITIAL_ALLOC; @@ -65,6 +82,7 @@ void main() { tag = Annotated_tag(ref); } int x0 = 0, y0 = 0, x1 = 0, y1 = 0; + float my_right_edge = INFINITY; switch (tag) { case Annotated_Line: AnnoLineSeg line = Annotated_Line_read(ref); @@ -82,8 +100,37 @@ void main() { y0 = int(floor(fill.bbox.y * SY)); x1 = int(ceil(fill.bbox.z * SX)); y1 = int(ceil(fill.bbox.w * SY)); + my_right_edge = x1; break; } + + // If the last element in this partition is a fill edge, then we need to do a + // look-forward to find the right edge of its corresponding fill. That data is + // recorded in aggregates computed in the element processing pass. + if (gl_LocalInvocationID.x == N_TILE - 1 && tag == Annotated_Line) { + uint aggregate_ix = (my_tile + 1) * ELEMENT_BINNING_RATIO; + // This is sequential but the expectation is that the amount of + // look-forward is small (performance may degrade in the case + // of massively complex paths). + do { + StateRef agg_ref = state_aggregate_ref(aggregate_ix); + my_right_edge = State_read(agg_ref).right_edge; + aggregate_ix++; + } while (isinf(my_right_edge)); + } + + // Now propagate right_edge backward, from fill to segment. + for (uint i = 0; i < LG_N_TILE; i++) { + // Note: we could try to cut down on write bandwidth here if the value hasn't + // changed, but not sure it's worth the complexity to track. + sh_right_edge[gl_LocalInvocationID.x] = my_right_edge; + barrier(); + if (gl_LocalInvocationID.x + (1 << i) < N_TILE && isinf(my_right_edge)) { + my_right_edge = sh_right_edge[gl_LocalInvocationID.x + (1 << i)]; + } + barrier(); + } + // At this point, we run an iterator over the coverage area, // trying to keep divergence low. // Right now, it's just a bbox, but we'll get finer with @@ -141,6 +188,7 @@ void main() { chunk_n = element_count - chunk_n; } else { chunk_end = ~0; + chunk_new_start = ~0; chunk_n = element_count; } sh_chunk_start[gl_LocalInvocationID.x] = instance_ref.offset; diff --git a/piet-gpu/shader/binning.spv b/piet-gpu/shader/binning.spv index 76148c2c44d71cb55a0d2ef55715d2d6f77ee77c..a5379e6dad7ab1566cc2378b2fa9ed054c62b1a3 100644 GIT binary patch literal 21800 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 literal 16812 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 diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index 8f87b87..15ad80d 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -10,7 +10,7 @@ #define N_ROWS 4 #define WG_SIZE 32 #define LG_WG_SIZE 5 -#define TILE_SIZE (WG_SIZE * N_ROWS) +#define PARTITION_SIZE (WG_SIZE * N_ROWS) layout(local_size_x = WG_SIZE, local_size_y = 1) in; @@ -81,6 +81,7 @@ State combine_state(State a, State b) { c.translate.x = a.mat.x * b.translate.x + a.mat.z * b.translate.y + a.translate.x; c.translate.y = a.mat.y * b.translate.x + a.mat.w * b.translate.y + a.translate.y; c.linewidth = (b.flags & FLAG_SET_LINEWIDTH) == 0 ? a.linewidth : b.linewidth; + c.right_edge = (a.flags & FLAG_SET_BBOX) != 0 ? a.right_edge : (a.flags & FLAG_RESET_BBOX) != 0 ? a.bbox.z : c.right_edge; c.flags = (a.flags & (FLAG_SET_LINEWIDTH | FLAG_SET_BBOX)) | b.flags; c.flags |= (a.flags & FLAG_RESET_BBOX) >> 1; return c; @@ -143,6 +144,7 @@ shared vec4 sh_mat[WG_SIZE]; shared vec2 sh_translate[WG_SIZE]; shared vec4 sh_bbox[WG_SIZE]; shared float sh_width[WG_SIZE]; +shared float sh_right_edge[WG_SIZE]; shared uint sh_flags[WG_SIZE]; shared uint sh_tile_ix; @@ -158,7 +160,7 @@ void main() { barrier(); uint tile_ix = sh_tile_ix; - uint ix = tile_ix * TILE_SIZE + gl_LocalInvocationID.x * N_ROWS; + uint ix = tile_ix * PARTITION_SIZE + gl_LocalInvocationID.x * N_ROWS; ElementRef ref = ElementRef(ix * Element_size); th_state[0] = map_element(ref); @@ -172,6 +174,7 @@ void main() { sh_translate[gl_LocalInvocationID.x] = agg.translate; sh_bbox[gl_LocalInvocationID.x] = agg.bbox; sh_width[gl_LocalInvocationID.x] = agg.linewidth; + sh_right_edge[gl_LocalInvocationID.x] = agg.right_edge; sh_flags[gl_LocalInvocationID.x] = agg.flags; for (uint i = 0; i < LG_WG_SIZE; i++) { barrier(); @@ -190,6 +193,7 @@ void main() { sh_translate[gl_LocalInvocationID.x] = agg.translate; sh_bbox[gl_LocalInvocationID.x] = agg.bbox; sh_width[gl_LocalInvocationID.x] = agg.linewidth; + sh_right_edge[gl_LocalInvocationID.x] = agg.right_edge; sh_flags[gl_LocalInvocationID.x] = agg.flags; } @@ -198,6 +202,7 @@ void main() { exclusive.mat = vec4(1.0, 0.0, 0.0, 1.0); exclusive.translate = vec2(0.0, 0.0); exclusive.linewidth = 1.0; //TODO should be 0.0 + exclusive.right_edge = 0.0; exclusive.flags = 0; // Publish aggregate for this partition @@ -250,6 +255,7 @@ void main() { other.translate = sh_translate[ix]; other.bbox = sh_bbox[ix]; other.linewidth = sh_width[ix]; + other.right_edge = sh_right_edge[ix]; other.flags = sh_flags[ix]; row = combine_state(row, other); } diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index 7828aa4732cc2ea3c5291afc93f45b4af815d3c3..ff0ae2d456ea352ee946cbe946a3e9b56ffc4853 100644 GIT binary patch literal 45068 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 O*%GYo{9Hr1YxqAgC=VY1 diff --git a/piet-gpu/shader/setup.h b/piet-gpu/shader/setup.h index 5d8fb9b..6b00661 100644 --- a/piet-gpu/shader/setup.h +++ b/piet-gpu/shader/setup.h @@ -51,9 +51,14 @@ #define N_TILE_X 16 #define N_TILE_Y 16 #define N_TILE (N_TILE_X * N_TILE_Y) +#define LG_N_TILE 8 #define N_SLICE (N_TILE / 32) // Number of workgroups for binning kernel #define N_WG 16 +// This is the ratio of the number of elements in a binning workgroup +// over the number of elements in a partition workgroup. +#define ELEMENT_BINNING_RATIO 4 + #define BIN_INITIAL_ALLOC 64 #define BIN_ALLOC 256 diff --git a/piet-gpu/shader/state.h b/piet-gpu/shader/state.h index 2547b93..bc6192f 100644 --- a/piet-gpu/shader/state.h +++ b/piet-gpu/shader/state.h @@ -9,10 +9,11 @@ struct State { vec2 translate; vec4 bbox; float linewidth; + float right_edge; uint flags; }; -#define State_size 48 +#define State_size 52 StateRef State_index(StateRef ref, uint index) { return StateRef(ref.offset + index * State_size); @@ -32,12 +33,14 @@ State State_read(StateRef ref) { uint raw9 = state[ix + 9]; uint raw10 = state[ix + 10]; uint raw11 = state[ix + 11]; + uint raw12 = state[ix + 12]; State s; s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3)); s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); s.bbox = vec4(uintBitsToFloat(raw6), uintBitsToFloat(raw7), uintBitsToFloat(raw8), uintBitsToFloat(raw9)); s.linewidth = uintBitsToFloat(raw10); - s.flags = raw11; + s.right_edge = uintBitsToFloat(raw11); + s.flags = raw12; return s; } @@ -54,6 +57,7 @@ void State_write(StateRef ref, State s) { state[ix + 8] = floatBitsToUint(s.bbox.z); state[ix + 9] = floatBitsToUint(s.bbox.w); state[ix + 10] = floatBitsToUint(s.linewidth); - state[ix + 11] = s.flags; + state[ix + 11] = floatBitsToUint(s.right_edge); + state[ix + 12] = s.flags; } diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 2dca39d..70b02f5 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -185,10 +185,10 @@ impl Renderer { ]) ?; let bin_code = include_bytes!("../shader/binning.spv"); - let bin_pipeline = device.create_simple_compute_pipeline(bin_code, 3, 0)?; + let bin_pipeline = device.create_simple_compute_pipeline(bin_code, 4, 0)?; let bin_ds = device.create_descriptor_set( &bin_pipeline, - &[&anno_buf, &bin_alloc_buf_dev, &bin_buf], + &[&anno_buf, &state_buf, &bin_alloc_buf_dev, &bin_buf], &[], )?; From 076e6d600d828f7b7902b2603d22178faf25c3c9 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Wed, 20 May 2020 07:38:52 -0700 Subject: [PATCH 2/5] Progress on wiring up fills Write the right_edge to the binning output. More work on encoding the fill/stroke distinction and plumbing that through the pipeline. This is a bit unsatisfying because of the code duplication; having an extra fill/stroke bool might be better, but I want to avoid making the structs bigger (this could be solved by better packing in the struct encoding). Fills are plumbed through to the last stage. Backdrop is WIP. --- piet-gpu-types/src/annotated.rs | 13 +++-- piet-gpu-types/src/bins.rs | 3 ++ piet-gpu-types/src/scene.rs | 11 ++++- piet-gpu/shader/annotated.h | 81 +++++++++++++++++++++++++------- piet-gpu/shader/binning.comp | 23 ++++----- piet-gpu/shader/binning.spv | Bin 21800 -> 22016 bytes piet-gpu/shader/bins.h | 6 ++- piet-gpu/shader/coarse.comp | 34 ++++++++++---- piet-gpu/shader/coarse.spv | Bin 30280 -> 33272 bytes piet-gpu/shader/elements.comp | 24 +++++++--- piet-gpu/shader/elements.spv | Bin 45068 -> 45312 bytes piet-gpu/shader/scene.h | 21 +++++---- piet-gpu/src/pico_svg.rs | 4 +- piet-gpu/src/render_ctx.rs | 22 ++++++--- 14 files changed, 175 insertions(+), 67 deletions(-) diff --git a/piet-gpu-types/src/annotated.rs b/piet-gpu-types/src/annotated.rs index 247ab12..f7a6ad6 100644 --- a/piet-gpu-types/src/annotated.rs +++ b/piet-gpu-types/src/annotated.rs @@ -3,7 +3,14 @@ use piet_gpu_derive::piet_gpu; piet_gpu! { #[gpu_write] mod annotated { - struct AnnoLineSeg { + struct AnnoFillLineSeg { + p0: [f32; 2], + p1: [f32; 2], + // A note: the layout of this struct is shared with + // AnnoStrokeLineSeg. In that case, we actually write + // [0.0, 0.0] as the stroke field, to minimize divergence. + } + struct AnnoStrokeLineSeg { p0: [f32; 2], p1: [f32; 2], // halfwidth in both x and y for binning @@ -35,8 +42,8 @@ piet_gpu! { } enum Annotated { Nop, - // The segments need a flag to indicate fill/stroke - Line(AnnoLineSeg), + FillLine(AnnoFillLineSeg), + StrokeLine(AnnoStrokeLineSeg), Quad(AnnoQuadSeg), Cubic(AnnoCubicSeg), Stroke(AnnoStroke), diff --git a/piet-gpu-types/src/bins.rs b/piet-gpu-types/src/bins.rs index 88f16f1..1ac2413 100644 --- a/piet-gpu-types/src/bins.rs +++ b/piet-gpu-types/src/bins.rs @@ -7,6 +7,9 @@ piet_gpu! { mod bins { struct BinInstance { element_ix: u32, + // Right edge of the bounding box of the associated fill + // element; used in backdrop computation. + right_edge: f32, } struct BinChunk { diff --git a/piet-gpu-types/src/scene.rs b/piet-gpu-types/src/scene.rs index 7451c9c..5792c94 100644 --- a/piet-gpu-types/src/scene.rs +++ b/piet-gpu-types/src/scene.rs @@ -85,8 +85,15 @@ piet_gpu! { } enum Element { Nop, - // The segments need a flag to indicate fill/stroke - Line(LineSeg), + // Another approach to encoding would be to use a single + // variant but have a bool for fill/stroke. This could be + // packed into the tag, so the on-the-wire representation + // would be very similar to what's here. + StrokeLine(LineSeg), + FillLine(LineSeg), + + // Note: we'll need to handle the stroke/fill distinction + // for these as well, when we do flattening on the GPU. Quad(QuadSeg), Cubic(CubicSeg), Stroke(Stroke), diff --git a/piet-gpu/shader/annotated.h b/piet-gpu/shader/annotated.h index a3fc464..9812264 100644 --- a/piet-gpu/shader/annotated.h +++ b/piet-gpu/shader/annotated.h @@ -1,6 +1,10 @@ // Code auto-generated by piet-gpu-derive -struct AnnoLineSegRef { +struct AnnoFillLineSegRef { + uint offset; +}; + +struct AnnoStrokeLineSegRef { uint offset; }; @@ -24,16 +28,27 @@ struct AnnotatedRef { uint offset; }; -struct AnnoLineSeg { +struct AnnoFillLineSeg { + vec2 p0; + vec2 p1; +}; + +#define AnnoFillLineSeg_size 16 + +AnnoFillLineSegRef AnnoFillLineSeg_index(AnnoFillLineSegRef ref, uint index) { + return AnnoFillLineSegRef(ref.offset + index * AnnoFillLineSeg_size); +} + +struct AnnoStrokeLineSeg { vec2 p0; vec2 p1; vec2 stroke; }; -#define AnnoLineSeg_size 24 +#define AnnoStrokeLineSeg_size 24 -AnnoLineSegRef AnnoLineSeg_index(AnnoLineSegRef ref, uint index) { - return AnnoLineSegRef(ref.offset + index * AnnoLineSeg_size); +AnnoStrokeLineSegRef AnnoStrokeLineSeg_index(AnnoStrokeLineSegRef ref, uint index) { + return AnnoStrokeLineSegRef(ref.offset + index * AnnoStrokeLineSeg_size); } struct AnnoQuadSeg { @@ -87,18 +102,39 @@ AnnoStrokeRef AnnoStroke_index(AnnoStrokeRef ref, uint index) { } #define Annotated_Nop 0 -#define Annotated_Line 1 -#define Annotated_Quad 2 -#define Annotated_Cubic 3 -#define Annotated_Stroke 4 -#define Annotated_Fill 5 +#define Annotated_FillLine 1 +#define Annotated_StrokeLine 2 +#define Annotated_Quad 3 +#define Annotated_Cubic 4 +#define Annotated_Stroke 5 +#define Annotated_Fill 6 #define Annotated_size 44 AnnotatedRef Annotated_index(AnnotatedRef ref, uint index) { return AnnotatedRef(ref.offset + index * Annotated_size); } -AnnoLineSeg AnnoLineSeg_read(AnnoLineSegRef ref) { +AnnoFillLineSeg AnnoFillLineSeg_read(AnnoFillLineSegRef 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]; + AnnoFillLineSeg s; + s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); + s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); + return s; +} + +void AnnoFillLineSeg_write(AnnoFillLineSegRef ref, AnnoFillLineSeg s) { + uint ix = ref.offset >> 2; + annotated[ix + 0] = floatBitsToUint(s.p0.x); + annotated[ix + 1] = floatBitsToUint(s.p0.y); + annotated[ix + 2] = floatBitsToUint(s.p1.x); + annotated[ix + 3] = floatBitsToUint(s.p1.y); +} + +AnnoStrokeLineSeg AnnoStrokeLineSeg_read(AnnoStrokeLineSegRef ref) { uint ix = ref.offset >> 2; uint raw0 = annotated[ix + 0]; uint raw1 = annotated[ix + 1]; @@ -106,14 +142,14 @@ AnnoLineSeg AnnoLineSeg_read(AnnoLineSegRef ref) { uint raw3 = annotated[ix + 3]; uint raw4 = annotated[ix + 4]; uint raw5 = annotated[ix + 5]; - AnnoLineSeg s; + AnnoStrokeLineSeg s; s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); s.stroke = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); return s; } -void AnnoLineSeg_write(AnnoLineSegRef ref, AnnoLineSeg s) { +void AnnoStrokeLineSeg_write(AnnoStrokeLineSegRef ref, AnnoStrokeLineSeg s) { uint ix = ref.offset >> 2; annotated[ix + 0] = floatBitsToUint(s.p0.x); annotated[ix + 1] = floatBitsToUint(s.p0.y); @@ -239,8 +275,12 @@ uint Annotated_tag(AnnotatedRef ref) { return annotated[ref.offset >> 2]; } -AnnoLineSeg Annotated_Line_read(AnnotatedRef ref) { - return AnnoLineSeg_read(AnnoLineSegRef(ref.offset + 4)); +AnnoFillLineSeg Annotated_FillLine_read(AnnotatedRef ref) { + return AnnoFillLineSeg_read(AnnoFillLineSegRef(ref.offset + 4)); +} + +AnnoStrokeLineSeg Annotated_StrokeLine_read(AnnotatedRef ref) { + return AnnoStrokeLineSeg_read(AnnoStrokeLineSegRef(ref.offset + 4)); } AnnoQuadSeg Annotated_Quad_read(AnnotatedRef ref) { @@ -263,9 +303,14 @@ void Annotated_Nop_write(AnnotatedRef ref) { annotated[ref.offset >> 2] = Annotated_Nop; } -void Annotated_Line_write(AnnotatedRef ref, AnnoLineSeg s) { - annotated[ref.offset >> 2] = Annotated_Line; - AnnoLineSeg_write(AnnoLineSegRef(ref.offset + 4), s); +void Annotated_FillLine_write(AnnotatedRef ref, AnnoFillLineSeg s) { + annotated[ref.offset >> 2] = Annotated_FillLine; + AnnoFillLineSeg_write(AnnoFillLineSegRef(ref.offset + 4), s); +} + +void Annotated_StrokeLine_write(AnnotatedRef ref, AnnoStrokeLineSeg s) { + annotated[ref.offset >> 2] = Annotated_StrokeLine; + AnnoStrokeLineSeg_write(AnnoStrokeLineSegRef(ref.offset + 4), s); } void Annotated_Quad_write(AnnotatedRef ref, AnnoQuadSeg s) { diff --git a/piet-gpu/shader/binning.comp b/piet-gpu/shader/binning.comp index cba0217..60b12e0 100644 --- a/piet-gpu/shader/binning.comp +++ b/piet-gpu/shader/binning.comp @@ -84,8 +84,9 @@ void main() { int x0 = 0, y0 = 0, x1 = 0, y1 = 0; float my_right_edge = INFINITY; switch (tag) { - case Annotated_Line: - AnnoLineSeg line = Annotated_Line_read(ref); + case Annotated_FillLine: + case Annotated_StrokeLine: + AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); x0 = int(floor((min(line.p0.x, line.p1.x) - line.stroke.x) * SX)); y0 = int(floor((min(line.p0.y, line.p1.y) - line.stroke.y) * SY)); x1 = int(ceil((max(line.p0.x, line.p1.x) + line.stroke.x) * SX)); @@ -107,7 +108,7 @@ void main() { // If the last element in this partition is a fill edge, then we need to do a // look-forward to find the right edge of its corresponding fill. That data is // recorded in aggregates computed in the element processing pass. - if (gl_LocalInvocationID.x == N_TILE - 1 && tag == Annotated_Line) { + if (gl_LocalInvocationID.x == N_TILE - 1 && tag == Annotated_FillLine) { uint aggregate_ix = (my_tile + 1) * ELEMENT_BINNING_RATIO; // This is sequential but the expectation is that the amount of // look-forward is small (performance may degrade in the case @@ -165,9 +166,9 @@ void main() { uint chunk_new_start; // Refactor to reduce code duplication? if (chunk_n > 0) { - uint next_chunk = chunk_ref.offset + BinChunk_size + chunk_n * 4; - if (next_chunk + BinChunk_size + min(24, element_count * 4) > wr_limit) { - uint alloc_amount = max(BIN_ALLOC, BinChunk_size + element_count * 4); + uint next_chunk = chunk_ref.offset + BinChunk_size + chunk_n * BinInstance_size; + if (next_chunk + BinChunk_size + min(24, element_count * BinInstance_size) > wr_limit) { + uint alloc_amount = max(BIN_ALLOC, BinChunk_size + element_count * BinInstance_size); // could try to reduce fragmentation if BIN_ALLOC is only a bit above needed next_chunk = atomicAdd(alloc, alloc_amount); wr_limit = next_chunk + alloc_amount; @@ -176,10 +177,10 @@ void main() { chunk_ref = BinChunkRef(next_chunk); } BinInstanceRef instance_ref = BinInstanceRef(chunk_ref.offset + BinChunk_size); - if (instance_ref.offset + element_count * 4 > wr_limit) { + if (instance_ref.offset + element_count * BinInstance_size > wr_limit) { chunk_end = wr_limit; - chunk_n = (wr_limit - instance_ref.offset) / 4; - uint alloc_amount = max(BIN_ALLOC, BinChunk_size + (element_count - chunk_n) * 4); + chunk_n = (wr_limit - instance_ref.offset) / BinInstance_size; + uint alloc_amount = max(BIN_ALLOC, BinChunk_size + (element_count - chunk_n) * BinInstance_size); chunk_new_start = atomicAdd(alloc, alloc_amount); wr_limit = chunk_new_start + alloc_amount; BinChunk_write(chunk_ref, BinChunk(chunk_n, BinChunkRef(chunk_new_start))); @@ -209,11 +210,11 @@ void main() { if (my_slice > 0) { idx += count[my_slice - 1][bin_ix]; } - uint out_offset = sh_chunk_start[bin_ix] + idx * 4; + uint out_offset = sh_chunk_start[bin_ix] + idx * BinInstance_size; if (out_offset >= sh_chunk_end[bin_ix]) { out_offset += sh_chunk_jump[bin_ix]; } - BinInstance_write(BinInstanceRef(out_offset), BinInstance(element_ix)); + BinInstance_write(BinInstanceRef(out_offset), BinInstance(element_ix, my_right_edge)); } x++; if (x == x1) { diff --git a/piet-gpu/shader/binning.spv b/piet-gpu/shader/binning.spv index a5379e6dad7ab1566cc2378b2fa9ed054c62b1a3..4fda673c4aea604390b10ba4ceb6b93a76378ee0 100644 GIT binary patch literal 22016 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 T3`LvYEyiC0R`>oAdw=~e9^Xm4 literal 21800 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 diff --git a/piet-gpu/shader/bins.h b/piet-gpu/shader/bins.h index 3ce06e0..85f7536 100644 --- a/piet-gpu/shader/bins.h +++ b/piet-gpu/shader/bins.h @@ -10,9 +10,10 @@ struct BinChunkRef { struct BinInstance { uint element_ix; + float right_edge; }; -#define BinInstance_size 4 +#define BinInstance_size 8 BinInstanceRef BinInstance_index(BinInstanceRef ref, uint index) { return BinInstanceRef(ref.offset + index * BinInstance_size); @@ -32,14 +33,17 @@ BinChunkRef BinChunk_index(BinChunkRef ref, uint index) { BinInstance BinInstance_read(BinInstanceRef ref) { uint ix = ref.offset >> 2; uint raw0 = bins[ix + 0]; + uint raw1 = bins[ix + 1]; BinInstance s; s.element_ix = raw0; + s.right_edge = uintBitsToFloat(raw1); return s; } void BinInstance_write(BinInstanceRef ref, BinInstance s) { uint ix = ref.offset >> 2; bins[ix + 0] = s.element_ix; + bins[ix + 1] = floatBitsToUint(s.right_edge); } BinChunk BinChunk_read(BinChunkRef ref) { diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index e331076..57abd73 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -30,6 +30,7 @@ layout(set = 0, binding = 3) buffer PtclBuf { #define N_RINGBUF 512 shared uint sh_elements[N_RINGBUF]; +shared float sh_right_edge[N_RINGBUF]; shared uint sh_chunk[N_WG]; shared uint sh_chunk_next[N_WG]; shared uint sh_chunk_n[N_WG]; @@ -41,6 +42,7 @@ shared uint sh_selected_n; shared uint sh_elements_ref; shared uint sh_bitmaps[N_SLICE][N_TILE]; +shared uint sh_backdrop[N_SLICE][N_TILE]; // scale factors useful for converting coordinates to tiles #define SX (1.0 / float(TILE_WIDTH_PX)) @@ -113,6 +115,7 @@ void main() { while (true) { for (uint i = 0; i < N_SLICE; i++) { sh_bitmaps[i][th_ix] = 0; + sh_backdrop[i][th_ix] = 0; } while (wr_ix - rd_ix <= N_TILE) { @@ -157,8 +160,10 @@ void main() { } BinInstanceRef inst_ref = BinInstanceRef(sh_elements_ref); if (th_ix < chunk_n) { - uint el = BinInstance_read(BinInstance_index(inst_ref, th_ix)).element_ix; - sh_elements[(wr_ix + th_ix) % N_RINGBUF] = el; + BinInstance inst = BinInstance_read(BinInstance_index(inst_ref, th_ix)); + uint wr_el_ix = (wr_ix + th_ix) % N_RINGBUF; + sh_elements[wr_el_ix] = inst.element_ix; + sh_right_edge[wr_el_ix] = inst.right_edge; } wr_ix += chunk_n; } @@ -180,8 +185,9 @@ void main() { // Bounding box of element in pixel coordinates. float xmin, xmax, ymin, ymax; switch (tag) { - case Annotated_Line: - AnnoLineSeg line = Annotated_Line_read(ref); + case Annotated_FillLine: + case Annotated_StrokeLine: + AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); xmin = min(line.p0.x, line.p1.x) - line.stroke.x; xmax = max(line.p0.x, line.p1.x) + line.stroke.x; ymin = min(line.p0.y, line.p1.y) - line.stroke.y; @@ -214,7 +220,7 @@ void main() { break; } - // Draw the coverage area into the bitmaks. This uses an algorithm + // Draw the coverage area into the bitmasks. This uses an algorithm // that computes the coverage of a span for given scanline. // Compute bounding box in tiles and clip to this bin. @@ -263,15 +269,27 @@ void main() { tag = Annotated_tag(ref); switch (tag) { - case Annotated_Line: - AnnoLineSeg line = Annotated_Line_read(ref); + case Annotated_FillLine: + case Annotated_StrokeLine: + AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); Segment seg = Segment(line.p0, line.p1); alloc_chunk(chunk_n_segs, seg_chunk_ref, first_seg_chunk, seg_limit); Segment_write(SegmentRef(seg_chunk_ref.offset + SegChunk_size + Segment_size * chunk_n_segs), seg); chunk_n_segs++; break; case Annotated_Fill: - chunk_n_segs = 0; + if (chunk_n_segs > 0) { + AnnoFill fill = Annotated_Fill_read(ref); + SegChunk_write(seg_chunk_ref, SegChunk(chunk_n_segs, SegChunkRef(0))); + seg_chunk_ref.offset += SegChunk_size + Segment_size * chunk_n_segs; + CmdFill cmd_fill; + cmd_fill.seg_ref = first_seg_chunk.offset; + cmd_fill.rgba_color = fill.rgba_color; + alloc_cmd(cmd_ref, cmd_limit); + Cmd_Fill_write(cmd_ref, cmd_fill); + cmd_ref.offset += Cmd_size; + chunk_n_segs = 0; + } break; case Annotated_Stroke: if (chunk_n_segs > 0) { diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index d61b227981fefe57ee154d9dd72928df4528cb29..e201c5ee594c6bd6ed8b29c3756015d10c16c85a 100644 GIT binary patch literal 33272 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 literal 30280 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 b8Mxeka(#?xuHJv{gUqLOxi8!wIY<5v^rU{n diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index 15ad80d..341952b 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -98,8 +98,9 @@ State map_element(ElementRef ref) { c.linewidth = 1.0; // TODO should be 0.0 c.flags = 0; switch (tag) { - case Element_Line: - LineSeg line = Element_Line_read(ref); + case Element_FillLine: + case Element_StrokeLine: + LineSeg line = Element_FillLine_read(ref); c.bbox.xy = min(line.p0, line.p1); c.bbox.zw = max(line.p0, line.p1); break; @@ -272,13 +273,22 @@ void main() { AnnotatedRef out_ref = AnnotatedRef((ix + i) * Annotated_size); uint tag = Element_tag(this_ref); switch (tag) { - case Element_Line: - LineSeg line = Element_Line_read(this_ref); - AnnoLineSeg anno_line; + case Element_FillLine: + case Element_StrokeLine: + LineSeg line = Element_StrokeLine_read(this_ref); + AnnoStrokeLineSeg anno_line; anno_line.p0 = st.mat.xz * line.p0.x + st.mat.yw * line.p0.y + st.translate; anno_line.p1 = st.mat.xz * line.p1.x + st.mat.yw * line.p1.y + st.translate; - anno_line.stroke = get_linewidth(st); - Annotated_Line_write(out_ref, anno_line); + if (tag == Element_StrokeLine) { + anno_line.stroke = get_linewidth(st); + } else { + anno_line.stroke = vec2(0.0); + } + // We do encoding a bit by hand to minimize divergence. Another approach + // would be to have a fill/stroke bool. + uint out_tag = tag == Element_FillLine ? Annotated_FillLine : Annotated_StrokeLine; + annotated[out_ref.offset >> 2] = out_tag; + AnnoStrokeLineSeg_write(AnnoStrokeLineSegRef(out_ref.offset + 4), anno_line); break; case Element_Stroke: Stroke stroke = Element_Stroke_read(this_ref); diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index ff0ae2d456ea352ee946cbe946a3e9b56ffc4853..c947240a374822edb8c39f605604b116253e8cd9 100644 GIT binary patch literal 45312 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 literal 45068 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 2]; } -LineSeg Element_Line_read(ElementRef ref) { +LineSeg Element_StrokeLine_read(ElementRef ref) { + return LineSeg_read(LineSegRef(ref.offset + 4)); +} + +LineSeg Element_FillLine_read(ElementRef ref) { return LineSeg_read(LineSegRef(ref.offset + 4)); } diff --git a/piet-gpu/src/pico_svg.rs b/piet-gpu/src/pico_svg.rs index 9cf5cc3..b2f054c 100644 --- a/piet-gpu/src/pico_svg.rs +++ b/piet-gpu/src/pico_svg.rs @@ -61,8 +61,8 @@ impl PicoSvg { for item in &self.items { match item { Item::Fill(fill_item) => { - //rc.fill(&fill_item.path, &fill_item.color); - rc.stroke(&fill_item.path, &fill_item.color, 1.0); + rc.fill(&fill_item.path, &fill_item.color); + //rc.stroke(&fill_item.path, &fill_item.color, 1.0); } Item::Stroke(stroke_item) => { rc.stroke(&stroke_item.path, &stroke_item.color, stroke_item.width); diff --git a/piet-gpu/src/render_ctx.rs b/piet-gpu/src/render_ctx.rs index e01a6ae..8d68b0c 100644 --- a/piet-gpu/src/render_ctx.rs +++ b/piet-gpu/src/render_ctx.rs @@ -94,7 +94,7 @@ impl RenderContext for PietGpuRenderContext { } let brush = brush.make_brush(self, || shape.bounding_box()).into_owned(); let path = shape.to_bez_path(TOLERANCE); - self.encode_path(path); + self.encode_path(path, false); match brush { PietGpuBrush::Solid(rgba_color) => { let stroke = Stroke { rgba_color }; @@ -116,7 +116,7 @@ impl RenderContext for PietGpuRenderContext { fn fill(&mut self, shape: impl Shape, brush: &impl IntoBrush) { let brush = brush.make_brush(self, || shape.bounding_box()).into_owned(); let path = shape.to_bez_path(TOLERANCE); - self.encode_path(path); + self.encode_path(path, true); match brush { PietGpuBrush::Solid(rgba_color) => { let fill = Fill { rgba_color }; @@ -198,7 +198,15 @@ impl RenderContext for PietGpuRenderContext { } impl PietGpuRenderContext { - fn encode_path(&mut self, path: impl Iterator) { + fn encode_line_seg(&mut self, seg: LineSeg, is_fill: bool) { + if is_fill { + self.elements.push(Element::FillLine(seg)); + } else { + self.elements.push(Element::StrokeLine(seg)); + } + } + + fn encode_path(&mut self, path: impl Iterator, is_fill: bool) { let flatten = true; if flatten { let mut start_pt = None; @@ -215,7 +223,7 @@ impl PietGpuRenderContext { p0: last_pt.unwrap(), p1: scene_pt, }; - self.elements.push(Element::Line(seg)); + self.encode_line_seg(seg, is_fill); last_pt = Some(scene_pt); } PathEl::ClosePath => { @@ -224,7 +232,7 @@ impl PietGpuRenderContext { p0: last, p1: start, }; - self.elements.push(Element::Line(seg)); + self.encode_line_seg(seg, is_fill); } } _ => (), @@ -246,7 +254,7 @@ impl PietGpuRenderContext { p0: last_pt.unwrap(), p1: scene_pt, }; - self.elements.push(Element::Line(seg)); + self.encode_line_seg(seg, is_fill); last_pt = Some(scene_pt); } PathEl::QuadTo(p1, p2) => { @@ -279,7 +287,7 @@ impl PietGpuRenderContext { p0: last, p1: start, }; - self.elements.push(Element::Line(seg)); + self.encode_line_seg(seg, is_fill); } } } From ed4ed307089c3d77b6b2468343a1c612cd2c01f9 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Wed, 20 May 2020 11:48:05 -0700 Subject: [PATCH 3/5] Adding backdrop logic Calculation of backdrops kinda works but with issues, so WIP. --- piet-gpu/shader/binning.comp | 11 +++++- piet-gpu/shader/binning.spv | Bin 22016 -> 22592 bytes piet-gpu/shader/coarse.comp | 64 ++++++++++++++++++++++++++++++----- piet-gpu/shader/coarse.spv | Bin 33272 -> 38016 bytes piet-gpu/src/lib.rs | 2 +- 5 files changed, 67 insertions(+), 10 deletions(-) diff --git a/piet-gpu/shader/binning.comp b/piet-gpu/shader/binning.comp index 60b12e0..138621e 100644 --- a/piet-gpu/shader/binning.comp +++ b/piet-gpu/shader/binning.comp @@ -35,6 +35,8 @@ layout(set = 0, binding = 3) buffer BinsBuf { #define SX (1.0 / float(N_TILE_X * TILE_WIDTH_PX)) #define SY (1.0 / float(N_TILE_Y * TILE_HEIGHT_PX)) +#define TSY (1.0 / float(TILE_HEIGHT_PX)) + // Constant not available in GLSL. Also consider uintBitsToFloat(0x7f800000) #define INFINITY (1.0 / 0.0) @@ -83,6 +85,7 @@ void main() { } int x0 = 0, y0 = 0, x1 = 0, y1 = 0; float my_right_edge = INFINITY; + bool crosses_edge = false; switch (tag) { case Annotated_FillLine: case Annotated_StrokeLine: @@ -91,6 +94,7 @@ void main() { y0 = int(floor((min(line.p0.y, line.p1.y) - line.stroke.y) * SY)); x1 = int(ceil((max(line.p0.x, line.p1.x) + line.stroke.x) * SX)); y1 = int(ceil((max(line.p0.y, line.p1.y) + line.stroke.y) * SY)); + crosses_edge = tag == Annotated_FillLine && ceil(line.p0.y * TSY) != ceil(line.p1.y * TSY); break; case Annotated_Fill: case Annotated_Stroke: @@ -101,7 +105,9 @@ void main() { y0 = int(floor(fill.bbox.y * SY)); x1 = int(ceil(fill.bbox.z * SX)); y1 = int(ceil(fill.bbox.w * SY)); - my_right_edge = x1; + // It probably makes more sense to track x1, to avoid having to redo + // the rounding to tile coords. + my_right_edge = fill.bbox.z; break; } @@ -131,6 +137,9 @@ void main() { } barrier(); } + if (crosses_edge) { + x1 = int(ceil(my_right_edge * SX)); + } // At this point, we run an iterator over the coverage area, // trying to keep divergence low. diff --git a/piet-gpu/shader/binning.spv b/piet-gpu/shader/binning.spv index 4fda673c4aea604390b10ba4ceb6b93a76378ee0..dc1713b5505929835d055744fc3124cd12d0d6e1 100644 GIT binary patch literal 22592 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 literal 22016 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 T3`LvYEyiC0R`>oAdw=~e9^Xm4 diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 57abd73..2389e27 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -43,6 +43,7 @@ shared uint sh_elements_ref; shared uint sh_bitmaps[N_SLICE][N_TILE]; shared uint sh_backdrop[N_SLICE][N_TILE]; +shared uint sh_bd_sign[N_SLICE]; // scale factors useful for converting coordinates to tiles #define SX (1.0 / float(TILE_WIDTH_PX)) @@ -111,7 +112,10 @@ void main() { sh_first_el[th_ix] = chunk.n > 0 ? BinInstance_read(BinInstanceRef(start_chunk + BinChunk_size)).element_ix : ~0; } - uint count = 0; + if (th_ix < N_SLICE) { + sh_bd_sign[th_ix] = 0; + } + int backdrop = 0; while (true) { for (uint i = 0; i < N_SLICE; i++) { sh_bitmaps[i][th_ix] = 0; @@ -174,8 +178,11 @@ void main() { // Read one element, compute coverage. uint tag = Annotated_Nop; AnnotatedRef ref; + float right_edge = 0.0; if (th_ix + rd_ix < wr_ix) { - uint element_ix = sh_elements[(rd_ix + th_ix) % N_RINGBUF]; + uint rd_el_ix = (rd_ix + th_ix) % N_RINGBUF; + uint element_ix = sh_elements[rd_el_ix]; + right_edge = sh_right_edge[rd_el_ix]; ref = AnnotatedRef(element_ix * Annotated_size); tag = Annotated_tag(ref); } @@ -184,6 +191,8 @@ void main() { float a, b, c; // Bounding box of element in pixel coordinates. float xmin, xmax, ymin, ymax; + uint my_slice = th_ix / 32; + uint my_mask = 1 << (th_ix & 31); switch (tag) { case Annotated_FillLine: case Annotated_StrokeLine: @@ -194,6 +203,14 @@ void main() { ymax = max(line.p0.y, line.p1.y) + line.stroke.y; float dx = line.p1.x - line.p0.x; float dy = line.p1.y - line.p0.y; + if (tag == Annotated_FillLine) { + // Set bit for backdrop sign calculation, 1 is +1, 0 is -1. + if (dy < 0) { + atomicOr(sh_bd_sign[my_slice], my_mask); + } else { + atomicAnd(sh_bd_sign[my_slice], ~my_mask); + } + } // Set up for per-scanline coverage formula, below. float invslope = abs(dy) < 1e-9 ? 1e9 : dx / dy; c = abs(invslope) * (0.5 * float(TILE_HEIGHT_PX) + line.stroke.y) * SX; @@ -226,14 +243,14 @@ void main() { // Compute bounding box in tiles and clip to this bin. int x0 = int(floor((xmin - xy0.x) * SX)); int x1 = int(ceil((xmax - xy0.x) * SX)); + int xr = int(ceil((right_edge - xy0.x) * SX)); int y0 = int(floor((ymin - xy0.y) * SY)); int y1 = int(ceil((ymax - xy0.y) * SY)); x0 = clamp(x0, 0, N_TILE_X); x1 = clamp(x1, x0, N_TILE_X); + xr = clamp(xr, 0, N_TILE_X); y0 = clamp(y0, 0, N_TILE_Y); y1 = clamp(y1, y0, N_TILE_Y); - uint my_slice = th_ix / 32; - uint my_mask = 1 << (th_ix & 31); float t = a + b * float(y0); for (uint y = y0; y < y1; y++) { uint xx0 = clamp(int(floor(t - c)), x0, x1); @@ -241,6 +258,15 @@ void main() { for (uint x = xx0; x < xx1; x++) { atomicOr(sh_bitmaps[my_slice][y * N_TILE_X + x], my_mask); } + if (tag == Annotated_FillLine && ymin <= xy0.y + float(y * TILE_HEIGHT_PX)) { + // Assign backdrop to all tiles to the right of the ray crossing the + // top edge of this tile, up to the right edge of the fill bbox. + float xray = t - 0.5 * b; + xx0 = max(int(ceil(xray)), 0); + for (uint x = xx0; x < xr; x++) { + atomicOr(sh_backdrop[my_slice][y * N_TILE_X + x], my_mask); + } + } t += b; } barrier(); @@ -248,20 +274,34 @@ void main() { // Output elements for this tile, based on bitmaps. uint slice_ix = 0; uint bitmap = sh_bitmaps[0][th_ix]; + uint bd_bitmap = sh_backdrop[0][th_ix]; + uint combined = bitmap | bd_bitmap; while (true) { - if (bitmap == 0) { + if (combined == 0) { slice_ix++; if (slice_ix == N_SLICE) { break; } bitmap = sh_bitmaps[slice_ix][th_ix]; - if (bitmap == 0) { + bd_bitmap = sh_backdrop[slice_ix][th_ix]; + combined = bitmap | bd_bitmap; + if (combined == 0) { continue; } } - uint element_ref_ix = slice_ix * 32 + findLSB(bitmap); + uint element_ref_ix = slice_ix * 32 + findLSB(combined); uint element_ix = sh_elements[(rd_ix + element_ref_ix) % N_RINGBUF]; + // TODO: use bit magic to aggregate this calculation. + if ((bd_bitmap & (1 << (element_ref_ix & 31))) != 0) { + if ((sh_bd_sign[slice_ix] & (1 << (element_ref_ix & 31))) != 0) { + backdrop += 1; + } else { + backdrop -= 1; + } + } + + if ((bitmap & (1 << (element_ref_ix & 31))) != 0) { // At this point, we read the element again from global memory. // If that turns out to be expensive, maybe we can pack it into // shared memory (or perhaps just the tag). @@ -284,12 +324,19 @@ void main() { seg_chunk_ref.offset += SegChunk_size + Segment_size * chunk_n_segs; CmdFill cmd_fill; cmd_fill.seg_ref = first_seg_chunk.offset; + cmd_fill.backdrop = backdrop; cmd_fill.rgba_color = fill.rgba_color; alloc_cmd(cmd_ref, cmd_limit); Cmd_Fill_write(cmd_ref, cmd_fill); cmd_ref.offset += Cmd_size; chunk_n_segs = 0; + } else if (backdrop != 0) { + AnnoFill fill = Annotated_Fill_read(ref); + alloc_cmd(cmd_ref, cmd_limit); + Cmd_Solid_write(cmd_ref, CmdSolid(fill.rgba_color)); + cmd_ref.offset += Cmd_size; } + backdrop = 0; break; case Annotated_Stroke: if (chunk_n_segs > 0) { @@ -307,9 +354,10 @@ void main() { } break; } + } // clear LSB - bitmap &= bitmap - 1; + combined &= combined - 1; } barrier(); diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index e201c5ee594c6bd6ed8b29c3756015d10c16c85a..bc097e44388cf90bb53859a8801d1fe1b4f343e3 100644 GIT binary patch literal 38016 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

3dIb`ZoUe;A+OOA9;NDs(rIh_lB!E zuA`U-$Gk6CeIJT3oLe>jhA8u9-MT+6!q4kmiu=PoabAs2qCUUC7t~mv3n{L}PpGqR z4kv#0jcrdTxcBu*HP5*AgWFgBrm7RJb`6?)U?|wjJ)muW%4CZDinHH_fz7krZ^O~l zGiM{fYR*sk?*coH?7@+6{nYJ$G_{xgYa2yTvwv~+U^lpR4~{`o&mKIW_IK{af|IXn zCD%XW8CTeo>v%NvjAsH^&A8bE2ZGfnQjF`^)Z7Ef+uE2XVw(gu4}D!*xxUW3V|1>Q zQ%~(%&hbHL>dEO~u$u2e$@>tvYn<=vQ{d*Oo_15gw$+w)-v^g#^8>hk>aNXU)LyQQ zwnHgu<}J?J{1Du_Hb7TRaWU$XxeYB;|Q^59_wLBGE?mxLc V#%$h?&3%yhv@Z9B`y=Pb{{z)BoU8x< diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index 341952b..bdb4e0d 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -34,14 +34,14 @@ layout(set = 0, binding = 2) buffer AnnotatedBuf { #include "state.h" #include "annotated.h" -#define StateBuf_stride (4 + 2 * State_size) +#define StateBuf_stride (8 + 2 * State_size) StateRef state_aggregate_ref(uint partition_ix) { - return StateRef(8 + partition_ix * StateBuf_stride); + return StateRef(12 + partition_ix * StateBuf_stride); } StateRef state_prefix_ref(uint partition_ix) { - return StateRef(8 + partition_ix * StateBuf_stride + State_size); + return StateRef(12 + partition_ix * StateBuf_stride + State_size); } uint state_flag_index(uint partition_ix) { @@ -81,13 +81,12 @@ State combine_state(State a, State b) { c.translate.x = a.mat.x * b.translate.x + a.mat.z * b.translate.y + a.translate.x; c.translate.y = a.mat.y * b.translate.x + a.mat.w * b.translate.y + a.translate.y; c.linewidth = (b.flags & FLAG_SET_LINEWIDTH) == 0 ? a.linewidth : b.linewidth; - c.right_edge = (a.flags & FLAG_SET_BBOX) != 0 ? a.right_edge : (a.flags & FLAG_RESET_BBOX) != 0 ? a.bbox.z : c.right_edge; c.flags = (a.flags & (FLAG_SET_LINEWIDTH | FLAG_SET_BBOX)) | b.flags; c.flags |= (a.flags & FLAG_RESET_BBOX) >> 1; return c; } -State map_element(ElementRef ref) { +State map_element(ElementRef ref, inout bool is_fill) { // TODO: it would *probably* be more efficient to make the memory read patterns less // divergent, though it would be more wasted memory. uint tag = Element_tag(ref); @@ -97,6 +96,7 @@ State map_element(ElementRef ref) { c.translate = vec2(0.0, 0.0); c.linewidth = 1.0; // TODO should be 0.0 c.flags = 0; + is_fill = false; switch (tag) { case Element_FillLine: case Element_StrokeLine: @@ -115,6 +115,8 @@ State map_element(ElementRef ref) { c.bbox.zw = max(max(cubic.p0, cubic.p1), max(cubic.p2, cubic.p3)); break; case Element_Fill: + is_fill = true; + // fall-through case Element_Stroke: c.flags = FLAG_RESET_BBOX; break; @@ -145,9 +147,10 @@ shared vec4 sh_mat[WG_SIZE]; shared vec2 sh_translate[WG_SIZE]; shared vec4 sh_bbox[WG_SIZE]; shared float sh_width[WG_SIZE]; -shared float sh_right_edge[WG_SIZE]; shared uint sh_flags[WG_SIZE]; +shared uint sh_min_fill; + shared uint sh_tile_ix; shared State sh_prefix; @@ -157,6 +160,7 @@ void main() { // 4.4 of prefix sum paper). if (gl_LocalInvocationID.x == 0) { sh_tile_ix = atomicAdd(state[0], 1); + sh_min_fill = ~0; } barrier(); uint tile_ix = sh_tile_ix; @@ -164,18 +168,24 @@ void main() { uint ix = tile_ix * PARTITION_SIZE + gl_LocalInvocationID.x * N_ROWS; ElementRef ref = ElementRef(ix * Element_size); - th_state[0] = map_element(ref); + bool is_fill; + uint my_min_fill = ~0; + th_state[0] = map_element(ref, is_fill); + if (is_fill) my_min_fill = ix; for (uint i = 1; i < N_ROWS; i++) { // discussion question: would it be faster to load using more coherent patterns // into thread memory? This is kinda strided. - th_state[i] = combine_state(th_state[i - 1], map_element(Element_index(ref, i))); + th_state[i] = combine_state(th_state[i - 1], map_element(Element_index(ref, i), is_fill)); + if (is_fill && my_min_fill == ~0) { + my_min_fill = ix + i; + } } + atomicMin(sh_min_fill, my_min_fill); State agg = th_state[N_ROWS - 1]; sh_mat[gl_LocalInvocationID.x] = agg.mat; sh_translate[gl_LocalInvocationID.x] = agg.translate; sh_bbox[gl_LocalInvocationID.x] = agg.bbox; sh_width[gl_LocalInvocationID.x] = agg.linewidth; - sh_right_edge[gl_LocalInvocationID.x] = agg.right_edge; sh_flags[gl_LocalInvocationID.x] = agg.flags; for (uint i = 0; i < LG_WG_SIZE; i++) { barrier(); @@ -194,7 +204,6 @@ void main() { sh_translate[gl_LocalInvocationID.x] = agg.translate; sh_bbox[gl_LocalInvocationID.x] = agg.bbox; sh_width[gl_LocalInvocationID.x] = agg.linewidth; - sh_right_edge[gl_LocalInvocationID.x] = agg.right_edge; sh_flags[gl_LocalInvocationID.x] = agg.flags; } @@ -203,7 +212,6 @@ void main() { exclusive.mat = vec4(1.0, 0.0, 0.0, 1.0); exclusive.translate = vec2(0.0, 0.0); exclusive.linewidth = 1.0; //TODO should be 0.0 - exclusive.right_edge = 0.0; exclusive.flags = 0; // Publish aggregate for this partition @@ -244,6 +252,7 @@ void main() { } } barrier(); + my_min_fill = sh_min_fill; if (tile_ix != 0) { exclusive = sh_prefix; } @@ -256,12 +265,17 @@ void main() { other.translate = sh_translate[ix]; other.bbox = sh_bbox[ix]; other.linewidth = sh_width[ix]; - other.right_edge = sh_right_edge[ix]; other.flags = sh_flags[ix]; row = combine_state(row, other); } + if (my_min_fill == ~0 && gl_LocalInvocationID.x == 0) { + state[state_flag_index(tile_ix) + 1] = 0x7f800000; // infinity + } for (uint i = 0; i < N_ROWS; i++) { State st = combine_state(row, th_state[i]); + if (my_min_fill == ix + i) { + state[state_flag_index(tile_ix) + 1] = floatBitsToUint(st.bbox.z); + } // We write the state now for development purposes, but the // actual goal is to write transformed and annotated elements. //State_write(StateRef((ix + i) * State_size), st); diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index c947240a374822edb8c39f605604b116253e8cd9..962bd0ac664fc8283b64a2a94fa207832f65fff5 100644 GIT binary patch literal 45536 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 literal 45312 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 diff --git a/piet-gpu/shader/setup.h b/piet-gpu/shader/setup.h index 6b00661..b913086 100644 --- a/piet-gpu/shader/setup.h +++ b/piet-gpu/shader/setup.h @@ -58,7 +58,7 @@ // This is the ratio of the number of elements in a binning workgroup // over the number of elements in a partition workgroup. -#define ELEMENT_BINNING_RATIO 4 +#define ELEMENT_BINNING_RATIO 2 #define BIN_INITIAL_ALLOC 64 #define BIN_ALLOC 256 diff --git a/piet-gpu/shader/state.h b/piet-gpu/shader/state.h index bc6192f..2547b93 100644 --- a/piet-gpu/shader/state.h +++ b/piet-gpu/shader/state.h @@ -9,11 +9,10 @@ struct State { vec2 translate; vec4 bbox; float linewidth; - float right_edge; uint flags; }; -#define State_size 52 +#define State_size 48 StateRef State_index(StateRef ref, uint index) { return StateRef(ref.offset + index * State_size); @@ -33,14 +32,12 @@ State State_read(StateRef ref) { uint raw9 = state[ix + 9]; uint raw10 = state[ix + 10]; uint raw11 = state[ix + 11]; - uint raw12 = state[ix + 12]; State s; s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3)); s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); s.bbox = vec4(uintBitsToFloat(raw6), uintBitsToFloat(raw7), uintBitsToFloat(raw8), uintBitsToFloat(raw9)); s.linewidth = uintBitsToFloat(raw10); - s.right_edge = uintBitsToFloat(raw11); - s.flags = raw12; + s.flags = raw11; return s; } @@ -57,7 +54,6 @@ void State_write(StateRef ref, State s) { state[ix + 8] = floatBitsToUint(s.bbox.z); state[ix + 9] = floatBitsToUint(s.bbox.w); state[ix + 10] = floatBitsToUint(s.linewidth); - state[ix + 11] = floatBitsToUint(s.right_edge); - state[ix + 12] = s.flags; + state[ix + 11] = s.flags; } diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 65bbe5c..70b02f5 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -46,8 +46,8 @@ pub fn render_scene(rc: &mut impl RenderContext) { let circle = Circle::new(center, radius); rc.fill(circle, &color); } - /* let mut path = BezPath::new(); + /* path.move_to((100.0, 1150.0)); path.line_to((200.0, 1200.0)); path.line_to((150.0, 1250.0)); diff --git a/piet-gpu/src/render_ctx.rs b/piet-gpu/src/render_ctx.rs index 8d68b0c..da234de 100644 --- a/piet-gpu/src/render_ctx.rs +++ b/piet-gpu/src/render_ctx.rs @@ -215,6 +215,7 @@ impl PietGpuRenderContext { match el { PathEl::MoveTo(p) => { let scene_pt = to_f32_2(p); + start_pt = Some(scene_pt); last_pt = Some(scene_pt); } PathEl::LineTo(p) => { @@ -228,11 +229,13 @@ impl PietGpuRenderContext { } PathEl::ClosePath => { if let (Some(start), Some(last)) = (start_pt.take(), last_pt.take()) { - let seg = LineSeg { - p0: last, - p1: start, - }; - self.encode_line_seg(seg, is_fill); + if last != start { + let seg = LineSeg { + p0: last, + p1: start, + }; + self.encode_line_seg(seg, is_fill); + } } } _ => (), @@ -246,6 +249,7 @@ impl PietGpuRenderContext { match el { PathEl::MoveTo(p) => { let scene_pt = to_f32_2(p); + start_pt = Some(scene_pt); last_pt = Some(scene_pt); } PathEl::LineTo(p) => { @@ -283,11 +287,13 @@ impl PietGpuRenderContext { } PathEl::ClosePath => { if let (Some(start), Some(last)) = (start_pt.take(), last_pt.take()) { - let seg = LineSeg { - p0: last, - p1: start, - }; - self.encode_line_seg(seg, is_fill); + if last != start { + let seg = LineSeg { + p0: last, + p1: start, + }; + self.encode_line_seg(seg, is_fill); + } } } } From 7d040dff37d98ba759303a23ab29aeac65384576 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 22 May 2020 07:13:27 -0700 Subject: [PATCH 5/5] Bit magic for backdrop accumulation Use bit counting rather than iterating backdrop increments one by one. A nice if not huge speedup. --- piet-gpu/shader/coarse.comp | 38 +++++++++++++++++++----------------- piet-gpu/shader/coarse.spv | Bin 43040 -> 43268 bytes 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 03c4535..c77c6b8 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -80,6 +80,14 @@ void alloc_chunk(inout uint chunk_n_segs, inout SegChunkRef seg_chunk_ref, } } +// Accumulate delta to backdrop. +// +// Each bit for which bd_bitmap is 1 and bd_sign is 1 counts as +1, and each +// bit for which bd_bitmap is 1 and bd_sign is 0 counts as -1. +int count_backdrop(uint bd_bitmap, uint bd_sign) { + return bitCount(bd_bitmap & bd_sign) - bitCount(bd_bitmap & ~bd_sign); +} + void main() { // Could use either linear or 2d layouts for both dispatch and // invocations within the workgroup. We'll use variables to abstract. @@ -275,33 +283,31 @@ void main() { uint slice_ix = 0; uint bitmap = sh_bitmaps[0][th_ix]; uint bd_bitmap = sh_backdrop[0][th_ix]; - uint combined = bitmap | bd_bitmap; + uint bd_sign = sh_bd_sign[0]; while (true) { - if (combined == 0) { + if (bitmap == 0) { + backdrop += count_backdrop(bd_bitmap, bd_sign); slice_ix++; if (slice_ix == N_SLICE) { break; } bitmap = sh_bitmaps[slice_ix][th_ix]; bd_bitmap = sh_backdrop[slice_ix][th_ix]; - combined = bitmap | bd_bitmap; - if (combined == 0) { + bd_sign = sh_bd_sign[slice_ix]; + if (bitmap == 0) { continue; } } - uint element_ref_ix = slice_ix * 32 + findLSB(combined); + uint element_ref_ix = slice_ix * 32 + findLSB(bitmap); uint element_ix = sh_elements[(rd_ix + element_ref_ix) % N_RINGBUF]; - // TODO: use bit magic to aggregate this calculation. - if ((bd_bitmap & (1 << (element_ref_ix & 31))) != 0) { - if ((sh_bd_sign[slice_ix] & (1 << (element_ref_ix & 31))) != 0) { - backdrop += 1; - } else { - backdrop -= 1; - } - } + // Bits up to and including the lsb + uint bd_mask = (bitmap - 1) ^ bitmap; + backdrop += count_backdrop(bd_bitmap & bd_mask, bd_sign); + // Clear bits that have been consumed. + bd_bitmap &= ~bd_mask; + bitmap &= ~bd_mask; - if ((bitmap & (1 << (element_ref_ix & 31))) != 0) { // At this point, we read the element again from global memory. // If that turns out to be expensive, maybe we can pack it into // shared memory (or perhaps just the tag). @@ -378,10 +384,6 @@ void main() { } break; } - } - - // clear LSB - combined &= combined - 1; } barrier(); diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 3d3f3ff34e9f936435e516410382d85c0fb9e92a..f74d0a003e966fa7050ab07d9a61957a6364f762 100644 GIT binary patch literal 43268 zcma)_2e@5TwS_m_dqeNN6G}pt-dkuP^xh$)b0Lisnv~Fc6)93hdItpoDF%U11O-Jf zQWX_Y1VN?P-v6Jo$IZ$P?|X0Sa*Z+OTyxD;_CEWplf;ghm!GAoW~yf8KcDrgTGxEl z%qUegN7buU_upyHoz@sXVdxs`uD7NRb5|WLKYiw@W~sWUJ1L_Eb&uBY*34D)DP>;T ztIwy1v;LM2{)4%C64F`CUiIH;VE;=t|=!jGH)Q!s;{Tu=>Qc z*4l)&9o1a49Y<1KjBnmL&Yly-jX7dinQ=R3?OxMzo~4=}Zv5%mpqZyOujDOH-p+yC zbs$apb1d^#3&CfIH^XSA>y0^`Hl77(-yTm_wMZSy`FG;&Q_XAI7`m#(;h7_Cz4(us z*SHab2MruDX5^T0?Kx0)41))cIYxU|HD|RHb=uF6YTbD|L;X9dCGl_P*sEHmZrdJ_ zS+@I8_bT)34WBkQ?L5`Int7_1c{(OF=i9w~bobB+hk?7;0V_~Xi#x*zdQvOLusm%t zhCX%s34U1Yp&J3rj23FY8AMBwR{Io7&M~XqzO=Wc{PbG~{JXYJ|YOxsKUS0wY{maFrbyITKi;{1PNtXIU?c)A#l>Hmt*9?wQSF?v;- zg171(Jz(_s34=xt8P-|>_qw{*wE3UA+6rFy4(uL1bl5RjgTg?N)+$V_pA%csuDuSO zRX=d69d#G~*@n7k+PZ(#yoQY&Hfq@D2?M*iTik={?#prABMzG|aM;iht^0nisy|v0 zW4cKw^rS_v9o2TmX+68TssZixTOT%Y^bt6<_Me*9wDEUUJHmo7oc=@aS>f6NY8gdt~OVHH7i)kBuH3 zarNPAwMXZ??`{0nymwUlfX7qZ2m81C$m6z^yPDUuF?Lo5!3nNk%SY~2j!(_;4IVV) zh@s=gjMeV=)Mp&u{M8`zI_3S~l{0)iS4*O`N_Se_@IPRmBeGc2n8`$3)lj|I2qX#VP?I(GZU{C`Am zJJMy(?a*3-6N>mJ_QapJIxX?Pc7bP1zPYxi6md^2;+|c{b(a4hSx;LG+BqL*7IDw& ziQ8433+5fw=XKATsCi9Wlg{dVco%^ z`M*eY6+G=`7(jY$jG!gETj~dD+Se=J8kA$YlGqv3cfjp2&0bv(9yD^~m>~m)jOuxr z=VqweZ_@s3?yRoG50CnO?W(S;`N-~3-L8kv|68WT@*{F3+J1dj|C?-QtysOP?@38)u@9B5#Ht*?ogEp`G?Wi_`r=MNG>1U6&Ur#^#ws}uK2eo-mKZDx5r=Q_%-ZQ=< z+Pr6cN5b3vc2*aG#||1dXjDBHS2Xzb4Swr%yrX&mp1dChPunY<)sNu3^Nn|#_}M7; z8jNP`{&=j`+#jANOxqtF)wA%-&&%NS^J?3#XMUzO+Pzb>`=Ds|7w~QqhKx);a<8#y z*5>m`t%+yiMXB9qN40Q)m+8Ts)tcaP{?=;nO&ff(1|QJiJ2d#-4ZhEGyrbG5o*XCk z;LhqCuzE z)o1J3mgiSz_1tuRoz)8s{u?-ZqV*leXN>1hBSsF~cg(mW`i~nkaqNI?+H3O%^ka@) zvz6Ol!4nQ^HG$9CIf&|wS0Xs zuhZJvc)k-4;iSZLTfV2a^-*l0!G0pSe&?c%I(8tMyjOKi+o%3IJ-+9&{s#3Tpnczh z=DSN~(s&P`mGk%zeA+yAR?jr}^YJH3W4;XMu{WXKCMccNuWPM6C!N*QMvONa{O##@ zSM@HOJu+-$dt0>nc^{2Eka42*sy=RO<&gn;NA(3dCrGV!UxG^qbDp`gwdbabKMPtN zyw$65=GL$EeYUe&06cA8x~hfYti$+`-9uVm;~e+mZEe(`@kh{0XSE{SGqub^pXp+B zRx87gX{}^?ZP#w`L4GZ1wciAOY+>J~#bfWNc7_ja-S-{Up5oR$-&Gv}?jC*A_>p7A z)_r$W$D$2s#qFq01rM(A>EJ(Ca)_5RV&Vla}opJvPpFz^z5- z*(;sZ4rqB1biH?xH{K2RXlwPmVP|y+eA-w$t3#*by{hBk*&pnQdXIEfrxtoX$In5d zzn*<_om}r)tzwHq4i@!JqLG9=hIo;3vWO7k7b0N)kE-Ow{0Dp!Mm!D z;hv)TYTceUe$nVP{TSzL@VOg&-UeT~!IznicU3FETX`3Kt}>lZXSG^`uhHOZHu&ZZ zzD0v?3oq}n?WVJLR0H6q;~eceovpLly}|cv@Vy&+NP`b;@X_${{u$G-PiXL?rsG}J zNpL@#%NS=(=fnF?gJ0O-7dQB|@G{`yfK zs_j{MzuS2&->x`Q?r3RzG=RBx zsF&-pwR!J?Kf=3n887eqWjwXS^WDFUC+|%>s#bp=0m^uJUoYdSC7$o@WjuLrVrh4L zz5{!e?bXuWci*zT-1bzhe0(pR1MF{D&WFE|%9jWyS@~j=1!!fv-b6RPcp=(2o@FUs zOJkXZx~=&OY1QIt3uBv&dRfXMw40q;Zk(mz_M>L$4WE-*%^1d=mpXCh0~=FqY35;m z>awY|UdrTwB{+pC$2<1-icjk!1<`l_3Y^Py%tV=Y6SSj&QqrDiV9Z`vBu z_RF>E_SkLTr}kMETVJs4)%0DdwyDckqjny``G{?eE8H)|_8Gn**j(lIwJCLS-3&Yn zMa{l9uetW#L~&fz-=VW}?`Kza8kSo;C-A zZKKUT4xzRWV`;OGA=L373f5mu+pxkmytb(sYXr5iY@@GYey>Y4iI)Y-4Jh znz6=G8_PD@^!L0x{zrk0rKbPU)cUJC4z=S8&G}P1xzNl}?TkW8U+1Ewuk*n6rRKVy zPo4YGeRe@@S2x~;)aGJ4ZRUO{b>e*+Y&eAD}j8^M8<9Zhk+c)<4e*%?H%n=cD$qHSb;XNj3N0O}_V_`7C$d^114~`S~d~&ZE?h zQO$Xi`x&aHeG1sTeE!JauDQyqnY4o@KX!yXfXRjGP9=_5Mqjw2E9?sP-{Nxs&w3*!d>Ls{)JN7<4Y^rLD z@Hbn0Qmeglb1DC`AoXg@l=s4?aMy1#nq_^SR?ya%sap5R7bu2tPJD)Y4(oj__nGK< zYq)mLTubhmYRNrQExBi^;eM{nQE=mVrW(7SEuN>A+;h}${XIV|xo4*(_sq29o|%^1 zGt+RNg{v3bcP!6FW4FJ41>X$bzu-OtJ=ZM#J<}}txee}FV`;yo;O65QW9;VR8DqHp zKT~k?^Ng{yd&U^TUKl=!_?{Vt>+gAC$vrC! z?~C1Y!jgMd7;byd3QO)eVYtr*&k4i(;_o?OxcPWaSaQz^OYS*g$vr15x#xr>_pGqw zo)?yUY=e7tSlT^5EV*Zh;l3kyju_sT@pz6H?*8%|vE-g5mfZ8il6$6Da?cgRogdE@ z!&~dy;GQv-cF!40?pb5F@jPz~H=gH>CHKs+40k>}TMYL--Lu7T=f`u!aG!Uc zE0)}I#c=&SR}A;v-*d%q<1f?To-4*~d(RZZ?awpCl6$5YuD@rB;r8d5Vz~WnQE=}^ z&lF?ti`_HDaQ!_~3^%^#is9ztxnjvZR}9zRbH#A;@mw+7_?|0 z=ec6I-+Me)3_lotQo;Sa@=P&y^YKhET)StA;kNfoG2DDSQw;Bm{knqN-ZRD6jqjOa zxOUGJ!-vB?Qw;YzglCH3eX)C{818tVD7fSGOfh!9zj~$^ZhxL9hMSM)iQ(EkPYk!c z=ZW%uyhXgt^XeUn@7R;kHsc)vbM- z`sTd7_^zUs81I9dF+M<3Pv0MceJ4^MOMbqm{Rym|IDZB=$M6xFdgA;AY#jB(`53Ie z8~OS@@)NMJ)y>y;DYf+T8QAX^<(U5lSJ&TnEqVO^0d9`(b2Rnj^#$0uRZqJw!OecY zLQ_Axp4)$d)oh#j{ukJI+RVpyJ+;LB54br`|3y_De6YTKb+9t~N{IGaJ}(WQ?=J^;0*d@2hHwIVV^xG3NrS`8{HB8fR4Ts=9=4^}hgDfRdlfU94FW?bKs)x^Fd`@K`_ z`*E=E#_lC`-;0BNCl2;~xZH0`z};u}(y!nDmV~Rd_7HKF277(QShX!hQS*C)IAdBC z?ERQ|>J3*jPJEVw+gHZDJX}BZv|ACZ?)PZN;rqH;Vyp}{M))dleVp%AsaK<{MA6Uo za(&{z23UXBZUE!@23SpB-~Htq5zF(DwZOYjt84eWf?8s&12&he^}29<%C%k(uAcnX z2d_=Btuf{LB<6VZZciy+b zwmrB%wfgR8er5~+t9#j|A6V^6`Zh0fFqhbNY}oWkemj9}pSjx^>^X{aWP7wi+6ff-u)pl!hI+%KYihi~e8}ktA^f$1!SsQZ@^w&6#Bb00W2BPrb!{j`~{n)#;9Xm}Z847`jn7Cwri zpEhHtWz3GxysQ)RNU$-pm&bwCrqXZbOwD=DoH;)EcxvNWJBJggkD_>KKf1PCr@v#s zixvD>@ZywwE*uBeNB#c#KK&+G-S-jaSw4YcfA%j<{Nusp-aP@Xb{}osyC;FYjHB&D zikfl6i8BdooZIUhPKK*Fm&Q32>}4Enr%=?4BX;giqt;)1I(SEl^AbO6dHT10hj>$H zV>tt!e9i=y<2nnjmT{c}_A(!BXH(S7N1Qn4fsK=A!};({DeCdL0IY7_=TggKyAZ7Q z5pTslw=M!ZHs6OGt9HkfzODbaF!Ti@E5Nq7qh8-D!D>5FZmG5JfNiVIHNToV`DnX}qGmqg#J(0>&hd5dl_=`* zxgM;Z`|i77HJ>HU`!!&-_dEghuxn~tW6JeO%*Vm)nC*9`C*a1MO8heJkI}Rx?qsm* zX?x?!^-0_(!R5UD1nxX!Z$1T9E8lOPhN~Oz8ESdnZ>E6zlaqShZ=MCKdnK>u;I6Oz z8%M5RxxTKm{Ay~~+ghIIfc5|Oe0c$zd)?U2Q_C~vpMur$jCc{OmOcA3u$RvsZ7)&O z%t34p6Kk%XxUYb{ck>?j3$U6wyi6^R?=QjSyuS)Jr@UYM3apR1&!5++lasdBC~D>; zHm>iUzX98qeNLs8r_VRR_Nna+uzVw)EpS{r*L&+en$N_%EuJj8dI*1dm-y!oj(2!c0I%Y0d{UO z7oUUG^fR6|HRByc?Ydga$Jcx!b#uSl_6v0PuJ}vvSCsVoPjI=<{smv0l05zm)<->U z{sT6j?8X0r^;35*&eTa~T;3nrs9KsiixZ~@Nz$N!Szwke&_{O&wlVX7q!Hg z6|9!Eo(=3;tH)<{u)6c%Z#44Q<^ZR?>pCagbye5LwVw;Dp81rg{XAe}<~#j-U^Ra~ z^}g>z`}x7@w)Zz7x$U(r2v*bP??ZC$FW;vY0^N7fV`xu|Z-DK~KPObiSQAa#spM?mYk`fUZqEMJrDne+PS z+LH4IU~~4*pBO`XVr&Thx|}yc*LHH9^TuG~sGGCDN2(>xrr_i}nSL_Qo1trq-{!TS zIhTH0pleIcTY@vs#?YP^{lLk&jIotIl+5$iVB@HpvwKc0akd42UC!H~Yl~n1+OL`O z_UPJ@^8m0pJI}_@o)|lTzb@w;(Y0lscLEzn-JHEQ)DmYGuyLAezAKux`0ZBvHTV7Q z=-M(zdw^}LZht#dt0m4};Ph9{_1@^(;<{)C zllQd);A+P7xpNTM%g-Zi2U660W{9)z4h9?hA@;B5!H0m=eC8PEP;laC8%P;OF^)L- z3<57q$!E}D@Lt4FkIxYB;*`JgjPRK^6s(^)KSI&&v&}w@Z$D`}99+g90XM#Sd=3K} z|5?Ut{BE$?Cv|^^gKd}ow3q$auRQZ)ZET-KBf-wooJ5w70?$NE)v{&&#vo`LO>zFl z>A>YWXgiWJf#UeYuI*Ur@f7>kUzU#vWJhtP&Y8mG@!5OEv?Bf%_?suQz&S%=6h^8&~=}F+@De9-!`Az~GS6j4G!0IPc z%#30TB`O4%l|;iGMCQ z@yoHEhpsJc&j+hH-t>6^*gng47ow@B-9=#Aswc0DwNo-bmw@$a>GeE*3vRyJ;&&-n zJ@a@vSk1k#0=0W^;c z6`D5NtV}IWo2$WTGlg~;?=|S!Y_m4CJZ-K8r%gGJ*P&~(%_h|Hw7DLfHvT!_^z&VG zZMNBlS}t~;@}A|q2fGh*Z)X0i6YplQW6XNr0&ecHThY|B-nW5mr=E4Y9jxxU<=(pk z%(iX)nPBasSu@{9?*wZz@0+OQ$>(mc^Otelh1=-zkem4AHtjYJcOp6d>#hdPCfZN0#+~c`4K$%Xiq+mg0-2? z1Jv^5^ElYOl6;;3H}B6Mqp2sK$za>5C!Z(5>SaDZfoHw6C!eRl+RW!MYI*W`2D}X= z`Ah*f^LZ9cJ^4Hbww-$Nc^<4@=JNtP^P@fa{1mLse4eJ3n~!_zMX-BnPIjIAXJBKj zUfX=ezJz95{j{g;&%v&L_{-oj)+_MD(pP(8*-m@f{sQdUC68Z%(^gxVhkn}A_EoU+ zoVLFLr>(ZKt$y0m_BF6`68<{4jP+}HV(F_rW3Zie+j@`u27G$K-vIk;N$fYl#vW7q zzXevyn!XLTjrz&;Gyfg1akaSyQ>oPw^S5AQ=6mYzz-s!wOD*@a;5}+T3#|RE>JQX^ zqG1^*k^{g(alcW~C!w)*Rnas30Vk8}7D zwLE!#0WS0Y5^mmEudl%Rs3-4#g6+?7Yfs+)0&7d&{|1+N{|8>?{a<+Uwypm9ByYA% zrH^@kPAxaKYdJI6v1s$pc*OdQ{7v^#F+z+A1TGGODVKgwL6f$y?l``6|;lb`k9`QD{ZZ?O40cKyxW@hwm7<@oejj-uxH#2Md; z;PM{p3->vi=j2Lo|E@$!Cokt@Ww`CMxfUx>t0m?tV71(ntAcY+YRf&j8d#fW7k(bD zUi*0_sm;%l+;3~ZwcDTfmOS&lCOG$-e`Z?le62<8c&)wP)}daP;-!7P+HRd#>w}FU zH>VB2571xo*buIk`)?z#ZPcA>`PvlwvTt!>ZwxN)zfIufKG_tmR^ES`!ObW4-{xTb z)N}uB0UpKuXMFAHZ%c4_|Mi3GoBL0@^WdDAt99CL1upyD8m^Z6Pn%jf&yHE1eP(Su z_sllnd_K#!g}d*v|F?sy>E{}2Q!}2Qo#tnq{Q6^a?lLdi!_|_XHZ|Ml^VrYEcgV-@ zMwT;}Gy58VpU?>`xX(BDqqg|%4Ay3h9jN88?Fueq>;`v@jG--lyMwhE zV;5?9KkhT1t9ybyhp|ok_d-+Ge-G^x$GA7Ob7bva-p-xYbL6w-V6c~Qv>ilIGmbcM27(=vxgJ6-k8Kdx{IwlQE%&!U@43O? zJE?7>%{J;o!26Q7Yc3xOSJU4(+SJm=FtBTzJu)1umOY|PE&e0GY8m%oV72^Nw8Oz( zj$2zdMa^-Go#)J_dg6`*8#jCuxZE3~;qEW}w8d`>Ses*WJ>;>C1(z|8gqJbL!QF5A zX-m8DU~R^9ZRD{{02?#=Zz9K1juS^2_88m>REzk3l!P>G%P5~QF z-7y|dt(Lf_ffr{^!cT|mllEtT^-<4njAw$?{f#kmdluZ^5w#`O*+qq!J zlRvw59$3w1d3?^VeV*a|@LlZ!xPI!!Jcn8>{uhGX1K}5e^~vvb7lZXtxBVs5YVp4m z>>kkeEoyo0;ctVzhi#+HHm<{E;PM{69ImFnakQzWk1N3Dlym1R!D_L82kaP<^HpFq z{fwtgE&f-7%Xrto)ndOEyaOfit^=#-XFP3c@xLDIT4gVO7pyifdojPy-T+s({oLqs z+xKBUZUn1o`yN=H-)CbsGLe-Gq`VB@Hp$Gy~QIh%YK+{z8#+#9}cJc6z*em|=H{46N_ z9!1yYeL9H=d<<+KKEur0SdYWi6YB|Z`Yio^jIJ%;vnPXXtDd$`f^BOaW!s;iX^Y=e zwV&?-rQg%&+S11}VB4zaH;gG@`_|_7a>wv2*!|&}Iya76Kj-uzYVGO!Iq=tw?|F1> z@q3~6YmVio=-Tod<%?kZUXfx9?V0bFz|Hyo8Jc>22l_eK80x-{yh82e=d!k!DQfO- zan|h@V8@oeehId(a{XV0t3S^A`~B)yVB4wtd6c-;`409P*nYj2^tVs*`Zaa((&u%G znt6$n*Hmzs*Kgp>yxu@lKbgE-zqi0@Z&ETZZ-b4c&0N!$b#i?NY%b=nzj>JJZ>f{3 zKJQZ0%vGE<{vG)1_QHGU+T!>7+ON46{(!FSk$Qgr2)3=dd3->fJhZ(}`HEs5;;h|= zVCSg37yblS&%FK_?7ZgL@ex=bb>sMVPX7XSJm%@%m+Ke%CxzX(K7;;>rXHV9!5>q+ zH;p0JC%JwGZsz(oH1+uWz4j^h;y=*TPbOE_{By9HYo0NE0XCMl_wOgmwfXOx%mrSsw)uCJ<+05JUbwdT_m<^}IUjhD+UDP3mT$y!+|Tv-!M9M` zmoaUtPuea3)@DBDB~PCVf^DPCyyUSh1U8m7^O7g#!eIN*W?pjV%Reu<2-sNVch*JG z)bozK7+B5kRf)N{8twA_ums%q0QIz65^P&-zFVD3e@lVY&BedZEjOnB*3+_J*G}6q zV7c$7&RcKrCDgXjmOPdNn@9Rw9GMpXZ}>_REUcntQ4bntFWt);`9xU!N%} zp{aXcoBPUO+o_xX3e;-Jb5*dpXj=s=*XBN39h`l(8dx6NH^A9vYk=j6xfVG4%)h%X z&pull>^`$EW7<}qv|R_R&3w#Do<7$F+eVvt$zxj&Y%Fc&B~Q%t!S}3KH%)py}|PA(S5=0QTsBcZS_gp{lMDH)x6~CbAPaHw3(MYwgbS% z(q>-r#5@peAKJ`Io;`XHxVc9UMpMta9|Be@_vk=)xknF$yGPa2ZV=eE+OkIngVoJt z2({ci-J`?6u8+2%)bi}n;b8ZuZM0=S$DJFrK< z)gHm-yWS|BxO{KdHj;8B#l0>zk3QJPg0t7hfaUpfG)ICr#z)<;jiy%17{-Ck!99B! ze&gY43!&-bUYrQeUYr1y8|x@){WDKTgRjD0A8qO57;w2>$HHAN^{m%%VAoh%_QyBD z&HZsantIxu09Lbo+MNhaJM)z57yBfz`!x4Av^tspQIF3l;FBnMXO-*Ym^`OB6}&Go z^!MM+ISsCV)?Thp;++n5?#n*UfUC#nOt3NTC%$>h^|4R??*G}~Ip|Z{SzvkQ_+0Qj zwe1|RJnM2E_Y4^}gtapj430a#yc#+9etMd0LdAy}^MAo{oj>=Uk+Bgl#+H=fYZ+YH2*K z?E2;J99{)iGY9XzYrtOKd)lt1s2N9WoIcpE2j||q4lK{T_g%2}p1L_*ORbi9{2n;- zcmr6jjjFnd|H*pZ2$p9aZw6nFk8QLi-YsA?`!cRP@ooj{tIfFb%;Rlfb1UcncDTCF z&SCU*2UsnA-33nWcY@`{zMER#&Qq^Z54SdHeu=<@5MKxSIROJ@F9O%RQm(hZHsUgxGQP!Tuv~ z_QWG#xqG5FwnxG1Q>&ZP!_;b-gU7(-^Z0SNTKPQwF+9)XC%|%JO{UgAbN?jR=dnK8 z(#KE0<@5L{xX)wt%>C0~pU2v=X3v20TurPgXzFSAELhF}R8UIrU?Y8_XuU;2Fo zY~1qR_yt@&KEDJTBhPKQKIY+b`&Z!HE3bm(nZMV;xzAq%%d>vJ247Em+h|L?sbDqd z!MO6o`wduMZN`*5y6x`@VcXYVSR3`QA0(m%8~ocJlipvHX21`MnQU z^WQVDe{E{<|Dg5{{}Arq#k-q*=lSQK;QFY?=g(mOeVY8v_YqueN7~(7xBCm+w%UBQ zd_wKzvqjs-6g9^uc6| z7sYtR<2@2C6V>Q9m@L#w_|QOo^g zPHLIohrw!D!ykdwd`^45`Y82dl!qwxqdjdO2WxY!9h*G1AA`%dPr}tEQxf+l;KbFQ zwoiez8P_?I$My`kjQcEHZ3-oEp93eZ_OyK-tj)O2wLG?;g3Gus!PQ=*B<|0^iK{(r ze-74WT-Qt<+b_V*jlTi=9Q`FlE%sNzjxqLMfz@*6`Wo0a>aP3i)W4><7hDhflt{^wiFYa5|HC~X&iyh!cp-|{ z0u=9;`KTA9c)u)6o%`iIaCyJH-{2oL_@@p2d4vC}!Dr^PE%E&~5dHrOl;?i>J=naQ z*UZ%)!0Nf5{s>mPpW@t`vs(N=0ITJG`Vg#E-cNsmXCG-#+dqS~8P~DPWBUuZjQcTM zZ89bM^Am95YERq0g0&gfIh4ot8Muu5H@MmqO5*+^v3&t9<9-QO zEAOYT;EAg}ZT|_@W?a`)9^1dcW!(S5)&4_CzC5aX;%ZOZnb5Tv*S#T+tpi-f?SiXy zQWCcpIQeQ%+gZTcj5{;6Jhs`vu4V4EIpAus&k1%-VxJ4HmV0q-ux-?HFU|vY@8zA1Gf?bcqoDZ%R`}|<%HTDJIYUy)9ux-@S=R#on%>6IdFEJMeJEw`c2wW}pMZwNZ z?2Ccb(&yq}+o-3{CBXKXdrhvNG3TeRC2PCS9C4mGi(^}g;xy(J&53CmZ zR$%8O_N~Ecv2O!*Y_V?(R*QW*usO!wAFQ?;J9shHW_z%G8rQbk&3yp%4it0G^FXe@ zvAzFxtnJ>L;@q3Pv8_PyT8`qqxh(ba6z|OysdF#xLc82co1^d1;QKcCK@C2r!G|~a z5d|L$KCamnLRch?7qu0K(0^xCxBg}+@ll0YOx;$ zcCKST8mt!kF<|E`_G7_nu^$I^?6H3ntd?iM@nHKju5GpF8E^vF-17{O>z~*sf*pTi zp9EI3{Uqv>DYnnOBiG0Fz1hd7fVKM!5$74w3)?Cbuazi1L;6y$Oz|1ADs|@fblRzx z_wX5L>bZx{1gn`x*7huT)>eDQbT(L=^NBO*Jh=@h;}~L zlH+-B{mLBAM^n#p;{vdn``UA4+g}J*cb^$k?%AlhTnwI@THRdb$#s78wJBa}Qj+Uh zU~^rE+Fbpfb_MOqTrY*|SLXU{H1*_q8CWg3&Wr!$aCLJvrrcc3my%r91Dopx)aJS@_4TwXbG;g_UzzJQXzI!JTCiGjT?YT_;OgdTOnJ_nzYAWW z?#o=|$<@!jjVWFmQj+UNU~}Ds+FTc4s3qgQ#-Hb`~dBo z*YJlM{KJ%eYU$)g~8lpN1!{_OyKltj)O2fjqY7!1k3ncpmJ$n4A7` zed7ND*cf@P{}ild`$^OS+&AEAlgT&x=S_IxYERp@z}k%K9LQsP7i?ddgWrOkm#ni~ zpZNa{Yz*(u0rdSISk3mX%kROq&pONXvAt{ghuZEsi?hx%W80VFwHL*8-ko~y8t+NH z55+a#k2-7q0Wr#F=7(_Glxz4WH1(|EpTTNbLu06AjDH2IWeqW#9jXt4$$Z_QQYR_U&Ay-G9;4(-%w9)0Z*qOHIG>cM{il5XI{d zifeoT^}re*OnoTDH6BczHJ*uvcnw@o?s9cb!V<4&+z*4P+o8ABIXEo6gCe1DAcz4_7PKcmcS5mutKrntJ+L2%Nr*VP9(cHP`rXVtI|AxW+@N z53BKT>TZf_d<1pYcwyp{YrF{DHs#zeil&}5UJR_3H8zG?#=baMEo;04Sgl;+CE?~% z_Ole4dd9vqIAb@4V^`C!Irj0y@)}EV?4ziUtnnD?aTLcsfjVPfhB)QemxbG=%&9k; zdd9vSSS@2WhFZqHJXkGbUjeLEj(tVA`IPos-{hDJxj#yqtQylwI z)W_7=d;3_5WB(?#V?Tg;P2xCqxjt*vJkOt%;KnF(Tp3M0bFm6o&ACY4tHP7FcJo$y zvE|c#hOY*1#$FvwJ@d8(SS|0@`_uj#aCKvvzub902;16V$EnS+$n!h@I$)oFw$av{ zzmu?e9Z$*pols*x|4yVhf0L-4FFzkQB~Io~pUrBX`CAumjB@_gLsQTEtq)c!=Whde z=1;rhQF9&=dqa3L_C{#xnZJ#}YMH;?XukkflKDHO#y)pWr8s}5Q#*e{sRs}z^QX@aHP0Bggd3xrzkX=ynZK>TYUTWG z1JC?vcRXraQxbby@F|Vh+o7pv{`!N}GJiwx-yW`RO!JpJf5Wit2zH#>9E&{jw-eZB zvu(6B=kIK6UT07;e`nTs4E0$Q=kFY9=g()`-o(lL>9bGGGsd0a#wh1+7c}+E->zV_ za{hLMXa2N19yPx&Cid>|X6!xC)H8p3g4HsABgthixVkaTU+(;k#tbB{ zSJN;34*{3`4~46>-*?*m4}+(F_4Gd+U0eDe0ai=@hk?_-aqVACzx3Y?F8e`~)K}K{a_a9;+>cjNXFpCPPPreCg4?Ft zk4K}aXFnbTR?B`ghFa$1Sg>05<8fd$=RN!Wn{e|f`#By>J!3xsoUt3jv8(BqzD@*} zeVqhX%ii;zn*_J7sg3?lM%R}9P64Ms*SjQ1a}&w#N2(9mTo+E_LSm z9O5|F@-fsG7uqTm)BlZe7a@!OoH6(v}=90jqgt;4}7HU^RUmvs~Ya z*uD*ROxhg3T$}AK2kWoRxsd1Cdd&HZr;eqJ|F+#l|V@737*^2P$+RAYT^rnnZjQfJ>h zLHz6++dfxt@9P(8o^f3Vx3Bzp$?M^2u9OW#n>u^&c5rhK-ifB3J$Og$@7&!5 zPQI>{T>p&c?!um2??F?~c_2ez5v|6yrKJHTOXBwl?Oa*uD=o4}D!*xxUW3 zV|1>Q(*w0{ImZv8sVAo&g4KK%O5P8_UE`duKMXfN^|X5gY+G$<_akt*Hjl#fQ+I71 zr}lDfv^_>qGjDO$=EvaX+Dt}MFW1I7aQ|vc4o`yBlIKsrYUP|i1y?WUTrDx420Q-n zXW+*4nd2Hv0jv3Ei!Osd3$~5AZS;8_oOOB*EH_{8C;juR`6<}XR(-Uk&lkb=nYDZg zY&_S}IC6c&=IZ_DKFEApm;1u~Q9egJ6S|Y)bsHtmk=qM=2iUc_i#mDzj5zv){~WGg z{*9TJ;rgh*$XwXZD`54s`31O)@k_Wd^6%oj3Rg?aUx96-o|vzJ)xD4G<8`q8sCynP I_dNK20E7kjt^fc4 literal 43040 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 D@a*Ai

3dIb`ZoUe;A+OOA9;NDs(rIh_lB!E zuA`U-$Gk6CeIJT3oLe>jhA8u9-MT+6!q4kmiu=PoabAs2qCUUC7t~mv3n{L}PpGqR z4kv#0jcrdTxcBu*HP5*AgWFgBrm7RJb`6?)U?|wjJ)muW%4CZDinHH_fz7krZ^O~l zGiM{fYR*sk?*coH?7@+6{nYJ$G_{xgYa2yTvwv~+U^lpR4~{`o&mKIW_IK{af|IXn zCD%XW8CTeo>v%NvjAsH^&A8bE2ZGfnQjF`^)Z7Ef+uE2XVw(gu4}D!*xxUW3V|1>Q zQ%~(%&hbHL>dEO~u$u2e$@>tvYn<=vQ{d*Oo_15gw$+w)-v^g#^8>hk>aNXU)LyQQ zwnHgu<}J?J{1Du_Hb7TRaWU$XxeYB;|Q^59_wLBGE?mxLc V#%$h?&3%yhv@Z9B`y=Pb{{z)BoU8x< literal 33272 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 diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 70b02f5..65bbe5c 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -46,8 +46,8 @@ pub fn render_scene(rc: &mut impl RenderContext) { let circle = Circle::new(center, radius); rc.fill(circle, &color); } - let mut path = BezPath::new(); /* + let mut path = BezPath::new(); path.move_to((100.0, 1150.0)); path.line_to((200.0, 1200.0)); path.line_to((150.0, 1250.0)); From a616b4d010a346d7cbfc026a0bb255d0f0626292 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Wed, 20 May 2020 16:36:09 -0700 Subject: [PATCH 4/5] Rework right_edge computation in elements Trying to fit it into the fancy monad doesn't really work, so use a more straightforward approach to compute it from the aggregate. Also add yEdge logic (basically copying piet-metal). With a fix to ELEMENT_BINNING_RATIO (which I had simply gotten wrong), the example renders almost correctly, with small bounding box artifacts. --- piet-gpu-types/src/state.rs | 1 - piet-gpu/shader/binning.comp | 9 ++++---- piet-gpu/shader/binning.spv | Bin 22592 -> 19600 bytes piet-gpu/shader/build.ninja | 2 +- piet-gpu/shader/coarse.comp | 24 +++++++++++++++++++++ piet-gpu/shader/coarse.spv | Bin 38016 -> 43040 bytes piet-gpu/shader/elements.comp | 38 +++++++++++++++++++++++----------- piet-gpu/shader/elements.spv | Bin 45312 -> 45536 bytes piet-gpu/shader/setup.h | 2 +- piet-gpu/shader/state.h | 10 +++------ piet-gpu/src/lib.rs | 2 +- piet-gpu/src/render_ctx.rs | 26 ++++++++++++++--------- 12 files changed, 76 insertions(+), 38 deletions(-) diff --git a/piet-gpu-types/src/state.rs b/piet-gpu-types/src/state.rs index b93e9f3..35076f0 100644 --- a/piet-gpu-types/src/state.rs +++ b/piet-gpu-types/src/state.rs @@ -8,7 +8,6 @@ piet_gpu! { translate: [f32; 2], bbox: [f32; 4], linewidth: f32, - right_edge: f32, flags: u32, } } diff --git a/piet-gpu/shader/binning.comp b/piet-gpu/shader/binning.comp index 138621e..713a654 100644 --- a/piet-gpu/shader/binning.comp +++ b/piet-gpu/shader/binning.comp @@ -50,10 +50,10 @@ shared uint sh_chunk_jump[N_TILE]; shared float sh_right_edge[N_TILE]; -#define StateBuf_stride (4 + 2 * State_size) +#define StateBuf_stride (8 + 2 * State_size) -StateRef state_aggregate_ref(uint partition_ix) { - return StateRef(8 + partition_ix * StateBuf_stride); +uint state_right_edge_index(uint partition_ix) { + return 2 + partition_ix * (StateBuf_stride / 4); } void main() { @@ -120,8 +120,7 @@ void main() { // look-forward is small (performance may degrade in the case // of massively complex paths). do { - StateRef agg_ref = state_aggregate_ref(aggregate_ix); - my_right_edge = State_read(agg_ref).right_edge; + my_right_edge = uintBitsToFloat(state[state_right_edge_index(aggregate_ix)]); aggregate_ix++; } while (isinf(my_right_edge)); } diff --git a/piet-gpu/shader/binning.spv b/piet-gpu/shader/binning.spv index dc1713b5505929835d055744fc3124cd12d0d6e1..e932e4d3b944d2352e9ea514e2b4b4250c3e9a46 100644 GIT binary patch literal 19600 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 WpK!IODe3bw;29KczE5)Br~d_$M=(MF literal 22592 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 diff --git a/piet-gpu/shader/build.ninja b/piet-gpu/shader/build.ninja index 3b6b963..14c72aa 100644 --- a/piet-gpu/shader/build.ninja +++ b/piet-gpu/shader/build.ninja @@ -12,7 +12,7 @@ build image.spv: glsl image.comp | scene.h build elements.spv: glsl elements.comp | scene.h state.h annotated.h -build binning.spv: glsl binning.comp | annotated.h bins.h setup.h +build binning.spv: glsl binning.comp | annotated.h state.h bins.h setup.h build coarse.spv: glsl coarse.comp | annotated.h bins.h ptcl.h setup.h diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 2389e27..03c4535 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -310,6 +310,30 @@ void main() { switch (tag) { case Annotated_FillLine: + AnnoFillLineSeg fill_line = Annotated_FillLine_read(ref); + // This is basically the same logic as piet-metal, but should be made numerically robust. + vec2 tile_xy = vec2(tile_x * TILE_WIDTH_PX, tile_y * TILE_HEIGHT_PX); + float yEdge = mix(fill_line.p0.y, fill_line.p1.y, (tile_xy.x - fill_line.p0.x) / (fill_line.p1.x - fill_line.p0.x)); + if (min(fill_line.p0.x, fill_line.p1.x) < tile_xy.x && yEdge >= tile_xy.y && yEdge < tile_xy.y + TILE_HEIGHT_PX) { + Segment edge_seg; + if (fill_line.p0.x > fill_line.p1.x) { + fill_line.p1 = vec2(tile_xy.x, yEdge); + edge_seg.start = fill_line.p1; + edge_seg.end = vec2(tile_xy.x, tile_xy.y + TILE_HEIGHT_PX); + } else { + fill_line.p0 = vec2(tile_xy.x, yEdge); + edge_seg.start = vec2(tile_xy.x, tile_xy.y + TILE_HEIGHT_PX); + edge_seg.end = fill_line.p0; + } + alloc_chunk(chunk_n_segs, seg_chunk_ref, first_seg_chunk, seg_limit); + Segment_write(SegmentRef(seg_chunk_ref.offset + SegChunk_size + Segment_size * chunk_n_segs), edge_seg); + chunk_n_segs++; + } + Segment fill_seg = Segment(fill_line.p0, fill_line.p1); + alloc_chunk(chunk_n_segs, seg_chunk_ref, first_seg_chunk, seg_limit); + Segment_write(SegmentRef(seg_chunk_ref.offset + SegChunk_size + Segment_size * chunk_n_segs), fill_seg); + chunk_n_segs++; + break; case Annotated_StrokeLine: AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); Segment seg = Segment(line.p0, line.p1); diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index bc097e44388cf90bb53859a8801d1fe1b4f343e3..3d3f3ff34e9f936435e516410382d85c0fb9e92a 100644 GIT binary patch literal 43040 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 D@a*Ai literal 38016 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