From b7f21a5078a313f7de89dad40ceb36f8ae5adf41 Mon Sep 17 00:00:00 2001 From: Chad Brokaw Date: Mon, 8 Sep 2025 09:27:47 -0400 Subject: [PATCH 1/2] Try to fix clip optimization --- examples/scenes/src/test_scenes.rs | 113 +++++++++++++++++++++++++- vello_shaders/shader/coarse.wgsl | 12 ++- vello_shaders/shader/fine.wgsl | 16 ++-- vello_shaders/shader/shared/ptcl.wgsl | 7 ++ 4 files changed, 138 insertions(+), 10 deletions(-) diff --git a/examples/scenes/src/test_scenes.rs b/examples/scenes/src/test_scenes.rs index ba16f3f68..bfba324e2 100644 --- a/examples/scenes/src/test_scenes.rs +++ b/examples/scenes/src/test_scenes.rs @@ -56,6 +56,7 @@ macro_rules! scene { } export_scenes!( + clipped_blend(clipped_blend), splash_with_tiger(impls::splash_with_tiger(), "splash_with_tiger", false), funky_paths(funky_paths), stroke_styles(impls::stroke_styles(Affine::IDENTITY), "stroke_styles", false), @@ -100,7 +101,7 @@ mod impls { use rand::Rng; use rand::{SeedableRng, rngs::StdRng}; use vello::kurbo::{ - Affine, BezPath, Cap, Circle, Ellipse, Join, PathEl, Point, Rect, Shape, Stroke, Vec2, + Affine, BezPath, Cap, Circle, Ellipse, Join, PathEl, Point, Rect, Shape, Stroke, Triangle, Vec2 }; use vello::peniko::color::{AlphaColor, Lch, palette}; use vello::peniko::*; @@ -108,6 +109,116 @@ mod impls { const FLOWER_IMAGE: &[u8] = include_bytes!("../../assets/splash-flower.jpg"); + pub(super) fn clipped_blend(scene: &mut Scene, params: &mut SceneParams<'_>) { + params.resolution = Some(Vec2::new(1000., 1200.)); + let transform = Affine::translate((10., 100.)); + params.text.add_run( + &mut *scene, + None, + 32., + Color::WHITE, + transform.then_translate((10., -30.).into()), + None, + &Style::Fill(Fill::EvenOdd), + "No Clip", + ); + + scene.fill( + Fill::EvenOdd, + transform, + palette::css::BLUE, + None, + &Rect::from_origin_size((0., 0.), (400., 400.)), + ); + scene.push_layer( + Mix::Multiply, + 1.0, + transform, + &Triangle::from_coords((200., 0.), (0., 400.), (400., 400.)), + ); + scene.fill( + Fill::EvenOdd, + transform, + palette::css::AQUAMARINE, + None, + &Rect::from_origin_size((0., 0.), (400., 400.)), + ); + scene.pop_layer(); + + let transform = Affine::translate((0., 600.)); + params.text.add_run( + &mut *scene, + None, + 32., + Color::WHITE, + transform.then_translate((10., -30.).into()), + None, + &Style::Fill(Fill::EvenOdd), + "Mix::Normal", + ); + + scene.fill( + Fill::EvenOdd, + transform, + palette::css::BLUE, + None, + &Rect::from_origin_size((0., 0.), (400., 400.)), + ); + let layer_shape = Triangle::from_coords((200., 0.), (0., 400.), (400., 400.)); + scene.push_layer(Mix::Normal, 1.0, transform, &layer_shape); + scene.push_layer(Mix::Multiply, 1.0, transform, &layer_shape); + scene.fill( + Fill::EvenOdd, + transform, + palette::css::AQUAMARINE, + None, + &Rect::from_origin_size((0., 0.), (400., 400.)), + ); + scene.pop_layer(); + scene.pop_layer(); + + let transform = Affine::translate((500., 600.)); + params.text.add_run( + &mut *scene, + None, + 32., + Color::WHITE, + transform.then_translate((10., -30.).into()), + None, + &Style::Fill(Fill::EvenOdd), + "Mix::Clip", + ); + + scene.fill( + Fill::EvenOdd, + transform, + palette::css::BLUE, + None, + &Rect::from_origin_size((0., 0.), (400., 400.)), + ); + let layer_shape = Triangle::from_coords((200., 0.), (0., 400.), (400., 400.)); + scene.push_layer(Mix::Clip, 1.0, transform, &layer_shape); + scene.push_layer(Mix::Clip, 1.0, transform, &Rect::from_origin_size((200.0, 200.0), (200.0, 200.0))); + scene.push_layer(Mix::Multiply, 1.0, transform, &layer_shape); + scene.fill( + Fill::EvenOdd, + transform, + palette::css::AQUAMARINE, + None, + &Rect::from_origin_size((0., 0.), (400., 400.)), + ); + scene.pop_layer(); + scene.pop_layer(); + scene.fill( + Fill::EvenOdd, + transform, + palette::css::RED, + None, + &Rect::from_origin_size((0.0, 100.0), (400.0, 100.0)), + ); + scene.pop_layer(); + } + pub(super) fn emoji(scene: &mut Scene, params: &mut SceneParams<'_>) { let text_size = 120. + 20. * (params.time * 2.).sin() as f32; let s = "🎉🤠✅"; diff --git a/vello_shaders/shader/coarse.wgsl b/vello_shaders/shader/coarse.wgsl index 706032376..5bd536915 100644 --- a/vello_shaders/shader/coarse.wgsl +++ b/vello_shaders/shader/coarse.wgsl @@ -131,9 +131,9 @@ fn write_image(info_offset: u32) { cmd_offset += 2u; } -fn write_begin_clip() { +fn write_begin_clip(flags: u32) { alloc_cmd(1u); - ptcl[cmd_offset] = CMD_BEGIN_CLIP; + ptcl[cmd_offset] = CMD_BEGIN_CLIP | flags; cmd_offset += 1u; } @@ -320,7 +320,6 @@ fn main( let is_clip = (tag & 1u) != 0u; var is_blend = false; if is_clip { - let BLEND_CLIP = (128u << 8u) | 3u; let scene_offset = draw_monoids[drawobj_ix].scene_offset; let dd = config.drawdata_base + scene_offset; let blend = scene[dd]; @@ -413,7 +412,12 @@ fn main( if tile.segment_count_or_ix == 0u && tile.backdrop == 0 { clip_zero_depth = clip_depth + 1u; } else { - write_begin_clip(); + let blend = scene[dd]; + if blend == BLEND_CLIP { + write_begin_clip(NON_ISOLATED_BLENDING_FLAG); + } else { + write_begin_clip(0); + } render_blend_depth += 1u; max_blend_depth = max(max_blend_depth, render_blend_depth); } diff --git a/vello_shaders/shader/fine.wgsl b/vello_shaders/shader/fine.wgsl index 9276871ff..067b72cb6 100644 --- a/vello_shaders/shader/fine.wgsl +++ b/vello_shaders/shader/fine.wgsl @@ -958,10 +958,11 @@ fn main( // main interpretation loop while true { let tag = ptcl[cmd_ix]; - if tag == CMD_END { + let cmd = tag & 0xFFu; + if cmd == CMD_END { break; } - switch tag { + switch cmd { case CMD_FILL: { let fill = read_fill(cmd_ix); #ifdef msaa @@ -987,18 +988,23 @@ fn main( cmd_ix += 2u; } case CMD_BEGIN_CLIP: { + let is_non_isolated = (tag & NON_ISOLATED_BLENDING_FLAG) != 0; + var rgba_mul = vec4(0.0); + if is_non_isolated { + rgba_mul = vec4(1.0); + } if clip_depth < BLEND_STACK_SPLIT { for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) { blend_stack[clip_depth][i] = pack4x8unorm(rgba[i]); - rgba[i] = vec4(0.0); - } + rgba[i] *= rgba_mul; + } } else { let blend_in_scratch = clip_depth - BLEND_STACK_SPLIT; let local_tile_ix = local_id.x * PIXELS_PER_THREAD + local_id.y * TILE_WIDTH; let local_blend_start = blend_offset + blend_in_scratch * TILE_WIDTH * TILE_HEIGHT + local_tile_ix; for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) { blend_spill[local_blend_start + i] = pack4x8unorm(rgba[i]); - rgba[i] = vec4(0.0); + rgba[i] *= rgba_mul; } } clip_depth += 1u; diff --git a/vello_shaders/shader/shared/ptcl.wgsl b/vello_shaders/shader/shared/ptcl.wgsl index d0b41cbed..07d080648 100644 --- a/vello_shaders/shader/shared/ptcl.wgsl +++ b/vello_shaders/shader/shared/ptcl.wgsl @@ -24,6 +24,13 @@ const CMD_END_CLIP = 11u; const CMD_JUMP = 12u; const CMD_BLUR_RECT = 13u; +// Full blend state for clip + normal. +const BLEND_CLIP = (128u << 8u) | 3u; + +// Flag set on CMD_BEGIN_CLIP to allow blending to punch through +// the layer. +const NON_ISOLATED_BLENDING_FLAG = 0x100u; + // The individual PTCL structs are written here, but read/write is by // hand in the relevant shaders From ce709c0df72c8833bfb9e6c68237a38fc0cd4add Mon Sep 17 00:00:00 2001 From: Chad Brokaw Date: Mon, 8 Sep 2025 09:29:34 -0400 Subject: [PATCH 2/2] fmt --- examples/scenes/src/test_scenes.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/scenes/src/test_scenes.rs b/examples/scenes/src/test_scenes.rs index bfba324e2..a8b33a934 100644 --- a/examples/scenes/src/test_scenes.rs +++ b/examples/scenes/src/test_scenes.rs @@ -101,7 +101,8 @@ mod impls { use rand::Rng; use rand::{SeedableRng, rngs::StdRng}; use vello::kurbo::{ - Affine, BezPath, Cap, Circle, Ellipse, Join, PathEl, Point, Rect, Shape, Stroke, Triangle, Vec2 + Affine, BezPath, Cap, Circle, Ellipse, Join, PathEl, Point, Rect, Shape, Stroke, Triangle, + Vec2, }; use vello::peniko::color::{AlphaColor, Lch, palette}; use vello::peniko::*; @@ -198,7 +199,12 @@ mod impls { ); let layer_shape = Triangle::from_coords((200., 0.), (0., 400.), (400., 400.)); scene.push_layer(Mix::Clip, 1.0, transform, &layer_shape); - scene.push_layer(Mix::Clip, 1.0, transform, &Rect::from_origin_size((200.0, 200.0), (200.0, 200.0))); + scene.push_layer( + Mix::Clip, + 1.0, + transform, + &Rect::from_origin_size((200.0, 200.0), (200.0, 200.0)), + ); scene.push_layer(Mix::Multiply, 1.0, transform, &layer_shape); scene.fill( Fill::EvenOdd,