.
diff --git a/sparse_strips/vello_common/src/recording.rs b/sparse_strips/vello_common/src/recording.rs index f34b1cb..80863d6 100644 --- a/sparse_strips/vello_common/src/recording.rs +++ b/sparse_strips/vello_common/src/recording.rs
@@ -67,6 +67,14 @@ pub fn strip_start_indices(&self) -> &[usize] { &self.strip_start_indices } + + /// Takes ownership of all buffers. + pub fn take(&mut self) -> (Vec<Strip>, Vec<u8>, Vec<usize>) { + let strips = core::mem::take(&mut self.strips); + let alphas = core::mem::take(&mut self.alphas); + let strip_start_indices = core::mem::take(&mut self.strip_start_indices); + (strips, alphas, strip_start_indices) + } } /// A recording of rendering commands that can cache generated strips. @@ -168,6 +176,11 @@ (self.cached_strips.strips(), self.cached_strips.alphas()) } + /// Takes cached strip buffers. + pub fn take_cached_strips(&mut self) -> (Vec<Strip>, Vec<u8>, Vec<usize>) { + self.cached_strips.take() + } + /// Get strip start indices. pub fn get_strip_start_indices(&self) -> &[usize] { self.cached_strips.strip_start_indices() @@ -206,14 +219,11 @@ /// /// # State Modification During Replay /// -/// **Important:** When replaying recordings using methods like `render_recording()`, +/// **Important:** When replaying recordings using methods like `execute_recording()`, /// the renderer's state (transform, paint, fill rule, stroke settings, etc.) will be /// modified to match the state changes captured in the recording. The renderer will /// be left in the final state after all commands have been executed. /// -/// If you need to preserve the original renderer state, save it before replaying -/// recordings and restore it afterward. -/// /// # Multithreading Limitation /// /// **Note:** Recording and replay functionality is not currently implemented for @@ -227,17 +237,18 @@ /// ```ignore /// let mut recording = Recording::new(); /// scene.record(&mut recording, |ctx| { ... }); -/// scene.render_recording(&mut recording); +/// scene.prepare_recording(&mut recording); +/// scene.execute_recording(&recording); /// ``` /// -/// And the following to prepare for later rendering: +/// Or to prepare for later rendering: /// ```ignore /// let mut recording = Recording::new(); /// scene.record(&mut recording, |ctx| { ... }); /// scene.prepare_recording(&mut recording); /// /// // sometime later -/// scene.render_recording(&mut recording); +/// scene.execute_recording(&recording); /// ``` pub trait Recordable { /// Record rendering commands into a recording. @@ -280,21 +291,29 @@ /// ``` fn prepare_recording(&mut self, recording: &mut Recording); - /// Render using a recording (caches strips on first use). + /// Execute a recording directly without preparation. /// - /// This method executes a previously recorded sequence of operations. - /// On first use, it will generate and cache the necessary rendering data. - /// Subsequent calls will reuse the cached data for better performance. - fn render_recording(&mut self, recording: &mut Recording) { - self.prepare_recording(recording); - self.execute_recording(recording); - } - - /// Execute a recording. + /// This method executes the rendering commands from a recording, using any + /// cached sparse strips that have been previously generated. If the recording + /// has not been prepared (no cached strips), this will result in empty rendering. /// - /// This method executes a previously recorded sequence of operations. - /// It will generate and cache the necessary rendering data if it hasn't been done yet. - /// Subsequent calls will reuse the cached data for better performance. + /// Use this method when you have a recording that has already been prepared + /// via `prepare_recording()`, or when you want to execute commands immediately + /// without explicit preparation. + /// + /// # Example + /// ```ignore + /// let mut recording = Recording::new(); + /// scene.record(&mut recording, |ctx| { + /// ctx.fill_rect(&Rect::new(0.0, 0.0, 100.0, 100.0)); + /// }); + /// + /// // Prepare strips first + /// scene.prepare_recording(&mut recording); + /// + /// // Then execute with cached strips + /// scene.execute_recording(&recording); + /// ``` fn execute_recording(&mut self, recording: &Recording); }
diff --git a/sparse_strips/vello_cpu/src/dispatch/mod.rs b/sparse_strips/vello_cpu/src/dispatch/mod.rs index 109fef7..1ee0850 100644 --- a/sparse_strips/vello_cpu/src/dispatch/mod.rs +++ b/sparse_strips/vello_cpu/src/dispatch/mod.rs
@@ -57,6 +57,6 @@ ); fn alpha_buf(&self) -> &[u8]; fn extend_alpha_buf(&mut self, alphas: &[u8]); - fn take_alpha_buf(&mut self) -> Vec<u8>; + fn replace_alpha_buf(&mut self, alphas: Vec<u8>) -> Vec<u8>; fn set_alpha_buf(&mut self, alphas: Vec<u8>); }
diff --git a/sparse_strips/vello_cpu/src/dispatch/multi_threaded.rs b/sparse_strips/vello_cpu/src/dispatch/multi_threaded.rs index d8c8e01..726bf10 100644 --- a/sparse_strips/vello_cpu/src/dispatch/multi_threaded.rs +++ b/sparse_strips/vello_cpu/src/dispatch/multi_threaded.rs
@@ -373,8 +373,8 @@ unimplemented!("extend_alpha_buf is not implemented for multi-threaded dispatcher") } - fn take_alpha_buf(&mut self) -> Vec<u8> { - unimplemented!("take_alpha_buf is not implemented for multi-threaded dispatcher") + fn replace_alpha_buf(&mut self, _alphas: Vec<u8>) -> Vec<u8> { + unimplemented!("replace_alpha_buf is not implemented for multi-threaded dispatcher") } fn set_alpha_buf(&mut self, _alphas: Vec<u8>) {
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 394eede..fce1a3e 100644 --- a/sparse_strips/vello_cpu/src/dispatch/multi_threaded/worker.rs +++ b/sparse_strips/vello_cpu/src/dispatch/multi_threaded/worker.rs
@@ -157,6 +157,6 @@ } pub(crate) fn finalize(&mut self) -> Vec<u8> { - self.strip_generator.take_alpha_buf() + self.strip_generator.replace_alpha_buf(Vec::new()) } }
diff --git a/sparse_strips/vello_cpu/src/dispatch/single_threaded.rs b/sparse_strips/vello_cpu/src/dispatch/single_threaded.rs index d040c93..42fb617 100644 --- a/sparse_strips/vello_cpu/src/dispatch/single_threaded.rs +++ b/sparse_strips/vello_cpu/src/dispatch/single_threaded.rs
@@ -109,8 +109,8 @@ self.strip_generator.extend_alpha_buf(alphas); } - fn take_alpha_buf(&mut self) -> Vec<u8> { - self.strip_generator.take_alpha_buf() + fn replace_alpha_buf(&mut self, alphas: Vec<u8>) -> Vec<u8> { + self.strip_generator.replace_alpha_buf(alphas) } fn set_alpha_buf(&mut self, alphas: Vec<u8>) {
diff --git a/sparse_strips/vello_cpu/src/render.rs b/sparse_strips/vello_cpu/src/render.rs index ac96ca4..b1d3fd3 100644 --- a/sparse_strips/vello_cpu/src/render.rs +++ b/sparse_strips/vello_cpu/src/render.rs
@@ -601,8 +601,9 @@ impl Recordable for RenderContext { fn prepare_recording(&mut self, recording: &mut Recording) { + let buffers = recording.take_cached_strips(); let (strips, alphas, strip_start_indices) = - self.generate_strips_from_commands(recording.commands()); + self.generate_strips_from_commands(recording.commands(), buffers); recording.set_cached_strips(strips, alphas, strip_start_indices); } @@ -707,12 +708,15 @@ fn generate_strips_from_commands( &mut self, commands: &[RenderCommand], + buffers: (Vec<Strip>, Vec<u8>, Vec<usize>), ) -> (Vec<Strip>, Vec<u8>, Vec<usize>) { - let saved_state = self.take_current_state(); + let (mut collected_strips, mut cached_alphas, mut strip_start_indices) = buffers; + collected_strips.clear(); + cached_alphas.clear(); + strip_start_indices.clear(); + let saved_state = self.take_current_state(cached_alphas); let mut strip_generator = StripGenerator::new(self.width, self.height, self.level); - let mut collected_strips = Vec::new(); - let mut strip_start_indices = Vec::new(); for command in commands { let start_index = collected_strips.len(); @@ -813,14 +817,14 @@ } /// Save the current rendering state. - fn take_current_state(&mut self) -> RenderState { + fn take_current_state(&mut self, alphas: Vec<u8>) -> RenderState { RenderState { paint: self.paint.clone(), paint_transform: self.paint_transform, transform: self.transform, fill_rule: self.fill_rule, stroke: core::mem::take(&mut self.stroke), - alphas: self.dispatcher.take_alpha_buf(), + alphas: self.dispatcher.replace_alpha_buf(alphas), } }
diff --git a/sparse_strips/vello_cpu/src/strip_generator.rs b/sparse_strips/vello_cpu/src/strip_generator.rs index 4debfb4..a1fcd2a 100644 --- a/sparse_strips/vello_cpu/src/strip_generator.rs +++ b/sparse_strips/vello_cpu/src/strip_generator.rs
@@ -91,6 +91,10 @@ core::mem::take(&mut self.alphas) } + pub(crate) fn replace_alpha_buf(&mut self, alphas: Vec<u8>) -> Vec<u8> { + core::mem::replace(&mut self.alphas, alphas) + } + pub(crate) fn reset(&mut self) { self.line_buf.clear(); self.tiles.reset();
diff --git a/sparse_strips/vello_hybrid/examples/scenes/src/svg.rs b/sparse_strips/vello_hybrid/examples/scenes/src/svg.rs index cb73a1a..124bf69 100644 --- a/sparse_strips/vello_hybrid/examples/scenes/src/svg.rs +++ b/sparse_strips/vello_hybrid/examples/scenes/src/svg.rs
@@ -82,7 +82,7 @@ // Case 1: Identical transforms - can reuse directly if transforms_are_identical(recording.transform(), current_transform) { - scene.render_recording(recording); + scene.execute_recording(recording); print_render_stats("Identical ", start.elapsed(), recording); return RenderResult { is_reused: true }; } @@ -100,7 +100,8 @@ scene.record(&mut new_recording, |recorder| { render_svg_record(recorder, &scene_obj.svg.items, current_transform); }); - scene.render_recording(&mut new_recording); + scene.prepare_recording(&mut new_recording); + scene.execute_recording(&new_recording); new_recording.set_transform(current_transform); print_render_stats("Fresh ", start.elapsed(), &new_recording);
diff --git a/sparse_strips/vello_hybrid/src/scene.rs b/sparse_strips/vello_hybrid/src/scene.rs index 700a9e3..7ac5c60 100644 --- a/sparse_strips/vello_hybrid/src/scene.rs +++ b/sparse_strips/vello_hybrid/src/scene.rs
@@ -375,8 +375,9 @@ impl Recordable for Scene { fn prepare_recording(&mut self, recording: &mut Recording) { + let buffers = recording.take_cached_strips(); let (strips, alphas, strip_start_indices) = - self.generate_strips_from_commands(recording.commands()); + self.generate_strips_from_commands(recording.commands(), buffers); recording.set_cached_strips(strips, alphas, strip_start_indices); } @@ -466,11 +467,14 @@ fn generate_strips_from_commands( &mut self, commands: &[RenderCommand], + buffers: (Vec<Strip>, Vec<u8>, Vec<usize>), ) -> (Vec<Strip>, Vec<u8>, Vec<usize>) { - let saved_state = self.take_current_state(); + let (mut collected_strips, mut cached_alphas, mut strip_start_indices) = buffers; + collected_strips.clear(); + cached_alphas.clear(); + strip_start_indices.clear(); - let mut collected_strips = Vec::new(); - let mut strip_start_indices = Vec::new(); + let saved_state = self.take_current_state(cached_alphas); for command in commands { let start_index = collected_strips.len(); @@ -507,10 +511,10 @@ } } - let alphas = core::mem::take(&mut self.alphas); + let collected_alphas = core::mem::take(&mut self.alphas); self.restore_state(saved_state); - (collected_strips, alphas, strip_start_indices) + (collected_strips, collected_alphas, strip_start_indices) } /// Prepare cached strips for rendering by adjusting alpha indices and extending alpha buffer. @@ -570,7 +574,7 @@ } /// Save current rendering state. - fn take_current_state(&mut self) -> RenderState { + fn take_current_state(&mut self, cached_alphas: Vec<u8>) -> RenderState { RenderState { paint: self.paint.clone(), paint_transform: self.paint_transform, @@ -579,7 +583,7 @@ blend_mode: self.blend_mode, stroke: core::mem::take(&mut self.stroke), strip_buf: core::mem::take(&mut self.strip_buf), - alphas: core::mem::take(&mut self.alphas), + alphas: core::mem::replace(&mut self.alphas, cached_alphas), } }
diff --git a/sparse_strips/vello_sparse_tests/snapshots/recording_incremental_build.png b/sparse_strips/vello_sparse_tests/snapshots/recording_incremental_build.png index ab97057..5e0f1d7 100644 --- a/sparse_strips/vello_sparse_tests/snapshots/recording_incremental_build.png +++ b/sparse_strips/vello_sparse_tests/snapshots/recording_incremental_build.png
@@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a993966cca4c8b4ac88d1c3766e1c679dab24dc92e780f357c1b6635bc657c8d -size 175 +oid sha256:fd33c91b2b8a16a61bbcb8461ae5fb3d10ff8d26d4915125fad3c2b9aa9c532b +size 233
diff --git a/sparse_strips/vello_sparse_tests/tests/recording.rs b/sparse_strips/vello_sparse_tests/tests/recording.rs index 28138c8..034f22e 100644 --- a/sparse_strips/vello_sparse_tests/tests/recording.rs +++ b/sparse_strips/vello_sparse_tests/tests/recording.rs
@@ -33,14 +33,16 @@ ctx.fill_rect(&Rect::new(92.0, 12.0, 96.0, 88.0)); }); - ctx.render_recording(&mut recording1); + ctx.prepare_recording(&mut recording1); + ctx.execute_recording(&recording1); ctx.set_paint(DARK_TURQUOISE); ctx.fill_rect(&Rect::new(12.0, 4.0, 88.0, 8.0)); ctx.set_paint(LIGHT_SALMON); ctx.fill_rect(&Rect::new(12.0, 92.0, 88.0, 96.0)); - ctx.render_recording(&mut recording2); + ctx.prepare_recording(&mut recording2); + ctx.execute_recording(&recording2); } #[vello_test(skip_multithreaded)]
diff --git a/sparse_strips/vello_sparse_tests/tests/renderer.rs b/sparse_strips/vello_sparse_tests/tests/renderer.rs index 97e0ac8..515c0e6 100644 --- a/sparse_strips/vello_sparse_tests/tests/renderer.rs +++ b/sparse_strips/vello_sparse_tests/tests/renderer.rs
@@ -52,7 +52,6 @@ fn record(&mut self, recording: &mut Recording, f: impl FnOnce(&mut Recorder<'_>)); fn prepare_recording(&mut self, recording: &mut Recording); fn execute_recording(&mut self, recording: &Recording); - fn render_recording(&mut self, recording: &mut Recording); } impl Renderer for RenderContext { @@ -173,10 +172,6 @@ fn execute_recording(&mut self, recording: &Recording) { Recordable::execute_recording(self, recording); } - - fn render_recording(&mut self, recording: &mut Recording) { - Recordable::render_recording(self, recording); - } } #[cfg(not(all(target_arch = "wasm32", feature = "webgl")))] @@ -484,10 +479,6 @@ fn execute_recording(&mut self, recording: &Recording) { self.scene.execute_recording(recording); } - - fn render_recording(&mut self, recording: &mut Recording) { - self.scene.render_recording(recording); - } } #[cfg(all(target_arch = "wasm32", feature = "webgl"))] @@ -685,10 +676,6 @@ fn execute_recording(&mut self, recording: &Recording) { self.scene.execute_recording(recording); } - - fn render_recording(&mut self, recording: &mut Recording) { - self.scene.render_recording(recording); - } } impl GlyphRenderer for HybridRenderer {