vello_hybrid: Allow nested blending even if scene constraint is set to default blending only
diff --git a/sparse_strips/vello_dev_macros/src/test.rs b/sparse_strips/vello_dev_macros/src/test.rs index 2e6f28a..af8f93a 100644 --- a/sparse_strips/vello_dev_macros/src/test.rs +++ b/sparse_strips/vello_dev_macros/src/test.rs
@@ -205,7 +205,10 @@ // Tests that use non-default blend modes will panic with `default_blending_only`. skip_hybrid_constrained |= skip_hybrid - || input_fn_name_str.contains("mix") + || (input_fn_name_str.contains("mix") + // This test is supposed to specifically show even with scene constraints enabled, + // blending will work fine as long as it doesn't happen on the root layer. + && !input_fn_name_str.contains("mix_in_inner_layer")) || input_fn_name_str.contains("compose") || (input_fn_name_str.contains("blend") && !input_fn_name_str.contains("default_blending_only"))
diff --git a/sparse_strips/vello_hybrid/src/scene.rs b/sparse_strips/vello_hybrid/src/scene.rs index 48bf767..c371125 100644 --- a/sparse_strips/vello_hybrid/src/scene.rs +++ b/sparse_strips/vello_hybrid/src/scene.rs
@@ -135,7 +135,7 @@ /// /// # Panics /// - /// The renderer will panic if a non-default blend mode is used. + /// The renderer will panic if a non-default blend mode is used in the root layer. #[inline(always)] pub fn default_blending_only(self) -> Self { Self(self.0 | Self::DEFAULT_BLENDING_ONLY) @@ -147,8 +147,8 @@ } #[inline(always)] - fn assert_blend_mode(&self, blend_mode: BlendMode) { - if self.use_default_blending_only() { + fn assert_blend_mode(&self, blend_mode: BlendMode, nested_layer: bool) { + if self.use_default_blending_only() && !nested_layer { assert!( blend_mode == DEFAULT_BLEND_MODE, "scene constrained to default blending" @@ -614,7 +614,8 @@ filter: Option<Filter>, ) { let blend_mode_val = blend_mode.unwrap_or(DEFAULT_BLEND_MODE); - self.constraints.assert_blend_mode(blend_mode_val); + self.constraints + .assert_blend_mode(blend_mode_val, self.wide.has_layers()); self.layer_id_next += 1; @@ -716,7 +717,8 @@ /// Set the blend mode for subsequent rendering operations. pub fn set_blend_mode(&mut self, blend_mode: BlendMode) { - self.constraints.assert_blend_mode(blend_mode); + self.constraints + .assert_blend_mode(blend_mode, self.wide.has_layers()); self.render_state.blend_mode = blend_mode; } @@ -1475,6 +1477,22 @@ } #[test] + #[should_panic(expected = "scene constrained to default blending")] + fn default_blending_only_rejects_root_blend_layer() { + let mut scene = default_blending_only(); + scene.push_blend_layer(BlendMode::new(Mix::Multiply, Compose::SrcOver)); + } + + #[test] + fn default_blending_only_allows_nested_blend_layer() { + let mut scene = default_blending_only(); + scene.push_layer(None, None, Some(0.5), None, None); + scene.push_blend_layer(BlendMode::new(Mix::Multiply, Compose::SrcOver)); + + assert!(scene.wide.has_layers()); + } + + #[test] fn reset_restores_fast_only() { let mut scene = unconstrained(); scene.set_paint(Color::from_rgba8(255, 0, 0, 255));
diff --git a/sparse_strips/vello_sparse_tests/snapshots/mix_in_inner_layer.png b/sparse_strips/vello_sparse_tests/snapshots/mix_in_inner_layer.png new file mode 100644 index 0000000..50b9197 --- /dev/null +++ b/sparse_strips/vello_sparse_tests/snapshots/mix_in_inner_layer.png
@@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eeb13181a3fe6d96586fe8465cc3233a96ecf2ddfedbfcaf3b2a3c151131d512 +size 209
diff --git a/sparse_strips/vello_sparse_tests/tests/mix.rs b/sparse_strips/vello_sparse_tests/tests/mix.rs index 7efdb03..5c674d9 100644 --- a/sparse_strips/vello_sparse_tests/tests/mix.rs +++ b/sparse_strips/vello_sparse_tests/tests/mix.rs
@@ -297,3 +297,18 @@ fn mix_non_isolated_color_dodge(ctx: &mut impl Renderer) { mix_non_isolated(ctx, Mix::ColorDodge); } + +#[vello_test] +fn mix_in_inner_layer(ctx: &mut impl Renderer) { + ctx.push_layer(None, None, None, None, None); + + ctx.set_paint(BLUE.with_alpha(0.5)); + ctx.fill_rect(&Rect::new(10.5, 10.5, 70.5, 70.5)); + + ctx.push_blend_layer(BlendMode::new(Mix::Multiply, Compose::SrcOver)); + ctx.set_paint(LIME.with_alpha(0.5)); + ctx.fill_rect(&Rect::new(30.5, 30.5, 90.5, 90.5)); + ctx.pop_layer(); + + ctx.pop_layer(); +}