diff --git a/sparse_strips/vello_bench/src/data.rs b/sparse_strips/vello_bench/src/data.rs index eda3b7a464..5a2622aa44 100644 --- a/sparse_strips/vello_bench/src/data.rs +++ b/sparse_strips/vello_bench/src/data.rs @@ -132,7 +132,7 @@ impl DataItem { /// Get the unsorted tiles. pub fn unsorted_tiles(&self) -> Tiles { - let mut tiles = Tiles::new(Level::new(), self.height); + let mut tiles = Tiles::new(Level::new(), self.width, self.height); let lines = self.lines(); tiles.make_tiles_analytic_aa(Level::new(), &lines, self.width, self.height); diff --git a/sparse_strips/vello_bench/src/strip.rs b/sparse_strips/vello_bench/src/strip.rs index 0ec6cbf1c1..c57afd635a 100644 --- a/sparse_strips/vello_bench/src/strip.rs +++ b/sparse_strips/vello_bench/src/strip.rs @@ -87,7 +87,7 @@ pub fn render_strips_cull(c: &mut Criterion) { let shifted_lines = shift_lines_50_percent(&item.lines()); - let mut tiler = Tiles::new(simd_level, item.height); + let mut tiler = Tiles::new(simd_level, item.width, item.height); tiler.make_tiles_analytic_aa(simd_level, &shifted_lines, item.width, item.height); tiler.sort_tiles(); @@ -139,7 +139,7 @@ pub fn render_rect(c: &mut Criterion) { &mut storage, None, ); - generator.reset(); + generator.reset(width, height); std::hint::black_box(&storage); }); }); @@ -152,7 +152,7 @@ pub fn render_rect(c: &mut Criterion) { b.iter(|| { storage.clear(); generator.generate_filled_rect_fast(&rect, &mut storage, None); - generator.reset(); + generator.reset(width, height); std::hint::black_box(&storage); }); }); diff --git a/sparse_strips/vello_bench/src/tile.rs b/sparse_strips/vello_bench/src/tile.rs index f6853295f3..8dd1bfe130 100644 --- a/sparse_strips/vello_bench/src/tile.rs +++ b/sparse_strips/vello_bench/src/tile.rs @@ -24,7 +24,7 @@ where g.bench_with_input(BenchmarkId::from_parameter(&item.name), &item, |b, item| { b.iter(|| { - let mut tiler = Tiles::new(Level::new(), item.height); + let mut tiler = Tiles::new(Level::new(), item.width, item.height); op(&mut tiler, &lines, item.width, item.height); }); }); diff --git a/sparse_strips/vello_common/src/strip_generator.rs b/sparse_strips/vello_common/src/strip_generator.rs index 9a8bfc237b..f06b15ca80 100644 --- a/sparse_strips/vello_common/src/strip_generator.rs +++ b/sparse_strips/vello_common/src/strip_generator.rs @@ -95,7 +95,7 @@ impl StripGenerator { Self { level, line_buf: Vec::new(), - tiles: Tiles::new(level, height), + tiles: Tiles::new(level, width, height), flatten_ctx: FlattenCtx::default(), stroke_ctx: StrokeCtx::default(), temp_storage: StripStorage::default(), @@ -238,10 +238,12 @@ impl StripGenerator { ); } - /// Reset the strip generator. - pub fn reset(&mut self) { + /// Reset the strip generator for a viewport size, resizing only when needed. + pub fn reset(&mut self, width: u16, height: u16) { + self.width = width; + self.height = height; self.line_buf.clear(); - self.tiles.reset(); + self.tiles.reset(width, height); self.temp_storage.clear(); } } @@ -307,7 +309,7 @@ mod tests { assert!(!generator.line_buf.is_empty()); assert!(!storage.is_empty()); - generator.reset(); + generator.reset(100, 100); storage.clear(); assert!(generator.line_buf.is_empty()); @@ -329,7 +331,7 @@ mod tests { &mut storage_path, None, ); - generator.reset(); + generator.reset(100, 100); generator.generate_filled_rect_fast(&rect, &mut storage_rect, None); diff --git a/sparse_strips/vello_common/src/tile.rs b/sparse_strips/vello_common/src/tile.rs index 9c32a8943e..a516a35e09 100644 --- a/sparse_strips/vello_common/src/tile.rs +++ b/sparse_strips/vello_common/src/tile.rs @@ -53,6 +53,7 @@ pub struct CulledWindings { pub active: Vec, /// Flag indicating if any geometry was early-culled outside the viewport. pub culled: bool, + height: u16, } impl CulledWindings { @@ -63,25 +64,36 @@ impl CulledWindings { /// Bitmask equivalent to modulo `WORD_BITS` (32 - 1 = 31). const WORD_MASK: usize = 31; - /// Constructor chained to `Tiles`' constructor and matches its lifetime. Since `Tiles` itself - /// matches the lifetime of `StripGenerator`, we know that the viewport dimensions will never - /// change, and thus the backing vecs never need to be resized. (For now). + /// Constructor chained to `Tiles`' constructor and matching its initial viewport height. pub fn new(height: u16) -> Self { - let height_usize = height as usize; - let tile_height = Tile::HEIGHT as usize; - let num_rows = height_usize.div_ceil(tile_height); - let num_bits = num_rows.div_ceil(Self::WORD_BITS); + let (num_rows, num_bits) = Self::sizes(height); Self { partial: vec![[0.0; Tile::HEIGHT as usize]; num_rows], coarse: vec![0; num_rows], active: vec![0; num_bits], culled: false, + height, } } - /// Clears but does not resize - pub fn reset(&mut self) { + fn sizes(height: u16) -> (usize, usize) { + let num_rows = usize::from(height).div_ceil(Tile::HEIGHT as usize); + let num_bits = num_rows.div_ceil(Self::WORD_BITS); + + (num_rows, num_bits) + } + + /// Reset the winding buffers. + pub fn reset(&mut self, height: u16) { + if self.height != height { + let (num_rows, num_bits) = Self::sizes(height); + self.partial.resize(num_rows, [0.0; Tile::HEIGHT as usize]); + self.coarse.resize(num_rows, 0); + self.active.resize(num_bits, 0); + self.height = height; + } + // TODO: Maybe consider tracking touched regions and only resetting those // instead of always the full array? if self.culled { @@ -414,17 +426,21 @@ pub struct Tiles { tile_buf: Vec, level: Level, sorted: bool, + width: u16, + height: u16, /// Auxiliary data tracking row windings and active rows for early culling. pub windings: CulledWindings, } impl Tiles { /// Create a new tiles container. - pub fn new(level: Level, height: u16) -> Self { + pub fn new(level: Level, width: u16, height: u16) -> Self { Self { tile_buf: vec![], level, sorted: false, + width, + height, windings: CulledWindings::new(height), } } @@ -444,9 +460,11 @@ impl Tiles { self.windings.culled } - /// Reset the tiles' container. - pub fn reset(&mut self) { - self.windings.reset(); + /// Reset the tiles' container and resize to the given dimensions. + pub fn reset(&mut self, width: u16, height: u16) { + self.windings.reset(height); + self.width = width; + self.height = height; self.tile_buf.clear(); self.sorted = false; } @@ -511,7 +529,7 @@ impl Tiles { width: u16, height: u16, ) -> bool { - self.reset(); + self.reset(width, height); if width == 0 || height == 0 { return self.windings.culled; @@ -939,7 +957,7 @@ impl Tiles { /// - W (Winding): Tracks whether the line touched the top edge of the tile. /// - R/L/B/T: Right, Left, Bottom, and Top edge intersections. pub fn make_tiles_msaa(&mut self, lines: &[Line], width: u16, height: u16) { - self.reset(); + self.reset(width, height); if width == 0 || height == 0 { return; @@ -1288,6 +1306,14 @@ mod tests { const VIEW_DIM: u16 = 100; const F_V_DIM: f32 = VIEW_DIM as f32; + fn new_tiles() -> Tiles { + Tiles::new( + Level::try_detect().unwrap_or(Level::baseline()), + VIEW_DIM, + VIEW_DIM, + ) + } + impl Tiles { fn assert_tiles_match( &mut self, @@ -1377,7 +1403,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &[]); } @@ -1402,7 +1428,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, W | T), Tile::new(1, 0, 1, W | T), @@ -1448,7 +1474,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(1, 24, 0, B), Tile::new(2, 24, 1, B), @@ -1471,7 +1497,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, W | T | R), Tile::new(1, 0, 0, L | B), @@ -1502,7 +1528,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 23, 0, B), Tile::new(0, 24, 0, W | T | R), @@ -1533,7 +1559,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(24, 0, 0, R), Tile::new(23, 0, 1, R), @@ -1560,7 +1586,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, L), Tile::new(0, 0, 1, L | R), @@ -1583,7 +1609,7 @@ mod tests { p1: Point { x: 90.0, y: -5.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &[]); } @@ -1600,7 +1626,7 @@ mod tests { }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &[]); } @@ -1611,7 +1637,7 @@ mod tests { p1: Point { x: 10.0, y: 10.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 2, 0, L | R), Tile::new(1, 2, 0, L | R), @@ -1634,7 +1660,7 @@ mod tests { }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(23, 2, 0, R), Tile::new(24, 2, 0, L | R)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -1659,7 +1685,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &[]); } @@ -1679,7 +1705,7 @@ mod tests { RectU16::new(0, 0, VIEWPORT_WIDTH, VIEWPORT_HEIGHT), ); - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); tiles.assert_tiles_match(&line_buf, VIEWPORT_WIDTH, VIEWPORT_HEIGHT, &[]); } @@ -1700,7 +1726,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, W | T), Tile::new(0, 0, 1, W | B | T), @@ -1737,7 +1763,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 24, 0, B), Tile::new(0, 23, 1, B), @@ -1754,7 +1780,7 @@ mod tests { p1: Point { x: 2.0, y: -1.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, W | L | T)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -1773,7 +1799,7 @@ mod tests { }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(24, 24, 0, R | B)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -1789,7 +1815,7 @@ mod tests { p1: Point { x: 8.5, y: 1.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, R), Tile::new(1, 0, 0, R | L), @@ -1799,6 +1825,38 @@ mod tests { tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); } + #[test] + fn resize_works_correctly() { + let lines = [ + Line { + p0: Point { x: 1.5, y: 1.0 }, + p1: Point { x: 8.5, y: 1.0 }, + }, + Line { + p0: Point { x: 1.5, y: 13.0 }, + p1: Point { x: 8.5, y: 13.0 }, + }, + ]; + let small_expected = [ + Tile::new(0, 0, 0, R), + Tile::new(1, 0, 0, R | L), + Tile::new(2, 0, 0, L), + ]; + let large_expected = [ + Tile::new(0, 0, 0, R), + Tile::new(1, 0, 0, R | L), + Tile::new(2, 0, 0, L), + Tile::new(0, 3, 1, R), + Tile::new(1, 3, 1, R | L), + Tile::new(2, 3, 1, L), + ]; + + let mut tiles = Tiles::new(Level::baseline(), 12, 8); + tiles.assert_tiles_match(&lines, 12, 8, &small_expected); + tiles.assert_tiles_match(&lines, 12, 16, &large_expected); + tiles.assert_tiles_match(&lines, 12, 8, &small_expected); + } + #[test] fn horizontal_line_right_to_left_three_tile() { let lines = [Line { @@ -1806,7 +1864,7 @@ mod tests { p1: Point { x: 1.5, y: 1.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, R), Tile::new(1, 0, 0, R | L), @@ -1823,7 +1881,7 @@ mod tests { p1: Point { x: 12.5, y: 1.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, R), Tile::new(1, 0, 0, R | L), @@ -1841,7 +1899,7 @@ mod tests { p1: Point { x: 1.0, y: 8.5 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, B), Tile::new(0, 1, 0, W | T | B), @@ -1858,7 +1916,7 @@ mod tests { p1: Point { x: 1.0, y: 13.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, B), Tile::new(0, 1, 0, W | T | B), @@ -1876,7 +1934,7 @@ mod tests { p1: Point { x: 1.0, y: 1.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, B), Tile::new(0, 1, 0, W | T | B), @@ -1894,7 +1952,7 @@ mod tests { p1: Point { x: 1.0, y: 1.5 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, B), Tile::new(0, 1, 0, W | T | B), @@ -1912,7 +1970,7 @@ mod tests { p1: Point { x: 1.0, y: 8.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, B), Tile::new(0, 1, 0, W | T)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -1925,7 +1983,7 @@ mod tests { p1: Point { x: 1.0, y: 7.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, W | B), Tile::new(0, 1, 0, W | T)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -1941,7 +1999,7 @@ mod tests { p1: Point { x: 11.0, y: 9.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, R), Tile::new(1, 0, 0, L | B), @@ -1960,7 +2018,7 @@ mod tests { p1: Point { x: 1.0, y: 1.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, R), Tile::new(1, 0, 0, L | B), @@ -1979,7 +2037,7 @@ mod tests { p1: Point { x: 14.0, y: 6.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(2, 1, 0, R | B), Tile::new(3, 1, 0, L), @@ -1998,7 +2056,7 @@ mod tests { p1: Point { x: 2.0, y: 11.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(2, 1, 0, R | B), Tile::new(3, 1, 0, L), @@ -2023,7 +2081,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, 0), Tile::new(0, 0, 1, 0)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -2036,7 +2094,7 @@ mod tests { p1: Point { x: 5.0, y: 3.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(1, 0, 0, L), Tile::new(0, 1, 0, R), @@ -2053,7 +2111,7 @@ mod tests { p1: Point { x: 0.1, y: 0.1 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, R), Tile::new(1, 0, 0, L), @@ -2070,7 +2128,7 @@ mod tests { p1: Point { x: 9.0, y: 9.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(1, 1, 0, R), Tile::new(2, 1, 0, L), @@ -2087,7 +2145,7 @@ mod tests { p1: Point { x: 9.0, y: 5.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(1, 1, 0, R | B), Tile::new(2, 1, 0, L), @@ -2104,7 +2162,7 @@ mod tests { p1: Point { x: 4.0, y: 4.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, W | R), Tile::new(1, 0, 0, L)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -2117,7 +2175,7 @@ mod tests { p1: Point { x: 4.0, y: 0.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, R), Tile::new(1, 0, 0, W | L)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -2130,7 +2188,7 @@ mod tests { p1: Point { x: 8.0, y: 8.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, W | R), Tile::new(1, 0, 0, L), @@ -2148,7 +2206,7 @@ mod tests { p1: Point { x: 8.0, y: 0.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(1, 0, 0, R | L), Tile::new(2, 0, 0, W | L), @@ -2166,7 +2224,7 @@ mod tests { p1: Point { x: 8.0, y: 2.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, R), Tile::new(1, 0, 0, R | L), @@ -2197,7 +2255,7 @@ mod tests { }, }]; - let mut tiles = Tiles::new(Level::baseline(), HEIGHT); + let mut tiles = Tiles::new(Level::baseline(), HEIGHT, HEIGHT); tiles.make_tiles_analytic_aa(Level::baseline(), &lines, WIDTH, HEIGHT); let row_tiles: Vec = tiles @@ -2219,7 +2277,7 @@ mod tests { p1: Point { x: 4.0, y: 0.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, R | B), Tile::new(1, 0, 0, W | L), @@ -2236,7 +2294,7 @@ mod tests { p1: Point { x: 4.0, y: 8.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [ Tile::new(0, 0, 0, W | B), Tile::new(0, 1, 0, W | R | T), @@ -2256,7 +2314,7 @@ mod tests { p1: Point { x: 3.0, y: 3.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, 0)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -2269,7 +2327,7 @@ mod tests { p1: Point { x: 3.0, y: 1.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, 0)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -2282,7 +2340,7 @@ mod tests { p1: Point { x: 1.0, y: 3.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, W)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -2295,7 +2353,7 @@ mod tests { p1: Point { x: 4.0, y: 1.0 }, }]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, R), Tile::new(1, 0, 0, L)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -2314,7 +2372,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, 0), Tile::new(0, 0, 1, 0)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -2333,7 +2391,7 @@ mod tests { }, ]; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); let expected = [Tile::new(0, 0, 0, W), Tile::new(0, 0, 1, W)]; tiles.assert_tiles_match(&lines, VIEW_DIM, VIEW_DIM, &expected); @@ -2344,16 +2402,16 @@ mod tests { //============================================================================================== #[test] fn test_culled_windings_new_and_reset() { - let mut windings = CulledWindings::new(100); - assert_eq!(windings.partial.len(), 25); - assert_eq!(windings.coarse.len(), 25); + let mut windings = CulledWindings::new(8); + assert_eq!(windings.partial.len(), 2); + assert_eq!(windings.coarse.len(), 2); assert_eq!(windings.active.len(), 1); windings.coarse[0] = 1; windings.active[0] = 0xFF; windings.culled = true; - windings.reset(); + windings.reset(8); assert_eq!(windings.coarse[0], 0); assert_eq!(windings.active[0], 0); @@ -2361,9 +2419,14 @@ mod tests { windings.active[0] = 0xFF; windings.culled = false; - windings.reset(); + windings.reset(8); assert_eq!(windings.coarse[0], 1); assert_eq!(windings.active[0], 0xFF); + + windings.culled = true; + windings.reset(12); + assert_eq!(windings.coarse[0], 0); + assert_eq!(windings.active[0], 0); } #[test] @@ -2432,7 +2495,7 @@ mod tests { p1: Point { x: 224.0, y: 388.0 }, }; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); tiles.make_tiles_msaa(&[line], 600, 600); tiles.make_tiles_analytic_aa(Level::baseline(), &[line], 600, 600); } @@ -2451,7 +2514,7 @@ mod tests { }, }; - let mut tiles = Tiles::new(Level::try_detect().unwrap_or(Level::baseline()), VIEW_DIM); + let mut tiles = new_tiles(); tiles.make_tiles_analytic_aa(Level::baseline(), &[line], 200, 100); tiles.make_tiles_msaa(&[line], 200, 100); } @@ -2459,7 +2522,7 @@ mod tests { #[test] fn sort_test() { let mut lines: Vec = Vec::new(); - let mut tiles = Tiles::new(Level::baseline(), VIEW_DIM); + let mut tiles = Tiles::new(Level::baseline(), VIEW_DIM, VIEW_DIM); let step = 4.0; let mut y = F_V_DIM - 10.0; diff --git a/sparse_strips/vello_cpu/examples/winit/src/main.rs b/sparse_strips/vello_cpu/examples/winit/src/main.rs index b53f6091bb..cef0c18110 100644 --- a/sparse_strips/vello_cpu/examples/winit/src/main.rs +++ b/sparse_strips/vello_cpu/examples/winit/src/main.rs @@ -211,14 +211,7 @@ impl ApplicationHandler for App { .unwrap(); self.pixmap.resize(width as u16, height as u16); - self.renderer = RenderContext::new_with( - width as u16, - height as u16, - RenderSettings { - num_threads: 0, - ..Default::default() - }, - ); + self.renderer.reset_and_resize(width as u16, height as u16); window.request_redraw(); } diff --git a/sparse_strips/vello_cpu/src/dispatch/mod.rs b/sparse_strips/vello_cpu/src/dispatch/mod.rs index 8c1fde1951..b0ece11fe4 100644 --- a/sparse_strips/vello_cpu/src/dispatch/mod.rs +++ b/sparse_strips/vello_cpu/src/dispatch/mod.rs @@ -65,7 +65,7 @@ pub(crate) trait Dispatcher: Debug + Send { filter_data: Option, ); fn pop_layer(&mut self); - fn reset(&mut self); + fn reset(&mut self, width: u16, height: u16); fn flush(&mut self); fn rasterize( &self, diff --git a/sparse_strips/vello_cpu/src/dispatch/multi_threaded.rs b/sparse_strips/vello_cpu/src/dispatch/multi_threaded.rs index 39e26b63c9..7d78792119 100644 --- a/sparse_strips/vello_cpu/src/dispatch/multi_threaded.rs +++ b/sparse_strips/vello_cpu/src/dispatch/multi_threaded.rs @@ -587,8 +587,8 @@ impl Dispatcher for MultiThreadedDispatcher { .expect("layer stack underflow"); } - fn reset(&mut self) { - // Bucketer will be reset on demand. + fn reset(&mut self, width: u16, height: u16) { + // Bucketer will be reset lazily during rasterization with the active viewport. self.clip_context.reset(); self.recorder.reset(); self.strip_storage.clear(); @@ -599,7 +599,7 @@ impl Dispatcher for MultiThreadedDispatcher { self.layer_depth = 0; self.task_sender = None; self.recorded_command_receiver = None; - self.strip_generator.reset(); + self.strip_generator.reset(width, height); self.alpha_storage.with_inner(|alphas| { for alpha in alphas { alpha.clear(); @@ -614,7 +614,7 @@ impl Dispatcher for MultiThreadedDispatcher { self.thread_pool.spawn_broadcast(move |_| { let worker = workers.get().unwrap(); let mut borrowed = worker.borrow_mut(); - borrowed.reset(); + borrowed.reset(width, height); t_barrier.wait(); }); diff --git a/sparse_strips/vello_cpu/src/dispatch/multi_threaded/worker.rs b/sparse_strips/vello_cpu/src/dispatch/multi_threaded/worker.rs index ea2a9d433a..3aa63a7dec 100644 --- a/sparse_strips/vello_cpu/src/dispatch/multi_threaded/worker.rs +++ b/sparse_strips/vello_cpu/src/dispatch/multi_threaded/worker.rs @@ -36,8 +36,8 @@ impl Worker { self.thread_id } - pub(crate) fn reset(&mut self) { - self.strip_generator.reset(); + pub(crate) fn reset(&mut self, width: u16, height: u16) { + self.strip_generator.reset(width, height); } pub(crate) fn run_render_task( diff --git a/sparse_strips/vello_cpu/src/dispatch/single_threaded.rs b/sparse_strips/vello_cpu/src/dispatch/single_threaded.rs index f98e57855c..784a12b86f 100644 --- a/sparse_strips/vello_cpu/src/dispatch/single_threaded.rs +++ b/sparse_strips/vello_cpu/src/dispatch/single_threaded.rs @@ -292,8 +292,7 @@ impl SingleThreadedDispatcher { .height() .saturating_add(padding.y0) .saturating_add(padding.y1); - // TODO: Once `StripGenerator`s (in particular `Tiles`) can be resized, - // we can use a pool of strip generators. + // TODO: Use a pool of strip generators. let filter_generator = StripGenerator::new(width, height, self.level); let parent_generator = core::mem::replace(&mut self.strip_generator, filter_generator); self.strip_generator_stack.push(parent_generator); @@ -441,13 +440,13 @@ impl Dispatcher for SingleThreadedDispatcher { } } - fn reset(&mut self) { + fn reset(&mut self, width: u16, height: u16) { // Bucketer will be reset on demand, so no need to reset it here. self.clip_state.reset(); self.recorder.reset(); self.strip_generator_stack.clear(); - self.strip_generator.reset(); self.strip_storage.clear(); + self.strip_generator.reset(width, height); } fn flush(&mut self) { @@ -605,7 +604,7 @@ mod tests { assert!(!dispatcher.strip_storage.strips.is_empty()); assert!(!dispatcher.recorder.root_cmds.is_empty()); - dispatcher.reset(); + dispatcher.reset(100, 100); // Verify all buffers are cleared. assert!(dispatcher.strip_storage.strips.is_empty()); diff --git a/sparse_strips/vello_cpu/src/render.rs b/sparse_strips/vello_cpu/src/render.rs index 3124ad2f4a..f81cafa148 100644 --- a/sparse_strips/vello_cpu/src/render.rs +++ b/sparse_strips/vello_cpu/src/render.rs @@ -681,9 +681,17 @@ impl RenderContext { self.filter = None; } + /// Reset the render context and update the scene size. + pub fn reset_and_resize(&mut self, width: u16, height: u16) { + self.width = width; + self.height = height; + + self.reset(); + } + /// Reset the render context. pub fn reset(&mut self) { - self.dispatcher.reset(); + self.dispatcher.reset(self.width, self.height); self.encoded_paints.clear(); self.mask = None; self.root_transforms.clear(); @@ -1069,6 +1077,28 @@ mod tests { } } + #[test] + fn reset_and_resize_updates_scene_size() { + let mut ctx = RenderContext::new(8, 4); + let mut resources = Resources::new(); + let mut pixmap = Pixmap::new(4, 8); + + ctx.reset_and_resize(4, 8); + assert_eq!(ctx.width(), 4); + assert_eq!(ctx.height(), 8); + + ctx.set_paint(BLUE); + ctx.fill_rect(&Rect::new(0.0, 0.0, 4.0, 8.0)); + ctx.flush(); + ctx.render(&mut pixmap, &mut resources); + + for y in 0..8 { + for x in 0..4 { + assert_eq!(pixmap.sample(x, y), blue_pixel(), "pixel at ({x}, {y})"); + } + } + } + #[test] fn render_into_raw_buffer() { let ctx = red_rect_context(2, 1, Rect::new(0.0, 0.0, 2.0, 1.0)); diff --git a/sparse_strips/vello_hybrid/src/scene.rs b/sparse_strips/vello_hybrid/src/scene.rs index 7bc9f19643..b51c087d0a 100644 --- a/sparse_strips/vello_hybrid/src/scene.rs +++ b/sparse_strips/vello_hybrid/src/scene.rs @@ -1085,7 +1085,7 @@ impl Scene { /// Reset scene to default values. pub fn reset(&mut self) { self.wide.reset(); - self.strip_generator.reset(); + self.strip_generator.reset(self.width, self.height); self.clip_context.reset(); // Set the strip storage back to `Append` mode since the fast path is re-enabled on reset. { diff --git a/sparse_strips/vello_toy/src/debug.rs b/sparse_strips/vello_toy/src/debug.rs index f6dd158004..468425331a 100644 --- a/sparse_strips/vello_toy/src/debug.rs +++ b/sparse_strips/vello_toy/src/debug.rs @@ -33,7 +33,7 @@ fn main() { Document::new().set("viewBox", (-10, -10, args.width + 20, args.height + 20)); let mut line_buf = vec![]; - let mut tiles = Tiles::new(Level::new(), args.height); + let mut tiles = Tiles::new(Level::new(), args.width, args.height); let mut strip_buf = vec![]; let mut alpha_buf = vec![]; let mut wide = Wide::::new(args.width, args.height);