From 3bbf108df5042a845ad7ebabadbf33bdcdf95e70 Mon Sep 17 00:00:00 2001 From: Arman Uguray Date: Thu, 2 Mar 2023 14:29:06 -0800 Subject: [PATCH] Renamed clear_color to base_color; addressed review comments --- examples/headless/src/main.rs | 15 +++++--- examples/scenes/src/lib.rs | 21 +++++++++- examples/with_bevy/src/main.rs | 2 +- examples/with_winit/src/main.rs | 68 +++++++-------------------------- shader/fine.wgsl | 2 +- shader/shared/config.wgsl | 2 +- src/encoding/packed.rs | 7 ++-- src/lib.rs | 4 +- src/render.rs | 6 ++- 9 files changed, 54 insertions(+), 73 deletions(-) diff --git a/examples/headless/src/main.rs b/examples/headless/src/main.rs index 0a6ea17..5664b32 100644 --- a/examples/headless/src/main.rs +++ b/examples/headless/src/main.rs @@ -92,15 +92,15 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> { let mut builder = SceneBuilder::for_fragment(&mut fragment); let example_scene = &mut scenes.scenes[index]; let mut text = SimpleText::new(); - let mut params = SceneParams { + let mut scene_params = SceneParams { time: args.time.unwrap_or(0.), text: &mut text, resolution: None, }; - (example_scene.function)(&mut builder, &mut params); + (example_scene.function)(&mut builder, &mut scene_params); builder.finish(); let mut transform = Affine::IDENTITY; - let (width, height) = if let Some(resolution) = params.resolution { + let (width, height) = if let Some(resolution) = scene_params.resolution { let ratio = resolution.x / resolution.y; let (new_width, new_height) = match (args.x_resolution, args.y_resolution) { (None, None) => (resolution.x.ceil() as u32, resolution.y.ceil() as u32), @@ -126,8 +126,11 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> { (Some(x), Some(y)) => (x.try_into()?, y.try_into()?), } }; - let params = vello::RenderParams { - clear_color: vello::peniko::Color::BLACK, + let render_params = vello::RenderParams { + base_color: args + .args + .get_base_color()? + .unwrap_or(vello::peniko::Color::BLACK), width, height, }; @@ -152,7 +155,7 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> { }); let view = target.create_view(&wgpu::TextureViewDescriptor::default()); renderer - .render_to_texture(&device, &queue, &scene, &view, ¶ms) + .render_to_texture(&device, &queue, &scene, &view, &render_params) .or_else(|_| bail!("Got non-Send/Sync error from rendering"))?; // (width * 4).next_multiple_of(256) let padded_byte_width = { diff --git a/examples/scenes/src/lib.rs b/examples/scenes/src/lib.rs index b23e54a..2aed412 100644 --- a/examples/scenes/src/lib.rs +++ b/examples/scenes/src/lib.rs @@ -5,7 +5,7 @@ mod svg; mod test_scenes; use std::path::PathBuf; -use anyhow::Result; +use anyhow::{anyhow, Result}; use clap::{Args, Subcommand}; use download::Download; pub use simple_text::SimpleText; @@ -13,7 +13,7 @@ pub use simple_text::SimpleText; pub use svg::{default_scene, scene_from_files}; pub use test_scenes::test_scenes; -use vello::{kurbo::Vec2, SceneBuilder}; +use vello::{kurbo::Vec2, peniko::Color, SceneBuilder}; pub struct SceneParams<'a> { pub time: f64, @@ -46,6 +46,12 @@ pub struct Arguments { #[arg(help_heading = "Scene Selection", global(false))] /// The svg files paths to render svgs: Option>, + #[arg(help_heading = "Render Parameters")] + #[arg(long, global(false))] + /// The base color applied as the blend background to the rasterizer. + /// Format is CSS style hexidecimal (#RGB, #RGBA, #RRGGBB, #RRGGBBAA) or + /// an SVG color name such as "aliceblue" + base_color: Option, #[clap(subcommand)] command: Option, } @@ -79,6 +85,17 @@ impl Arguments { .map(Some) } } + + pub fn get_base_color(&self) -> Result> { + self.base_color.as_ref().map_or_else( + || Ok(None), + |s| { + Color::parse(&s) + .ok_or_else(|| anyhow!("malformed color: {}", s)) + .map(Some) + }, + ) + } } impl Command { diff --git a/examples/with_bevy/src/main.rs b/examples/with_bevy/src/main.rs index 690d980..f98ce73 100644 --- a/examples/with_bevy/src/main.rs +++ b/examples/with_bevy/src/main.rs @@ -47,7 +47,7 @@ fn render_scenes( for scene in &mut scenes { let gpu_image = gpu_images.get(&scene.1).unwrap(); let params = vello::RenderParams { - clear_color: vello::peniko::Color::AQUAMARINE, + base_color: vello::peniko::Color::AQUAMARINE, width: gpu_image.size.x as u32, height: gpu_image.size.y as u32, }; diff --git a/examples/with_winit/src/main.rs b/examples/with_winit/src/main.rs index 6d2aa5c..8aee854 100644 --- a/examples/with_winit/src/main.rs +++ b/examples/with_winit/src/main.rs @@ -17,10 +17,7 @@ use std::time::Instant; use anyhow::Result; -use clap::{ - builder::{PossibleValuesParser, TypedValueParser as _}, - CommandFactory, Parser, -}; +use clap::{CommandFactory, Parser}; use scenes::{SceneParams, SceneSet, SimpleText}; use vello::SceneFragment; use vello::{ @@ -53,52 +50,18 @@ struct Args { /// Switch between scenes with left and right arrow keys #[arg(long)] scene: Option, - #[arg( - long, - default_value_t = ClearColor::Black, - value_parser = PossibleValuesParser::new(["black", "white", "aquamarine", "crimson"]) - .map(|s| s.parse::().unwrap()) - )] - clear_color: ClearColor, + /// The base color used as the #[command(flatten)] args: scenes::Arguments, } -#[derive(Debug, Clone)] -enum ClearColor { - Black, - White, - Crimson, - Aquamarine, -} - -impl std::fmt::Display for ClearColor { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let s = match self { - Self::Black => "black", - Self::White => "white", - Self::Crimson => "crimson", - Self::Aquamarine => "aquamarine", - }; - s.fmt(f) - } -} - -impl std::str::FromStr for ClearColor { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "black" => Ok(Self::Black), - "white" => Ok(Self::White), - "crimson" => Ok(Self::Crimson), - "aquamarine" => Ok(Self::Aquamarine), - _ => Err(format!("invalid color: {s}")), - } - } -} - -async fn run(event_loop: EventLoop, window: Window, args: Args, mut scenes: SceneSet) { +async fn run( + event_loop: EventLoop, + window: Window, + args: Args, + base_color: Color, + mut scenes: SceneSet, +) { use winit::{event::*, event_loop::ControlFlow}; let mut render_cx = RenderContext::new().unwrap(); let size = window.inner_size(); @@ -120,12 +83,6 @@ async fn run(event_loop: EventLoop, window: Window, args: Args, mut s if let Some(set_scene) = args.scene { scene_ix = set_scene; } - let clear_color = match args.clear_color { - ClearColor::Black => Color::BLACK, - ClearColor::White => Color::WHITE, - ClearColor::Crimson => Color::CRIMSON, - ClearColor::Aquamarine => Color::AQUAMARINE, - }; let mut prev_scene_ix = scene_ix - 1; event_loop.run(move |event, _, control_flow| match event { Event::WindowEvent { @@ -207,7 +164,7 @@ async fn run(event_loop: EventLoop, window: Window, args: Args, mut s let device_handle = &render_cx.devices[surface.dev_id]; let render_params = vello::RenderParams { - clear_color, + base_color, width, height, }; @@ -300,6 +257,7 @@ fn main() -> Result<()> { env_logger::init(); let args = Args::parse(); let scenes = args.args.select_scene_set(|| Args::command())?; + let base_color = args.args.get_base_color()?.unwrap_or(Color::BLACK); if let Some(scenes) = scenes { #[cfg(not(target_arch = "wasm32"))] { @@ -317,7 +275,7 @@ fn main() -> Result<()> { .with_title("Vello demo") .build(&event_loop) .unwrap(); - pollster::block_on(run(event_loop, window, args, scenes)); + pollster::block_on(run(event_loop, window, args, base_color, scenes)); } #[cfg(target_arch = "wasm32")] { @@ -337,7 +295,7 @@ fn main() -> Result<()> { .and_then(|doc| doc.body()) .and_then(|body| body.append_child(&web_sys::Element::from(canvas)).ok()) .expect("couldn't append canvas to document body"); - wasm_bindgen_futures::spawn_local(run(event_loop, window, args, scenes)); + wasm_bindgen_futures::spawn_local(run(event_loop, window, args, base_color, scenes)); } } Ok(()) diff --git a/shader/fine.wgsl b/shader/fine.wgsl index bfcfb66..6851bae 100644 --- a/shader/fine.wgsl +++ b/shader/fine.wgsl @@ -188,7 +188,7 @@ fn main( #ifdef full var rgba: array, PIXELS_PER_THREAD>; for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) { - rgba[i] = unpack4x8unorm(config.clear_color).wzyx; + rgba[i] = unpack4x8unorm(config.base_color).wzyx; } var blend_stack: array, BLEND_STACK_SPLIT>; var clip_depth = 0u; diff --git a/shader/shared/config.wgsl b/shader/shared/config.wgsl index af5ff3d..7ab9ec6 100644 --- a/shader/shared/config.wgsl +++ b/shader/shared/config.wgsl @@ -10,7 +10,7 @@ struct Config { // The initial color applied to the pixels in a tile during the fine stage. // This is only used in the full pipeline. The format is packed RGBA8 in MSB // order. - clear_color: u32, + base_color: u32, n_drawobj: u32, n_path: u32, diff --git a/src/encoding/packed.rs b/src/encoding/packed.rs index 2ee7c67..4455f79 100644 --- a/src/encoding/packed.rs +++ b/src/encoding/packed.rs @@ -48,7 +48,8 @@ pub struct Layout { pub linewidth_base: u32, } -/// Scene configuration. +/// Scene configuration. This data structure must be kept in sync with the definition in +/// shaders/shared/config.wgsl. #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] #[repr(C)] pub struct Config { @@ -60,8 +61,8 @@ pub struct Config { pub target_width: u32, /// Height of the target in pixels. pub target_height: u32, - /// The initial background color applied to the target - pub clear_color: u32, + /// The base background color applied to the target before any blends. + pub base_color: u32, /// Layout of packed scene data. pub layout: Layout, /// Size of binning buffer allocation (in u32s). diff --git a/src/lib.rs b/src/lib.rs index 5cb4b1a..f4aabca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,7 @@ pub struct Renderer { pub struct RenderParams { /// The background color applied to the target. This value is only applicable to the full /// pipeline. - pub clear_color: peniko::Color, + pub base_color: peniko::Color, /// Dimensions of the rasterization target pub width: u32, @@ -64,7 +64,7 @@ pub struct RenderParams { } impl Renderer { - /// Creates a new renderer for the specified device with default options. + /// Creates a new renderer for the specified device. pub fn new(device: &Device) -> Result { let mut engine = Engine::new(); let shaders = shaders::full_shaders(device, &mut engine)?; diff --git a/src/render.rs b/src/render.rs index e25be78..d5d29a6 100644 --- a/src/render.rs +++ b/src/render.rs @@ -55,6 +55,8 @@ const BIN_HEADER_SIZE: u64 = 8; const TILE_SIZE: u64 = 8; const SEGMENT_SIZE: u64 = 24; +// This data structure must be kept in sync with encoding::Config and the definition in +// shaders/shared/config.wgsl. #[repr(C)] #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] struct Config { @@ -62,7 +64,7 @@ struct Config { height_in_tiles: u32, target_width: u32, target_height: u32, - clear_color: u32, + base_color: u32, n_drawobj: u32, n_path: u32, n_clip: u32, @@ -264,7 +266,7 @@ impl Render { height_in_tiles: new_height / 16, target_width: params.width, target_height: params.height, - clear_color: params.clear_color.to_premul_u32(), + base_color: params.base_color.to_premul_u32(), binning_size: self.binning_info_size - info_size, tiles_size: self.tiles_size, segments_size: self.segments_size,