.
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 {