From 24b3def0a1d7fb99d0ad9b34ea7acc75e2206def Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 22 May 2020 14:18:39 -0700 Subject: [PATCH 1/5] Start work on parallel segment output Output of segments is in parallel. Getting closer, some problems with chaining but mostly correct. --- piet-gpu/bin/cli.rs | 4 +- piet-gpu/shader/coarse.comp | 196 +++++++++++++++++++++++++----------- piet-gpu/shader/coarse.spv | Bin 43620 -> 44012 bytes piet-gpu/src/lib.rs | 4 +- piet-gpu/src/pico_svg.rs | 6 +- 5 files changed, 142 insertions(+), 68 deletions(-) diff --git a/piet-gpu/bin/cli.rs b/piet-gpu/bin/cli.rs index c5c0b6b..3fdc5f8 100644 --- a/piet-gpu/bin/cli.rs +++ b/piet-gpu/bin/cli.rs @@ -107,8 +107,8 @@ fn main() -> Result<(), Error> { /* let mut data: Vec = Default::default(); - device.read_buffer(&renderer.bin_buf, &mut data).unwrap(); - //piet_gpu::dump_k1_data(&data); + device.read_buffer(&renderer.ptcl_buf, &mut data).unwrap(); + piet_gpu::dump_k1_data(&data); //trace_merge(&data); */ diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 0519b2e..8130e39 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -44,6 +44,14 @@ 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]; +shared uint sh_is_segment[N_SLICE]; + +// Shared state for parallel segment output stage + +// Count of total number of segments in each tile, then +// inclusive prefix sum of same. +shared uint sh_seg_count[N_TILE]; +shared uint sh_seg_alloc; // scale factors useful for converting coordinates to tiles #define SX (1.0 / float(TILE_WIDTH_PX)) @@ -60,26 +68,6 @@ void alloc_cmd(inout CmdRef cmd_ref, inout uint cmd_limit) { } } -// Ensure that there is space to encode a segment. -void alloc_chunk(inout uint chunk_n_segs, inout SegChunkRef seg_chunk_ref, - inout SegChunkRef first_seg_chunk, inout uint seg_limit) -{ - // TODO: Reduce divergence of atomic alloc? - if (chunk_n_segs == 0) { - if (seg_chunk_ref.offset + 40 > seg_limit) { - seg_chunk_ref.offset = atomicAdd(alloc, SEG_CHUNK_ALLOC); - seg_limit = seg_chunk_ref.offset + SEG_CHUNK_ALLOC - Segment_size; - } - first_seg_chunk = seg_chunk_ref; - } else if (seg_chunk_ref.offset + SegChunk_size + Segment_size * chunk_n_segs > seg_limit) { - uint new_chunk_ref = atomicAdd(alloc, SEG_CHUNK_ALLOC); - seg_limit = new_chunk_ref + SEG_CHUNK_ALLOC - Segment_size; - SegChunk_write(seg_chunk_ref, SegChunk(chunk_n_segs, SegChunkRef(new_chunk_ref))); - seg_chunk_ref.offset = new_chunk_ref; - chunk_n_segs = 0; - } -} - // Accumulate delta to backdrop. // // Each bit for which bd_bitmap is 1 and bd_sign is 1 counts as +1, and each @@ -128,6 +116,7 @@ void main() { for (uint i = 0; i < N_SLICE; i++) { sh_bitmaps[i][th_ix] = 0; sh_backdrop[i][th_ix] = 0; + sh_is_segment[th_ix] = 0; } while (wr_ix - rd_ix <= N_TILE) { @@ -219,6 +208,7 @@ void main() { atomicAnd(sh_bd_sign[my_slice], ~my_mask); } } + atomicOr(sh_is_segment[my_slice], my_mask); // Set up for per-scanline coverage formula, below. float invslope = abs(dy) < 1e-9 ? 1e9 : dx / dy; c = (line.stroke.x + abs(invslope) * (0.5 * float(TILE_HEIGHT_PX) + line.stroke.y)) * SX; @@ -279,14 +269,102 @@ void main() { } barrier(); - // Output elements for this tile, based on bitmaps. + // We've computed coverage and other info for each element in the input, now for + // the output stage. We'll do segments first using a more parallel algorithm. + + uint seg_count = 0; + for (uint i = 0; i < N_SLICE; i++) { + // Count each segment as 1 and each non-segment element as 1. A finer + // approach would be to count bytes accurately (non-segment elements that + // are not strokes and fills wouldn't count). + seg_count += bitCount(sh_bitmaps[i][th_ix]); + } + sh_seg_count[th_ix] = seg_count; + // Prefix sum of sh_seg_count + for (uint i = 0; i < LG_N_TILE; i++) { + barrier(); + if (th_ix >= (1 << i)) { + seg_count += sh_seg_count[th_ix - (1 << i)]; + } + barrier(); + sh_seg_count[th_ix] = seg_count; + } + if (th_ix == N_TILE - 1) { + sh_seg_alloc = atomicAdd(alloc, seg_count * Segment_size + SegChunk_size); + } + barrier(); + uint total_seg_count = sh_seg_count[N_TILE - 1]; + uint seg_alloc = sh_seg_alloc; + + // Output buffer is allocated as segments for each tile laid end-to-end, + // but with gaps for non-segment elements (to fit the linked list headers). + + for (uint ix = th_ix; ix < total_seg_count; ix += N_TILE) { + // Find the work item; this thread is now not bound to an element or tile. + // First find the tile (by binary search) + uint tile_ix = 0; + for (uint i = 0; i < LG_N_TILE; i++) { + uint probe = tile_ix + ((N_TILE / 2) >> i); + if (ix >= sh_seg_count[probe - 1]) { + tile_ix = probe; + } + } + // Now, sh_seg_count[tile_ix - 1] <= ix < sh_seg_count[tile_ix]. + // (considering sh_seg_count[-1] == 0) + + // Index of segment within tile's segments + uint seq_ix = ix; + // Maybe consider a sentinel value to avoid the conditional? + if (tile_ix > 0) { + seq_ix -= sh_seg_count[tile_ix - 1]; + } + // Find the segment. This is done by linear scan through the bitmaps of the + // tile, accelerated by bit counting. Binary search might help, maybe not. + uint slice_ix = 0; + uint seq_bits; + while (true) { + seq_bits = sh_bitmaps[slice_ix][tile_ix]; + uint this_count = bitCount(seq_bits); + if (this_count > seq_ix) { + break; + } + seq_ix -= this_count; + slice_ix++; + } + // Now find position of nth bit set (n = seq_ix) in seq_bits; binary search + uint bit_ix = 0; + for (int i = 0; i < 5; i++) { + uint probe = bit_ix + (16 >> i); + if (seq_ix >= bitCount(seq_bits & ((1 << probe) - 1))) { + bit_ix = probe; + } + } + if ((sh_is_segment[slice_ix] & (1 << bit_ix)) != 0) { + uint out_offset = seg_alloc + Segment_size * ix + SegChunk_size; + uint rd_el_ix = (rd_ix + slice_ix * 32 + bit_ix) % N_RINGBUF; + uint element_ix = sh_elements[rd_el_ix]; + ref = AnnotatedRef(element_ix * Annotated_size); + AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); + Segment seg = Segment(line.p0, line.p1); + Segment_write(SegmentRef(seg_alloc + Segment_size * ix + SegChunk_size), seg); + } + } + + // Output non-segment elements for this tile. The thread does a sequential walk + // through the non-segment elements, and for segments, count and backdrop are + // aggregated using bit counting. uint slice_ix = 0; uint bitmap = sh_bitmaps[0][th_ix]; uint bd_bitmap = sh_backdrop[0][th_ix]; uint bd_sign = sh_bd_sign[0]; + uint is_segment = sh_is_segment[0]; + uint seg_start = th_ix == 0 ? 0 : sh_seg_count[th_ix - 1]; + seg_count = 0; while (true) { - if (bitmap == 0) { + uint nonseg_bitmap = bitmap & ~is_segment; + if (nonseg_bitmap == 0) { backdrop += count_backdrop(bd_bitmap, bd_sign); + seg_count += bitCount(bitmap & is_segment); slice_ix++; if (slice_ix == N_SLICE) { break; @@ -294,16 +372,19 @@ void main() { bitmap = sh_bitmaps[slice_ix][th_ix]; bd_bitmap = sh_backdrop[slice_ix][th_ix]; bd_sign = sh_bd_sign[slice_ix]; - if (bitmap == 0) { + is_segment = sh_is_segment[slice_ix]; + nonseg_bitmap = bitmap & ~is_segment; + if (nonseg_bitmap == 0) { continue; } } - uint element_ref_ix = slice_ix * 32 + findLSB(bitmap); + uint element_ref_ix = slice_ix * 32 + findLSB(nonseg_bitmap); uint element_ix = sh_elements[(rd_ix + element_ref_ix) % N_RINGBUF]; // Bits up to and including the lsb - uint bd_mask = (bitmap - 1) ^ bitmap; + uint bd_mask = (nonseg_bitmap - 1) ^ nonseg_bitmap; backdrop += count_backdrop(bd_bitmap & bd_mask, bd_sign); + seg_count += bitCount(bitmap & bd_mask & is_segment); // Clear bits that have been consumed. bd_bitmap &= ~bd_mask; bitmap &= ~bd_mask; @@ -315,40 +396,8 @@ void main() { tag = Annotated_tag(ref); 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); - 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: - if (chunk_n_segs > 0) { + if (seg_count > 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; @@ -367,12 +416,21 @@ void main() { cmd_ref.offset += Cmd_size; } backdrop = 0; + seg_count = 0; break; case Annotated_Stroke: - if (chunk_n_segs > 0) { + if (chunk_n_segs > 0 || seg_count > 0) { + uint chunk_offset = seg_count > 0 ? seg_alloc + seg_start * Segment_size : 0; + SegChunkRef chunk_start = SegChunkRef(chunk_offset); + if (chunk_n_segs > 0) { + SegChunk_write(seg_chunk_ref, SegChunk(chunk_n_segs, chunk_start)); + } else { + first_seg_chunk = chunk_start; + } + if (seg_count > 0) { + SegChunk_write(chunk_start, SegChunk(seg_count, SegChunkRef(0))); + } AnnoStroke stroke = Annotated_Stroke_read(ref); - SegChunk_write(seg_chunk_ref, SegChunk(chunk_n_segs, SegChunkRef(0))); - seg_chunk_ref.offset += SegChunk_size + Segment_size * chunk_n_segs; CmdStroke cmd_stroke; cmd_stroke.seg_ref = first_seg_chunk.offset; cmd_stroke.half_width = 0.5 * stroke.linewidth; @@ -382,9 +440,25 @@ void main() { cmd_ref.offset += Cmd_size; chunk_n_segs = 0; } + seg_start += seg_count + 1; + seg_count = 0; + break; + default: + // This shouldn't happen, but just in case. + seg_start++; break; } } + if (seg_count > 0) { + SegChunkRef chunk_start = SegChunkRef(seg_alloc + seg_start * Segment_size); + if (chunk_n_segs > 0) { + SegChunk_write(seg_chunk_ref, SegChunk(chunk_n_segs, chunk_start)); + } else { + first_seg_chunk = chunk_start; + } + seg_chunk_ref = chunk_start; + chunk_n_segs = seg_count; + } barrier(); rd_ix += N_TILE; diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 1329bb6f475f7cc836cc7715a5792d8410f48850..bd07113e408eafba66282984f99011952cd47a95 100644 GIT binary patch literal 44012 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

c+g4TArA9g3Z%?aSyfE*Zd}q`rQ<6 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 literal 43620 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 { - 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); From 8eaf49a04d8ccdd5e817b6d5de65ed140d505950 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Mon, 25 May 2020 09:08:21 -0700 Subject: [PATCH 2/5] Checkpoint parallel output Parallel segment output seems to be working for strokes. --- piet-gpu-types/src/ptcl.rs | 7 +-- piet-gpu/bin/cli.rs | 54 +++++++++++++++++++- piet-gpu/shader/coarse.comp | 96 +++++++++++++++++++++-------------- piet-gpu/shader/coarse.spv | Bin 44012 -> 40472 bytes piet-gpu/shader/kernel4.comp | 5 +- piet-gpu/shader/kernel4.spv | Bin 17856 -> 18428 bytes piet-gpu/shader/ptcl.h | 12 +++-- piet-gpu/src/lib.rs | 6 +-- piet-gpu/src/pico_svg.rs | 2 +- 9 files changed, 130 insertions(+), 52 deletions(-) diff --git a/piet-gpu-types/src/ptcl.rs b/piet-gpu-types/src/ptcl.rs index 534cf85..2aa869e 100644 --- a/piet-gpu-types/src/ptcl.rs +++ b/piet-gpu-types/src/ptcl.rs @@ -13,8 +13,8 @@ piet_gpu! { end: [f32; 2], } struct CmdStroke { - // Should be Ref - seg_ref: u32, + // Consider a specialization to one segment. + seg_ref: Ref, half_width: f32, rgba_color: u32, } @@ -63,7 +63,8 @@ piet_gpu! { struct SegChunk { n: u32, next: Ref, - // Segments follow (could represent this as a variable sized array). + // Actually a reference to a variable-sized slice. + segs: Ref, } } } diff --git a/piet-gpu/bin/cli.rs b/piet-gpu/bin/cli.rs index 3fdc5f8..347cf01 100644 --- a/piet-gpu/bin/cli.rs +++ b/piet-gpu/bin/cli.rs @@ -75,6 +75,58 @@ fn trace_merge(buf: &[u32]) { } } +/// Interpret the output of the coarse raster stage, for diagnostic purposes. +#[allow(unused)] +fn trace_ptcl(buf: &[u32]) { + for y in 0..96 { + for x in 0..128 { + let tile_ix = y * 128 + x; + println!("tile {} @({}, {})", tile_ix, x, y); + let mut tile_offset = tile_ix * 1024; + loop { + let tag = buf[tile_offset / 4]; + match tag { + 0 => break, + 4 => { + let line_width = f32::from_bits(buf[tile_offset / 4 + 2]); + let rgba_color = buf[tile_offset / 4 + 3]; + println!(" {:x}: stroke {:x} {}", tile_offset, rgba_color, line_width); + let mut seg_chunk = buf[tile_offset / 4 + 1] as usize; + let n = buf[seg_chunk / 4] as usize; + let segs = buf[seg_chunk / 4 + 2] as usize; + println!(" chunk @{:x}: n={}, segs @{:x}", seg_chunk, n, segs); + for i in 0..n { + let x0 = f32::from_bits(buf[segs / 4 + i * 4]); + let y0 = f32::from_bits(buf[segs / 4 + i * 4 + 1]); + let x1 = f32::from_bits(buf[segs / 4 + i * 4 + 2]); + let y1 = f32::from_bits(buf[segs / 4 + i * 4 + 3]); + println!(" ({:.3}, {:.3}) - ({:.3}, {:.3})", x0, y0, x1, y1); + } + loop { + seg_chunk = buf[seg_chunk / 4 + 1] as usize; + if seg_chunk == 0 { + break; + } + } + } + _ => { + println!("{:x}: {}", tile_offset, tag); + } + } + if tag == 0 { + break; + } + if tag == 8 { + tile_offset = buf[tile_offset / 4 + 1] as usize; + } else { + tile_offset += 20; + } + } + } + } +} + + fn main() -> Result<(), Error> { let (instance, _) = VkInstance::new(None)?; unsafe { @@ -109,7 +161,7 @@ fn main() -> Result<(), Error> { let mut data: Vec = Default::default(); device.read_buffer(&renderer.ptcl_buf, &mut data).unwrap(); piet_gpu::dump_k1_data(&data); - //trace_merge(&data); + //trace_ptcl(&data); */ let mut img_data: Vec = Default::default(); diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 8130e39..8d593d8 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -51,6 +51,7 @@ shared uint sh_is_segment[N_SLICE]; // Count of total number of segments in each tile, then // inclusive prefix sum of same. shared uint sh_seg_count[N_TILE]; +shared uint sh_orig_seg_count[N_TILE]; shared uint sh_seg_alloc; // scale factors useful for converting coordinates to tiles @@ -68,6 +69,11 @@ void alloc_cmd(inout CmdRef cmd_ref, inout uint cmd_limit) { } } +// TODO: aggregate rather than doing an atomic every time +SegChunkRef alloc_seg_chunk() { + return SegChunkRef(atomicAdd(alloc, SegChunk_size)); +} + // Accumulate delta to backdrop. // // Each bit for which bd_bitmap is 1 and bd_sign is 1 counts as +1, and each @@ -91,10 +97,10 @@ void main() { uint cmd_limit = cmd_ref.offset + PTCL_INITIAL_ALLOC - 2 * Cmd_size; // Allocation and management of segment output - SegChunkRef seg_chunk_ref = SegChunkRef(0); SegChunkRef first_seg_chunk = SegChunkRef(0); - uint seg_limit = 0; - uint chunk_n_segs = 0; + SegChunkRef last_chunk_ref = SegChunkRef(0); + uint last_chunk_n = 0; + SegmentRef last_chunk_segs = SegmentRef(0); uint wr_ix = 0; uint rd_ix = 0; @@ -274,12 +280,10 @@ void main() { uint seg_count = 0; for (uint i = 0; i < N_SLICE; i++) { - // Count each segment as 1 and each non-segment element as 1. A finer - // approach would be to count bytes accurately (non-segment elements that - // are not strokes and fills wouldn't count). - seg_count += bitCount(sh_bitmaps[i][th_ix]); + seg_count += bitCount(sh_bitmaps[i][th_ix] & sh_is_segment[i]); } sh_seg_count[th_ix] = seg_count; + sh_orig_seg_count[th_ix] = seg_count; // Prefix sum of sh_seg_count for (uint i = 0; i < LG_N_TILE; i++) { barrier(); @@ -290,14 +294,13 @@ void main() { sh_seg_count[th_ix] = seg_count; } if (th_ix == N_TILE - 1) { - sh_seg_alloc = atomicAdd(alloc, seg_count * Segment_size + SegChunk_size); + sh_seg_alloc = atomicAdd(alloc, seg_count * Segment_size); } barrier(); uint total_seg_count = sh_seg_count[N_TILE - 1]; uint seg_alloc = sh_seg_alloc; - // Output buffer is allocated as segments for each tile laid end-to-end, - // but with gaps for non-segment elements (to fit the linked list headers). + // Output buffer is allocated as segments for each tile laid end-to-end. for (uint ix = th_ix; ix < total_seg_count; ix += N_TILE) { // Find the work item; this thread is now not bound to an element or tile. @@ -322,8 +325,9 @@ void main() { // tile, accelerated by bit counting. Binary search might help, maybe not. uint slice_ix = 0; uint seq_bits; + while (true) { - seq_bits = sh_bitmaps[slice_ix][tile_ix]; + seq_bits = sh_bitmaps[slice_ix][tile_ix] & sh_is_segment[slice_ix]; uint this_count = bitCount(seq_bits); if (this_count > seq_ix) { break; @@ -339,15 +343,13 @@ void main() { bit_ix = probe; } } - if ((sh_is_segment[slice_ix] & (1 << bit_ix)) != 0) { - uint out_offset = seg_alloc + Segment_size * ix + SegChunk_size; - uint rd_el_ix = (rd_ix + slice_ix * 32 + bit_ix) % N_RINGBUF; - uint element_ix = sh_elements[rd_el_ix]; - ref = AnnotatedRef(element_ix * Annotated_size); - AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); - Segment seg = Segment(line.p0, line.p1); - Segment_write(SegmentRef(seg_alloc + Segment_size * ix + SegChunk_size), seg); - } + uint out_offset = seg_alloc + Segment_size * ix + SegChunk_size; + uint rd_el_ix = (rd_ix + slice_ix * 32 + bit_ix) % N_RINGBUF; + uint element_ix = sh_elements[rd_el_ix]; + ref = AnnotatedRef(element_ix * Annotated_size); + AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); + Segment seg = Segment(line.p0, line.p1); + Segment_write(SegmentRef(seg_alloc + Segment_size * ix), seg); } // Output non-segment elements for this tile. The thread does a sequential walk @@ -397,6 +399,7 @@ void main() { switch (tag) { case Annotated_Fill: + /* if (seg_count > 0) { AnnoFill fill = Annotated_Fill_read(ref); SegChunk_write(seg_chunk_ref, SegChunk(chunk_n_segs, SegChunkRef(0))); @@ -415,32 +418,45 @@ void main() { Cmd_Solid_write(cmd_ref, CmdSolid(fill.rgba_color)); cmd_ref.offset += Cmd_size; } + */ backdrop = 0; seg_count = 0; break; case Annotated_Stroke: - if (chunk_n_segs > 0 || seg_count > 0) { - uint chunk_offset = seg_count > 0 ? seg_alloc + seg_start * Segment_size : 0; - SegChunkRef chunk_start = SegChunkRef(chunk_offset); - if (chunk_n_segs > 0) { - SegChunk_write(seg_chunk_ref, SegChunk(chunk_n_segs, chunk_start)); - } else { - first_seg_chunk = chunk_start; - } + if (last_chunk_n > 0 || seg_count > 0) { + // TODO: noncontiguous case + + SegChunkRef chunk_ref = SegChunkRef(0); if (seg_count > 0) { - SegChunk_write(chunk_start, SegChunk(seg_count, SegChunkRef(0))); + chunk_ref = alloc_seg_chunk(); + SegChunk chunk; + chunk.n = seg_count; + chunk.next = SegChunkRef(0); + uint seg_offset = seg_alloc + seg_start * Segment_size; + chunk.segs = SegmentRef(seg_offset); + SegChunk_write(chunk_ref, chunk); } + if (last_chunk_n > 0) { + SegChunk chunk; + chunk.n = last_chunk_n; + chunk.next = chunk_ref; + chunk.segs = last_chunk_segs; + SegChunk_write(last_chunk_ref, chunk); + } else { + first_seg_chunk = chunk_ref; + } + AnnoStroke stroke = Annotated_Stroke_read(ref); CmdStroke cmd_stroke; - cmd_stroke.seg_ref = first_seg_chunk.offset; + cmd_stroke.seg_ref = first_seg_chunk; cmd_stroke.half_width = 0.5 * stroke.linewidth; cmd_stroke.rgba_color = stroke.rgba_color; alloc_cmd(cmd_ref, cmd_limit); Cmd_Stroke_write(cmd_ref, cmd_stroke); cmd_ref.offset += Cmd_size; - chunk_n_segs = 0; + last_chunk_n = 0; } - seg_start += seg_count + 1; + seg_start += seg_count; seg_count = 0; break; default: @@ -450,14 +466,18 @@ void main() { } } if (seg_count > 0) { - SegChunkRef chunk_start = SegChunkRef(seg_alloc + seg_start * Segment_size); - if (chunk_n_segs > 0) { - SegChunk_write(seg_chunk_ref, SegChunk(chunk_n_segs, chunk_start)); + SegChunkRef chunk_ref = alloc_seg_chunk(); + if (last_chunk_n > 0) { + SegChunk_write(last_chunk_ref, SegChunk(last_chunk_n, chunk_ref, last_chunk_segs)); } else { - first_seg_chunk = chunk_start; + first_seg_chunk = chunk_ref; } - seg_chunk_ref = chunk_start; - chunk_n_segs = seg_count; + // TODO: free two registers by writing count and segments ref now, + // as opposed to deferring SegChunk write until all fields are known. + last_chunk_ref = chunk_ref; + last_chunk_n = seg_count; + uint seg_offset = seg_alloc + seg_start * Segment_size; + last_chunk_segs = SegmentRef(seg_offset); } barrier(); diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index bd07113e408eafba66282984f99011952cd47a95..ac0895068da7b6c3cde6bbdf42f33f2d10928539 100644 GIT binary patch literal 40472 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

c+g4TArA9g3Z%?aSyfE*Zd}q`rQ<6 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 diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index bdc540c..4c4aba3 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -47,11 +47,12 @@ void main() { case Cmd_Stroke: CmdStroke stroke = Cmd_Stroke_read(cmd_ref); float df = 1e9; - SegChunkRef seg_chunk_ref = SegChunkRef(stroke.seg_ref); + SegChunkRef seg_chunk_ref = stroke.seg_ref; do { SegChunk seg_chunk = SegChunk_read(seg_chunk_ref); + SegmentRef segs = seg_chunk.segs; for (int i = 0; i < seg_chunk.n; i++) { - Segment seg = Segment_read(SegmentRef(seg_chunk_ref.offset + SegChunk_size + Segment_size * i)); + Segment seg = Segment_read(Segment_index(segs, i)); vec2 line_vec = seg.end - seg.start; vec2 dpos = xy + vec2(0.5, 0.5) - seg.start; float t = clamp(dot(line_vec, dpos) / dot(line_vec, line_vec), 0.0, 1.0); diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index 6658915fb85538479cd894533e38ac794acb58b7..02bd1378c14a8746b89c6c235c86c14f8e34f01a 100644 GIT binary patch literal 18428 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 Dn}E@X literal 17856 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 2; - ptcl[ix + 0] = s.seg_ref; + ptcl[ix + 0] = s.seg_ref.offset; ptcl[ix + 1] = floatBitsToUint(s.half_width); ptcl[ix + 2] = s.rgba_color; } @@ -416,9 +417,11 @@ SegChunk SegChunk_read(SegChunkRef ref) { uint ix = ref.offset >> 2; uint raw0 = ptcl[ix + 0]; uint raw1 = ptcl[ix + 1]; + uint raw2 = ptcl[ix + 2]; SegChunk s; s.n = raw0; s.next = SegChunkRef(raw1); + s.segs = SegmentRef(raw2); return s; } @@ -426,5 +429,6 @@ void SegChunk_write(SegChunkRef ref, SegChunk s) { uint ix = ref.offset >> 2; ptcl[ix + 0] = s.n; ptcl[ix + 1] = s.next.offset; + ptcl[ix + 2] = s.segs.offset; } diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 2bfe5b1..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)); @@ -59,8 +59,8 @@ pub fn render_scene(rc: &mut impl RenderContext) { &Color::WHITE, 5.0, ); - render_cardioid(rc); - //render_tiger(rc); + //render_cardioid(rc); + render_tiger(rc); } #[allow(unused)] diff --git a/piet-gpu/src/pico_svg.rs b/piet-gpu/src/pico_svg.rs index bc2503f..9cf5cc3 100644 --- a/piet-gpu/src/pico_svg.rs +++ b/piet-gpu/src/pico_svg.rs @@ -58,7 +58,7 @@ impl PicoSvg { } pub fn render(&self, rc: &mut impl RenderContext) { - for item in self.items.iter().take(30) { + for item in &self.items { match item { Item::Fill(fill_item) => { //rc.fill(&fill_item.path, &fill_item.color); From 3d422d924345b95fdd7711d0fdfab5bc6d4a7f48 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Mon, 25 May 2020 12:22:29 -0700 Subject: [PATCH 3/5] Allocate segment chunks in slabs Another speedup might be to special-case when the number of chunks in a stroke or fill command is 1, then the segment header doesn't need allocation and memory traffic is reduced. But right now we'll avoid the complexity. --- piet-gpu/shader/coarse.comp | 16 ++++++++++++++-- piet-gpu/shader/coarse.spv | Bin 40472 -> 40892 bytes 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 8d593d8..81ea890 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -69,9 +69,20 @@ void alloc_cmd(inout CmdRef cmd_ref, inout uint cmd_limit) { } } -// TODO: aggregate rather than doing an atomic every time +#define CHUNK_ALLOC_SLAB 16 + +uint alloc_chunk_remaining; +uint alloc_chunk_offset; + SegChunkRef alloc_seg_chunk() { - return SegChunkRef(atomicAdd(alloc, SegChunk_size)); + if (alloc_chunk_remaining == 0) { + alloc_chunk_offset = atomicAdd(alloc, CHUNK_ALLOC_SLAB * SegChunk_size); + alloc_chunk_remaining = CHUNK_ALLOC_SLAB; + } + uint offset = alloc_chunk_offset; + alloc_chunk_offset += SegChunk_size; + alloc_chunk_remaining--; + return SegChunkRef(offset); } // Accumulate delta to backdrop. @@ -101,6 +112,7 @@ void main() { SegChunkRef last_chunk_ref = SegChunkRef(0); uint last_chunk_n = 0; SegmentRef last_chunk_segs = SegmentRef(0); + alloc_chunk_remaining = 0; uint wr_ix = 0; uint rd_ix = 0; diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index ac0895068da7b6c3cde6bbdf42f33f2d10928539..069209e9fc4104d855cf5680c2673a39454a7ac8 100644 GIT binary patch literal 40892 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 m#x`(c;SeOb;l}qtp5k5-$cUz literal 40472 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 k+!* Date: Mon, 25 May 2020 15:01:52 -0700 Subject: [PATCH 4/5] Reinstate fills Add fills back in. --- piet-gpu-types/src/ptcl.rs | 7 +++-- piet-gpu/bin/cli.rs | 38 ++++++++++++++++++----- piet-gpu/shader/coarse.comp | 58 ++++++++++++++++++++++++++--------- piet-gpu/shader/coarse.spv | Bin 40892 -> 49152 bytes piet-gpu/shader/kernel4.comp | 6 ++-- piet-gpu/shader/kernel4.spv | Bin 18428 -> 19028 bytes piet-gpu/shader/ptcl.h | 12 +++++--- piet-gpu/src/pico_svg.rs | 4 +-- 8 files changed, 94 insertions(+), 31 deletions(-) diff --git a/piet-gpu-types/src/ptcl.rs b/piet-gpu-types/src/ptcl.rs index 2aa869e..bdf342b 100644 --- a/piet-gpu-types/src/ptcl.rs +++ b/piet-gpu-types/src/ptcl.rs @@ -19,8 +19,7 @@ piet_gpu! { rgba_color: u32, } struct CmdFill { - // Should be Ref - seg_ref: u32, + seg_ref: Ref, backdrop: i32, rgba_color: u32, } @@ -58,6 +57,10 @@ piet_gpu! { struct Segment { start: [f32; 2], end: [f32; 2], + + // This is used for fills only, but we're including it in + // the general structure for simplicity. + y_edge: f32, } struct SegChunk { diff --git a/piet-gpu/bin/cli.rs b/piet-gpu/bin/cli.rs index 347cf01..fe8c4ac 100644 --- a/piet-gpu/bin/cli.rs +++ b/piet-gpu/bin/cli.rs @@ -87,6 +87,29 @@ fn trace_ptcl(buf: &[u32]) { let tag = buf[tile_offset / 4]; match tag { 0 => break, + 3 => { + let backdrop = buf[tile_offset / 4 + 2]; + let rgba_color = buf[tile_offset / 4 + 3]; + println!(" {:x}: fill {:x} {}", tile_offset, rgba_color, backdrop); + let mut seg_chunk = buf[tile_offset / 4 + 1] as usize; + let n = buf[seg_chunk / 4] as usize; + let segs = buf[seg_chunk / 4 + 2] as usize; + println!(" chunk @{:x}: n={}, segs @{:x}", seg_chunk, n, segs); + for i in 0..n { + let x0 = f32::from_bits(buf[segs / 4 + i * 5]); + let y0 = f32::from_bits(buf[segs / 4 + i * 5 + 1]); + let x1 = f32::from_bits(buf[segs / 4 + i * 5 + 2]); + let y1 = f32::from_bits(buf[segs / 4 + i * 5 + 3]); + let y_edge = f32::from_bits(buf[segs / 4 + i * 5 + 4]); + println!(" ({:.3}, {:.3}) - ({:.3}, {:.3}) | {:.3}", x0, y0, x1, y1, y_edge); + } + loop { + seg_chunk = buf[seg_chunk / 4 + 1] as usize; + if seg_chunk == 0 { + break; + } + } + } 4 => { let line_width = f32::from_bits(buf[tile_offset / 4 + 2]); let rgba_color = buf[tile_offset / 4 + 3]; @@ -96,11 +119,12 @@ fn trace_ptcl(buf: &[u32]) { let segs = buf[seg_chunk / 4 + 2] as usize; println!(" chunk @{:x}: n={}, segs @{:x}", seg_chunk, n, segs); for i in 0..n { - let x0 = f32::from_bits(buf[segs / 4 + i * 4]); - let y0 = f32::from_bits(buf[segs / 4 + i * 4 + 1]); - let x1 = f32::from_bits(buf[segs / 4 + i * 4 + 2]); - let y1 = f32::from_bits(buf[segs / 4 + i * 4 + 3]); - println!(" ({:.3}, {:.3}) - ({:.3}, {:.3})", x0, y0, x1, y1); + let x0 = f32::from_bits(buf[segs / 4 + i * 5]); + let y0 = f32::from_bits(buf[segs / 4 + i * 5 + 1]); + let x1 = f32::from_bits(buf[segs / 4 + i * 5 + 2]); + let y1 = f32::from_bits(buf[segs / 4 + i * 5 + 3]); + let y_edge = f32::from_bits(buf[segs / 4 + i * 5 + 4]); + println!(" ({:.3}, {:.3}) - ({:.3}, {:.3}) | {:.3}", x0, y0, x1, y1, y_edge); } loop { seg_chunk = buf[seg_chunk / 4 + 1] as usize; @@ -160,8 +184,8 @@ fn main() -> Result<(), Error> { /* let mut data: Vec = Default::default(); device.read_buffer(&renderer.ptcl_buf, &mut data).unwrap(); - piet_gpu::dump_k1_data(&data); - //trace_ptcl(&data); + //piet_gpu::dump_k1_data(&data); + trace_ptcl(&data); */ let mut img_data: Vec = Default::default(); diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 81ea890..3a73417 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -51,7 +51,6 @@ shared uint sh_is_segment[N_SLICE]; // Count of total number of segments in each tile, then // inclusive prefix sum of same. shared uint sh_seg_count[N_TILE]; -shared uint sh_orig_seg_count[N_TILE]; shared uint sh_seg_alloc; // scale factors useful for converting coordinates to tiles @@ -295,7 +294,6 @@ void main() { seg_count += bitCount(sh_bitmaps[i][th_ix] & sh_is_segment[i]); } sh_seg_count[th_ix] = seg_count; - sh_orig_seg_count[th_ix] = seg_count; // Prefix sum of sh_seg_count for (uint i = 0; i < LG_N_TILE; i++) { barrier(); @@ -359,8 +357,23 @@ void main() { uint rd_el_ix = (rd_ix + slice_ix * 32 + bit_ix) % N_RINGBUF; uint element_ix = sh_elements[rd_el_ix]; ref = AnnotatedRef(element_ix * Annotated_size); - AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); - Segment seg = Segment(line.p0, line.p1); + AnnoFillLineSeg line = Annotated_FillLine_read(ref); + float y_edge = 0.0; + // This is basically the same logic as piet-metal, but should be made numerically robust. + if (Annotated_tag(ref) == Annotated_FillLine) { + vec2 tile_xy = xy0 + vec2((tile_ix % N_TILE_X) * TILE_WIDTH_PX, (tile_ix / N_TILE_X) * TILE_HEIGHT_PX); + y_edge = mix(line.p0.y, line.p1.y, (tile_xy.x - line.p0.x) / (line.p1.x - line.p0.x)); + if (min(line.p0.x, line.p1.x) < tile_xy.x && y_edge >= tile_xy.y && y_edge < tile_xy.y + TILE_HEIGHT_PX) { + if (line.p0.x > line.p1.x) { + line.p1 = vec2(tile_xy.x, y_edge); + } else { + line.p0 = vec2(tile_xy.x, y_edge); + } + } else { + y_edge = 1e9; + } + } + Segment seg = Segment(line.p0, line.p1, y_edge); Segment_write(SegmentRef(seg_alloc + Segment_size * ix), seg); } @@ -411,33 +424,50 @@ void main() { switch (tag) { case Annotated_Fill: - /* - if (seg_count > 0) { + if (last_chunk_n > 0 || seg_count > 0) { + SegChunkRef chunk_ref = SegChunkRef(0); + if (seg_count > 0) { + chunk_ref = alloc_seg_chunk(); + SegChunk chunk; + chunk.n = seg_count; + chunk.next = SegChunkRef(0); + uint seg_offset = seg_alloc + seg_start * Segment_size; + chunk.segs = SegmentRef(seg_offset); + SegChunk_write(chunk_ref, chunk); + } + if (last_chunk_n > 0) { + SegChunk chunk; + chunk.n = last_chunk_n; + chunk.next = chunk_ref; + chunk.segs = last_chunk_segs; + SegChunk_write(last_chunk_ref, chunk); + } else { + first_seg_chunk = chunk_ref; + } + 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.seg_ref = first_seg_chunk; 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; + last_chunk_n = 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; + seg_start += seg_count; seg_count = 0; + backdrop = 0; break; case Annotated_Stroke: + // TODO: reduce divergence & code duplication? Much of the + // fill and stroke processing is in common. if (last_chunk_n > 0 || seg_count > 0) { - // TODO: noncontiguous case - SegChunkRef chunk_ref = SegChunkRef(0); if (seg_count > 0) { chunk_ref = alloc_seg_chunk(); diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 069209e9fc4104d855cf5680c2673a39454a7ac8..56337efe2c287438514a7be4724992bd6a4f6b2b 100644 GIT binary patch literal 49152 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 m#x`(c;SeOb;l}qtp5k5-$cUz diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index 4c4aba3..1abcc2b 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -68,11 +68,12 @@ void main() { CmdFill fill = Cmd_Fill_read(cmd_ref); // Probably better to store as float, but conversion is no doubt cheap. float area = float(fill.backdrop); - SegChunkRef fill_seg_chunk_ref = SegChunkRef(fill.seg_ref); + SegChunkRef fill_seg_chunk_ref = fill.seg_ref; do { SegChunk seg_chunk = SegChunk_read(fill_seg_chunk_ref); + SegmentRef segs = seg_chunk.segs; for (int i = 0; i < seg_chunk.n; i++) { - Segment seg = Segment_read(SegmentRef(fill_seg_chunk_ref.offset + SegChunk_size + Segment_size * i)); + Segment seg = Segment_read(Segment_index(segs, i)); vec2 start = seg.start - xy; vec2 end = seg.end - xy; vec2 window = clamp(vec2(start.y, end.y), 0.0, 1.0); @@ -87,6 +88,7 @@ void main() { float a = (b + 0.5 * (d * d - c * c) - xmin) / (xmax - xmin); area += a * (window.x - window.y); } + area += sign(end.x - start.x) * clamp(xy.y - seg.y_edge + 1.0, 0.0, 1.0); } fill_seg_chunk_ref = seg_chunk.next; } while (fill_seg_chunk_ref.offset != 0); diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index 02bd1378c14a8746b89c6c235c86c14f8e34f01a..8060f1ff2b700288356a5af27af23f9511c73062 100644 GIT binary patch literal 19028 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 Dn}E@X diff --git a/piet-gpu/shader/ptcl.h b/piet-gpu/shader/ptcl.h index 2026b46..dd1f9a8 100644 --- a/piet-gpu/shader/ptcl.h +++ b/piet-gpu/shader/ptcl.h @@ -80,7 +80,7 @@ CmdStrokeRef CmdStroke_index(CmdStrokeRef ref, uint index) { } struct CmdFill { - uint seg_ref; + SegChunkRef seg_ref; int backdrop; uint rgba_color; }; @@ -152,9 +152,10 @@ CmdRef Cmd_index(CmdRef ref, uint index) { struct Segment { vec2 start; vec2 end; + float y_edge; }; -#define Segment_size 16 +#define Segment_size 20 SegmentRef Segment_index(SegmentRef ref, uint index) { return SegmentRef(ref.offset + index * Segment_size); @@ -238,7 +239,7 @@ CmdFill CmdFill_read(CmdFillRef ref) { uint raw1 = ptcl[ix + 1]; uint raw2 = ptcl[ix + 2]; CmdFill s; - s.seg_ref = raw0; + s.seg_ref = SegChunkRef(raw0); s.backdrop = int(raw1); s.rgba_color = raw2; return s; @@ -246,7 +247,7 @@ CmdFill CmdFill_read(CmdFillRef ref) { void CmdFill_write(CmdFillRef ref, CmdFill s) { uint ix = ref.offset >> 2; - ptcl[ix + 0] = s.seg_ref; + ptcl[ix + 0] = s.seg_ref.offset; ptcl[ix + 1] = uint(s.backdrop); ptcl[ix + 2] = s.rgba_color; } @@ -399,9 +400,11 @@ Segment Segment_read(SegmentRef ref) { uint raw1 = ptcl[ix + 1]; uint raw2 = ptcl[ix + 2]; uint raw3 = ptcl[ix + 3]; + uint raw4 = ptcl[ix + 4]; Segment s; s.start = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); s.end = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); + s.y_edge = uintBitsToFloat(raw4); return s; } @@ -411,6 +414,7 @@ void Segment_write(SegmentRef ref, Segment s) { ptcl[ix + 1] = floatBitsToUint(s.start.y); ptcl[ix + 2] = floatBitsToUint(s.end.x); ptcl[ix + 3] = floatBitsToUint(s.end.y); + ptcl[ix + 4] = floatBitsToUint(s.y_edge); } SegChunk SegChunk_read(SegChunkRef ref) { 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); From e16f68d89d1c4941e2b85020340061e0b61c823f Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Tue, 26 May 2020 22:46:33 -0700 Subject: [PATCH 5/5] Fix buffer overrun Was a little too eager zeroing out sh_is_segment[] --- piet-gpu/shader/coarse.comp | 2 ++ piet-gpu/shader/coarse.spv | Bin 49152 -> 49152 bytes 2 files changed, 2 insertions(+) diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 3a73417..1f73318 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -133,6 +133,8 @@ void main() { for (uint i = 0; i < N_SLICE; i++) { sh_bitmaps[i][th_ix] = 0; sh_backdrop[i][th_ix] = 0; + } + if (th_ix < N_SLICE) { sh_is_segment[th_ix] = 0; } diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 56337efe2c287438514a7be4724992bd6a4f6b2b..d951b247c1f2e6116832ab6fbd677a0e3ef937c0 100644 GIT binary patch delta 17 YcmZo@U~Xt&-Z00ODTI0RJlmuu0638bTL1t6 delta 17 YcmZo@U~Xt&-Z00O=^4}JdA3PS06d8X>;M1&