From e399f4792d68c4f621dec974534d861aee45ce45 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 28 Apr 2023 13:49:12 -0700 Subject: [PATCH 01/14] Display error message when WebGPU not enabled Detect the case where creating the WebGPU surface fails, and insert a message explaning the failure into the DOM, rather than panicking. --- examples/with_winit/Cargo.toml | 2 +- examples/with_winit/src/lib.rs | 29 +++++++++++++++++++++++++---- src/util.rs | 18 +++++++++++++----- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/examples/with_winit/Cargo.toml b/examples/with_winit/Cargo.toml index 3303388..24c157e 100644 --- a/examples/with_winit/Cargo.toml +++ b/examples/with_winit/Cargo.toml @@ -45,4 +45,4 @@ android_logger = "0.13.0" console_error_panic_hook = "0.1.7" console_log = "0.2" wasm-bindgen-futures = "0.4.33" -web-sys = "0.3.60" +web-sys = { version = "0.3.60", features = [ "HtmlCollection", "Text" ] } diff --git a/examples/with_winit/src/lib.rs b/examples/with_winit/src/lib.rs index e08add2..3d6422d 100644 --- a/examples/with_winit/src/lib.rs +++ b/examples/with_winit/src/lib.rs @@ -413,7 +413,7 @@ fn run( let size = window.inner_size(); let surface_future = render_cx.create_surface(&window, size.width, size.height); // We need to block here, in case a Suspended event appeared - let surface = pollster::block_on(surface_future); + let surface = pollster::block_on(surface_future).expect("Error creating surface"); render_state = { let render_state = RenderState { window, surface }; renderers.resize_with(render_cx.devices.len(), || None); @@ -453,6 +453,23 @@ enum UserEvent { HotReload, } +#[cfg(target_arch = "wasm32")] +fn display_error_message() -> Option<()> { + let window = web_sys::window()?; + let document = window.document()?; + let elements = document.get_elements_by_tag_name("body"); + let body = elements.item(0)?; + let canvas = body.first_child()?; + // TODO: style the notice at least a little, maybe link? + let text = document.create_text_node( + "WebGPU is not enabled. Make sure your browser is updated to + Chrome M113 or another browser compatible with WebGPU.", + ); + let _ = body.insert_before(&text, Some(&canvas)); + web_sys::console::log_1(&"got body".into()); + Some(()) +} + pub fn main() -> Result<()> { // TODO: initializing both env_logger and console_logger fails on wasm. // Figure out a more principled approach. @@ -496,9 +513,13 @@ pub fn main() -> Result<()> { let surface = render_cx .create_surface(&window, size.width, size.height) .await; - let render_state = RenderState { window, surface }; - // No error handling here; if the event loop has finished, we don't need to send them the surface - run(event_loop, args, scenes, render_cx, render_state); + if let Ok(surface) = surface { + let render_state = RenderState { window, surface }; + // No error handling here; if the event loop has finished, we don't need to send them the surface + run(event_loop, args, scenes, render_cx, render_state); + } else { + _ = display_error_message(); + } }); } } diff --git a/src/util.rs b/src/util.rs index 87e2d35..add0ea2 100644 --- a/src/util.rs +++ b/src/util.rs @@ -50,12 +50,20 @@ impl RenderContext { } /// Creates a new surface for the specified window and dimensions. - pub async fn create_surface(&mut self, window: &W, width: u32, height: u32) -> RenderSurface + pub async fn create_surface( + &mut self, + window: &W, + width: u32, + height: u32, + ) -> Result where W: HasRawWindowHandle + HasRawDisplayHandle, { - let surface = unsafe { self.instance.create_surface(window) }.unwrap(); - let dev_id = self.device(Some(&surface)).await.unwrap(); + let surface = unsafe { self.instance.create_surface(window) }?; + let dev_id = self + .device(Some(&surface)) + .await + .ok_or("Error creating device")?; let device_handle = &self.devices[dev_id]; let capabilities = surface.get_capabilities(&device_handle.adapter); @@ -75,12 +83,12 @@ impl RenderContext { view_formats: vec![], }; surface.configure(&self.devices[dev_id].device, &config); - RenderSurface { + Ok(RenderSurface { surface, config, dev_id, format, - } + }) } /// Resizes the surface to the new dimensions. From 8a083d94735642911f4cf02aeb22a46f59203d71 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 28 Apr 2023 14:25:16 -0700 Subject: [PATCH 02/14] Nicer HTML It's easier with innerHTML rather than constructing DOM by hand. --- examples/with_winit/src/lib.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/examples/with_winit/src/lib.rs b/examples/with_winit/src/lib.rs index 3d6422d..ce95e82 100644 --- a/examples/with_winit/src/lib.rs +++ b/examples/with_winit/src/lib.rs @@ -459,14 +459,18 @@ fn display_error_message() -> Option<()> { let document = window.document()?; let elements = document.get_elements_by_tag_name("body"); let body = elements.item(0)?; - let canvas = body.first_child()?; - // TODO: style the notice at least a little, maybe link? - let text = document.create_text_node( - "WebGPU is not enabled. Make sure your browser is updated to - Chrome M113 or another browser compatible with WebGPU.", + body.set_inner_html( + r#" +

WebGPU + is not enabled. Make sure your browser is updated to + Chrome M113 or + another browser compatible with WebGPU.

"#, ); - let _ = body.insert_before(&text, Some(&canvas)); - web_sys::console::log_1(&"got body".into()); Some(()) } From 152fa008435cc66f5375ee7a794b261babebd31c Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 28 Apr 2023 16:44:37 -0700 Subject: [PATCH 03/14] Basic splash screen Just has key bindings for now. --- examples/scenes/src/test_scenes.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/examples/scenes/src/test_scenes.rs b/examples/scenes/src/test_scenes.rs index 5e4ca8e..deb7864 100644 --- a/examples/scenes/src/test_scenes.rs +++ b/examples/scenes/src/test_scenes.rs @@ -27,6 +27,7 @@ pub fn test_scenes() -> SceneSet { // For WASM below, must be mutable #[allow(unused_mut)] let mut scenes = vec![ + scene!(splash_screen), scene!(funky_paths), scene!(cardioid_and_friends), scene!(animated_text: animated), @@ -627,3 +628,26 @@ fn make_diamond(cx: f64, cy: f64) -> [PathEl; 5] { PathEl::ClosePath, ] } + +fn splash_screen(sb: &mut SceneBuilder, params: &mut SceneParams) { + let strings = [ + "Vello test", + "key bindings:", + " Arrow keys: switch scenes", + " S: toggle stats", + " V: toggle vsync", + " Q, E: rotate", + " Space: reset transform", + ]; + for (i, s) in strings.iter().enumerate() { + let text_size = if i == 0 { 60.0 } else { 40.0 }; + params.text.add( + sb, + None, + text_size, + None, + Affine::translate((100.0, 100.0 + 60.0 * i as f64)), + s, + ); + } +} From 495229bf106136be8d9ac5ba3cc8802cb9352026 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 28 Apr 2023 17:13:37 -0700 Subject: [PATCH 04/14] Combine tiger and splash screen Always show the tiger, and include key bindings. --- examples/scenes/src/test_scenes.rs | 49 +++++++++++++++--------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/examples/scenes/src/test_scenes.rs b/examples/scenes/src/test_scenes.rs index deb7864..53f99ba 100644 --- a/examples/scenes/src/test_scenes.rs +++ b/examples/scenes/src/test_scenes.rs @@ -24,10 +24,15 @@ macro_rules! scene { } pub fn test_scenes() -> SceneSet { - // For WASM below, must be mutable - #[allow(unused_mut)] - let mut scenes = vec![ - scene!(splash_screen), + let splash_scene = ExampleScene { + config: SceneConfig { + animated: false, + name: "splash_with_tiger".to_owned(), + }, + function: Box::new(splash_with_tiger()), + }; + let scenes = vec![ + splash_scene, scene!(funky_paths), scene!(cardioid_and_friends), scene!(animated_text: animated), @@ -37,14 +42,6 @@ pub fn test_scenes() -> SceneSet { scene!(labyrinth), scene!(base_color_test: animated), ]; - #[cfg(any(target_arch = "wasm32", target_os = "android"))] - scenes.push(ExampleScene { - config: SceneConfig { - animated: false, - name: "included_tiger".to_owned(), - }, - function: Box::new(included_tiger()), - }); SceneSet { scenes } } @@ -278,15 +275,6 @@ fn blend_grid(sb: &mut SceneBuilder, _: &mut SceneParams) { } } -#[cfg(any(target_arch = "wasm32", target_os = "android"))] -fn included_tiger() -> impl FnMut(&mut SceneBuilder, &mut SceneParams) { - let contents = include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/../assets/Ghostscript_Tiger.svg" - )); - crate::svg::svg_function_of("Ghostscript Tiger".to_string(), move || contents) -} - // Support functions fn render_cardioid(sb: &mut SceneBuilder) { @@ -632,13 +620,14 @@ fn make_diamond(cx: f64, cy: f64) -> [PathEl; 5] { fn splash_screen(sb: &mut SceneBuilder, params: &mut SceneParams) { let strings = [ "Vello test", - "key bindings:", " Arrow keys: switch scenes", + " Space: reset transform", " S: toggle stats", " V: toggle vsync", " Q, E: rotate", - " Space: reset transform", ]; + // Tweak to make it fit with tiger + let a = Affine::scale(0.12) * Affine::translate((-90.0, -50.0)); for (i, s) in strings.iter().enumerate() { let text_size = if i == 0 { 60.0 } else { 40.0 }; params.text.add( @@ -646,8 +635,20 @@ fn splash_screen(sb: &mut SceneBuilder, params: &mut SceneParams) { None, text_size, None, - Affine::translate((100.0, 100.0 + 60.0 * i as f64)), + a * Affine::translate((100.0, 100.0 + 60.0 * i as f64)), s, ); } } + +fn splash_with_tiger() -> impl FnMut(&mut SceneBuilder, &mut SceneParams) { + let contents = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../assets/Ghostscript_Tiger.svg" + )); + let mut tiger = crate::svg::svg_function_of("Ghostscript Tiger".to_string(), move || contents); + move |sb, params| { + tiger(sb, params); + splash_screen(sb, params); + } +} From f4a2fc616b2fcced1370d95d3a984c464177b944 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 28 Apr 2023 18:19:02 -0700 Subject: [PATCH 05/14] Mmark example This commit ports the mmark example from the mmark branch, and also makes the complexity adjustable through up/down arrow keys. --- examples/scenes/Cargo.toml | 1 + examples/scenes/src/lib.rs | 14 +++++++++++++- examples/scenes/src/test_scenes.rs | 8 ++++++++ examples/with_winit/src/lib.rs | 6 +++++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/examples/scenes/Cargo.toml b/examples/scenes/Cargo.toml index c68ffa3..fd5e641 100644 --- a/examples/scenes/Cargo.toml +++ b/examples/scenes/Cargo.toml @@ -16,6 +16,7 @@ vello_svg = { path = "../../integrations/vello_svg" } anyhow = { workspace = true } clap = { workspace = true, features = ["derive"] } image = "0.24.5" +rand = "0.8.5" instant = { workspace = true } # Used for the `download` command diff --git a/examples/scenes/src/lib.rs b/examples/scenes/src/lib.rs index c85573c..7fee5cd 100644 --- a/examples/scenes/src/lib.rs +++ b/examples/scenes/src/lib.rs @@ -1,5 +1,6 @@ pub mod download; mod images; +mod mmark; mod simple_text; mod svg; mod test_scenes; @@ -25,6 +26,7 @@ pub struct SceneParams<'a> { pub images: &'a mut ImageCache, pub resolution: Option, pub base_color: Option, + pub complexity: usize, } pub struct SceneConfig { @@ -34,10 +36,20 @@ pub struct SceneConfig { } pub struct ExampleScene { - pub function: Box, + pub function: Box, pub config: SceneConfig, } +pub trait TestScene { + fn render(&mut self, sb: &mut SceneBuilder, params: &mut SceneParams); +} + +impl TestScene for F { + fn render(&mut self, sb: &mut SceneBuilder, params: &mut SceneParams) { + self(sb, params); + } +} + pub struct SceneSet { pub scenes: Vec, } diff --git a/examples/scenes/src/test_scenes.rs b/examples/scenes/src/test_scenes.rs index 53f99ba..4fbabba 100644 --- a/examples/scenes/src/test_scenes.rs +++ b/examples/scenes/src/test_scenes.rs @@ -31,8 +31,16 @@ pub fn test_scenes() -> SceneSet { }, function: Box::new(splash_with_tiger()), }; + let mmark_scene = ExampleScene { + config: SceneConfig { + animated: false, + name: "mmark".to_owned(), + }, + function: Box::new(crate::mmark::MMark::new(80_000)), + }; let scenes = vec![ splash_scene, + mmark_scene, scene!(funky_paths), scene!(cardioid_and_friends), scene!(animated_text: animated), diff --git a/examples/with_winit/src/lib.rs b/examples/with_winit/src/lib.rs index ce95e82..5b897b5 100644 --- a/examples/with_winit/src/lib.rs +++ b/examples/with_winit/src/lib.rs @@ -113,6 +113,7 @@ fn run( let mut prior_position: Option = None; // We allow looping left and right through the scenes, so use a signed index let mut scene_ix: i32 = 0; + let mut complexity: usize = 0; if let Some(set_scene) = args.scene { scene_ix = set_scene; } @@ -134,6 +135,8 @@ fn run( match input.virtual_keycode { Some(VirtualKeyCode::Left) => scene_ix = scene_ix.saturating_sub(1), Some(VirtualKeyCode::Right) => scene_ix = scene_ix.saturating_add(1), + Some(VirtualKeyCode::Up) => complexity += 1, + Some(VirtualKeyCode::Down) => complexity = complexity.saturating_sub(1), Some(key @ VirtualKeyCode::Q) | Some(key @ VirtualKeyCode::E) => { if let Some(prior_position) = prior_position { let is_clockwise = key == VirtualKeyCode::E; @@ -295,8 +298,9 @@ fn run( resolution: None, base_color: None, interactive: true, + complexity, }; - (example_scene.function)(&mut builder, &mut scene_params); + example_scene.function.render(&mut builder, &mut scene_params); // If the user specifies a base color in the CLI we use that. Otherwise we use any // color specified by the scene. The default is black. From 6fc1ed8e13dd5e2442be35320c4ab3ba90f64257 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Sat, 29 Apr 2023 08:16:28 -0700 Subject: [PATCH 06/14] Cargo fmt --- examples/with_winit/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/with_winit/src/lib.rs b/examples/with_winit/src/lib.rs index 5b897b5..985f42a 100644 --- a/examples/with_winit/src/lib.rs +++ b/examples/with_winit/src/lib.rs @@ -300,7 +300,9 @@ fn run( interactive: true, complexity, }; - example_scene.function.render(&mut builder, &mut scene_params); + example_scene + .function + .render(&mut builder, &mut scene_params); // If the user specifies a base color in the CLI we use that. Otherwise we use any // color specified by the scene. The default is black. From a20c9e1592674ce9c6f6d867ad054d0de37448a0 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Sat, 29 Apr 2023 08:18:04 -0700 Subject: [PATCH 07/14] Oops, forgot to commit mmark.rs --- examples/scenes/src/mmark.rs | 191 +++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 examples/scenes/src/mmark.rs diff --git a/examples/scenes/src/mmark.rs b/examples/scenes/src/mmark.rs new file mode 100644 index 0000000..dc5ce32 --- /dev/null +++ b/examples/scenes/src/mmark.rs @@ -0,0 +1,191 @@ +//! A benchmark based on MotionMark 1.2's path benchmark. + +use rand::{seq::SliceRandom, Rng}; +use vello::peniko::Color; +use vello::{ + kurbo::{Affine, BezPath, CubicBez, Line, ParamCurve, PathSeg, Point, QuadBez}, + peniko::Stroke, + SceneBuilder, +}; + +use crate::{SceneParams, TestScene}; + +const WIDTH: usize = 1600; +const HEIGHT: usize = 900; + +const GRID_WIDTH: i64 = 80; +const GRID_HEIGHT: i64 = 40; + +pub struct MMark { + elements: Vec, +} + +struct Element { + seg: PathSeg, + color: Color, + width: f64, + is_split: bool, + grid_point: GridPoint, +} + +#[derive(Clone, Copy)] +struct GridPoint((i64, i64)); + +impl MMark { + pub fn new(n: usize) -> MMark { + let mut result = MMark { elements: vec![] }; + result.resize(n); + result + } + + fn resize(&mut self, n: usize) { + let old_n = self.elements.len(); + if n < old_n { + self.elements.truncate(n) + } else if n > old_n { + let mut last = self + .elements + .last() + .map(|e| e.grid_point) + .unwrap_or(GridPoint((GRID_WIDTH / 2, GRID_HEIGHT / 2))); + self.elements.extend((old_n..n).map(|_| { + let element = Element::new_rand(last); + last = element.grid_point; + element + })); + } + } +} + +impl TestScene for MMark { + fn render(&mut self, sb: &mut SceneBuilder, params: &mut SceneParams) { + let c = params.complexity; + let n = if c < 10 { + (c + 1) * 1000 + } else { + ((c - 8) * 10000).min(120_000) + }; + self.resize(n); + let mut rng = rand::thread_rng(); + let mut path = BezPath::new(); + let len = self.elements.len(); + for (i, element) in self.elements.iter_mut().enumerate() { + if path.is_empty() { + path.move_to(element.seg.start()); + } + match element.seg { + PathSeg::Line(l) => path.line_to(l.p1), + PathSeg::Quad(q) => path.quad_to(q.p1, q.p2), + PathSeg::Cubic(c) => path.curve_to(c.p1, c.p2, c.p3), + } + if element.is_split || i == len { + // This gets color and width from the last element, original + // gets it from the first, but this should not matter. + sb.stroke( + &Stroke::new(element.width as f32), + Affine::IDENTITY, + element.color, + None, + &path, + ); + path.truncate(0); // Should have clear method, to avoid allocations. + } + if rng.gen::() > 0.995 { + element.is_split ^= true; + } + } + let label = format!("mmark test: {} path elements (up/down to adjust)", n); + params.text.add( + sb, + None, + 40.0, + None, + Affine::translate((100.0, 1100.0)), + &label, + ); + } +} + +const COLORS: &[Color] = &[ + Color::rgb8(0x10, 0x10, 0x10), + Color::rgb8(0x80, 0x80, 0x80), + Color::rgb8(0xc0, 0xc0, 0xc0), + Color::rgb8(0x10, 0x10, 0x10), + Color::rgb8(0x80, 0x80, 0x80), + Color::rgb8(0xc0, 0xc0, 0xc0), + Color::rgb8(0xe0, 0x10, 0x40), +]; + +impl Element { + fn new_rand(last: GridPoint) -> Element { + let mut rng = rand::thread_rng(); + let seg_type = rng.gen_range(0..4); + let next = GridPoint::random_point(last); + let (grid_point, seg) = if seg_type < 2 { + ( + next, + PathSeg::Line(Line::new(last.coordinate(), next.coordinate())), + ) + } else if seg_type < 3 { + let p2 = GridPoint::random_point(next); + ( + p2, + PathSeg::Quad(QuadBez::new( + last.coordinate(), + next.coordinate(), + p2.coordinate(), + )), + ) + } else { + let p2 = GridPoint::random_point(next); + let p3 = GridPoint::random_point(next); + ( + p3, + PathSeg::Cubic(CubicBez::new( + last.coordinate(), + next.coordinate(), + p2.coordinate(), + p3.coordinate(), + )), + ) + }; + let color = COLORS.choose(&mut rng).unwrap().clone(); + let width = rng.gen::().powi(5) * 20.0 + 1.0; + let is_split = rng.gen(); + Element { + seg, + color, + width, + is_split, + grid_point, + } + } +} + +const OFFSETS: &[(i64, i64)] = &[(-4, 0), (2, 0), (1, -2), (1, 2)]; + +impl GridPoint { + fn random_point(last: GridPoint) -> GridPoint { + let mut rng = rand::thread_rng(); + + let offset = OFFSETS.choose(&mut rng).unwrap(); + let mut x = last.0 .0 + offset.0; + if x < 0 || x > GRID_WIDTH { + x -= offset.0 * 2; + } + let mut y = last.0 .1 + offset.1; + if y < 0 || y > GRID_HEIGHT { + y -= offset.1 * 2; + } + GridPoint((x, y)) + } + + fn coordinate(&self) -> Point { + let scale_x = WIDTH as f64 / ((GRID_WIDTH + 1) as f64); + let scale_y = HEIGHT as f64 / ((GRID_HEIGHT + 1) as f64); + Point::new( + (self.0 .0 as f64 + 0.5) * scale_x, + 100.0 + (self.0 .1 as f64 + 0.5) * scale_y, + ) + } +} From 9c7e08423965d2904f12e361fb69721dd180c001 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Sat, 29 Apr 2023 08:19:01 -0700 Subject: [PATCH 08/14] Focus canvas on setup --- examples/with_winit/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/with_winit/src/lib.rs b/examples/with_winit/src/lib.rs index 985f42a..16d48f9 100644 --- a/examples/with_winit/src/lib.rs +++ b/examples/with_winit/src/lib.rs @@ -516,8 +516,9 @@ pub fn main() -> Result<()> { web_sys::window() .and_then(|win| win.document()) .and_then(|doc| doc.body()) - .and_then(|body| body.append_child(&web_sys::Element::from(canvas)).ok()) + .and_then(|body| body.append_child(&web_sys::Element::from(canvas.clone())).ok()) .expect("couldn't append canvas to document body"); + _ = web_sys::HtmlElement::from(canvas).focus(); wasm_bindgen_futures::spawn_local(async move { let size = window.inner_size(); let surface = render_cx From e7c7f105245acd7a2bc7bba161182ab21eba3209 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Sat, 29 Apr 2023 08:19:28 -0700 Subject: [PATCH 09/14] Cargo fmt --- examples/with_winit/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/with_winit/src/lib.rs b/examples/with_winit/src/lib.rs index 16d48f9..d27ae6a 100644 --- a/examples/with_winit/src/lib.rs +++ b/examples/with_winit/src/lib.rs @@ -516,7 +516,10 @@ pub fn main() -> Result<()> { web_sys::window() .and_then(|win| win.document()) .and_then(|doc| doc.body()) - .and_then(|body| body.append_child(&web_sys::Element::from(canvas.clone())).ok()) + .and_then(|body| { + body.append_child(&web_sys::Element::from(canvas.clone())) + .ok() + }) .expect("couldn't append canvas to document body"); _ = web_sys::HtmlElement::from(canvas).focus(); wasm_bindgen_futures::spawn_local(async move { From 1b3938e54f52e58a2b3c540d13805e8ff9804d0c Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Sat, 29 Apr 2023 08:22:49 -0700 Subject: [PATCH 10/14] Clean up casting Get rid of unneeded clone and make syntax nicer. --- examples/with_winit/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/with_winit/src/lib.rs b/examples/with_winit/src/lib.rs index d27ae6a..44d197b 100644 --- a/examples/with_winit/src/lib.rs +++ b/examples/with_winit/src/lib.rs @@ -516,10 +516,7 @@ pub fn main() -> Result<()> { web_sys::window() .and_then(|win| win.document()) .and_then(|doc| doc.body()) - .and_then(|body| { - body.append_child(&web_sys::Element::from(canvas.clone())) - .ok() - }) + .and_then(|body| body.append_child(canvas.as_ref()).ok()) .expect("couldn't append canvas to document body"); _ = web_sys::HtmlElement::from(canvas).focus(); wasm_bindgen_futures::spawn_local(async move { From 8f413c5b44fe0df8d2554c66a7801ccc0dc59e10 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Thu, 18 May 2023 11:16:10 -0700 Subject: [PATCH 11/14] Fix headless example --- examples/headless/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/headless/src/main.rs b/examples/headless/src/main.rs index 0fa9c7e..ac40765 100644 --- a/examples/headless/src/main.rs +++ b/examples/headless/src/main.rs @@ -104,8 +104,9 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> { resolution: None, base_color: None, interactive: false, + complexity: 0, }; - (example_scene.function)(&mut builder, &mut scene_params); + example_scene.function.render(&mut builder, &mut scene_params); let mut transform = Affine::IDENTITY; let (width, height) = if let Some(resolution) = scene_params.resolution { let ratio = resolution.x / resolution.y; From 8158e778590d5795b7b5296d8168778399c4a0e8 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Thu, 18 May 2023 11:18:22 -0700 Subject: [PATCH 12/14] Rustfmt I should set up git pre-push hooks. Also, I am surprised this needed a fmt, and would not add all the extra vertical space if it were up to me, but the reason we use default rustfmt is to avoid spending mental energy on such details. --- examples/headless/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/headless/src/main.rs b/examples/headless/src/main.rs index ac40765..43d33aa 100644 --- a/examples/headless/src/main.rs +++ b/examples/headless/src/main.rs @@ -106,7 +106,9 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> { interactive: false, complexity: 0, }; - example_scene.function.render(&mut builder, &mut scene_params); + example_scene + .function + .render(&mut builder, &mut scene_params); let mut transform = Affine::IDENTITY; let (width, height) = if let Some(resolution) = scene_params.resolution { let ratio = resolution.x / resolution.y; From 6ed6e4a940776fcb319469920495a65a2cc9887e Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Wed, 31 May 2023 17:44:30 -0700 Subject: [PATCH 13/14] Address review feedback --- examples/scenes/src/mmark.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/scenes/src/mmark.rs b/examples/scenes/src/mmark.rs index 98be5fa..c7e439a 100644 --- a/examples/scenes/src/mmark.rs +++ b/examples/scenes/src/mmark.rs @@ -1,4 +1,10 @@ //! A benchmark based on MotionMark 1.2's path benchmark. +//! This is roughly comparable to: +//! +//! https://browserbench.org/MotionMark1.2/developer.html?warmup-length=2000&warmup-frame-count=30&first-frame-minimum-length=0&test-interval=15&display=minimal&tiles=big&controller=adaptive&frame-rate=50&time-measurement=performance&suite-name=MotionMark&test-name=Paths&complexity=1 +//! +//! However, at this point it cannot be directly compared, as we don't accurately +//! implement the stroke style parameters, and it has not been carefully validated. use std::cmp::Ordering; @@ -31,7 +37,7 @@ struct Element { } #[derive(Clone, Copy)] -struct GridPoint((i64, i64)); +struct GridPoint(i64, i64); impl MMark { pub fn new(n: usize) -> MMark { @@ -49,7 +55,7 @@ impl MMark { .elements .last() .map(|e| e.grid_point) - .unwrap_or(GridPoint((GRID_WIDTH / 2, GRID_HEIGHT / 2))); + .unwrap_or(GridPoint(GRID_WIDTH / 2, GRID_HEIGHT / 2)); self.elements.extend((old_n..n).map(|_| { let element = Element::new_rand(last); last = element.grid_point; @@ -173,23 +179,23 @@ impl GridPoint { let mut rng = rand::thread_rng(); let offset = OFFSETS.choose(&mut rng).unwrap(); - let mut x = last.0 .0 + offset.0; + let mut x = last.0 + offset.0; if !(0..=GRID_WIDTH).contains(&x) { x -= offset.0 * 2; } - let mut y = last.0 .1 + offset.1; + let mut y = last.1 + offset.1; if !(0..=GRID_HEIGHT).contains(&y) { y -= offset.1 * 2; } - GridPoint((x, y)) + GridPoint(x, y) } fn coordinate(&self) -> Point { let scale_x = WIDTH as f64 / ((GRID_WIDTH + 1) as f64); let scale_y = HEIGHT as f64 / ((GRID_HEIGHT + 1) as f64); Point::new( - (self.0 .0 as f64 + 0.5) * scale_x, - 100.0 + (self.0 .1 as f64 + 0.5) * scale_y, + (self.0 as f64 + 0.5) * scale_x, + 100.0 + (self.1 as f64 + 0.5) * scale_y, ) } } From 4fcc34894048555f13c56b6adc2076c09705ab34 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Thu, 1 Jun 2023 06:59:53 -0700 Subject: [PATCH 14/14] Change to caniuse for webgpu --- examples/with_winit/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/with_winit/src/lib.rs b/examples/with_winit/src/lib.rs index 9ae4576..8a5dacc 100644 --- a/examples/with_winit/src/lib.rs +++ b/examples/with_winit/src/lib.rs @@ -480,7 +480,7 @@ fn display_error_message() -> Option<()> { font-family: sans-serif; } -

WebGPU +

WebGPU is not enabled. Make sure your browser is updated to Chrome M113 or another browser compatible with WebGPU.

"#,