diff --git a/render-wasm/Cargo.toml b/render-wasm/Cargo.toml index 62543fd943..72570a1274 100644 --- a/render-wasm/Cargo.toml +++ b/render-wasm/Cargo.toml @@ -7,7 +7,7 @@ license-file = "../LICENSE" description = "Wasm-based canvas renderer for Penpot" [features] -default = ["profile"] +default = [] profile = ["profile-macros", "profile-raf"] profile-macros = [] profile-raf = [] diff --git a/render-wasm/_build_env b/render-wasm/_build_env index 970402da33..996fe32346 100644 --- a/render-wasm/_build_env +++ b/render-wasm/_build_env @@ -24,7 +24,7 @@ EMSDK_QUIET=1 . /usr/local/emsdk/emsdk_env.sh; export EM_CACHE="/tmp/emsdk_cache"; -_CARGO_PARAMS=""; +_CARGO_PARAMS="${@:2}"; if [ "$_BUILD_MODE" = "release" ]; then _CARGO_PARAMS="--release $_CARGO_PARAMS" diff --git a/render-wasm/src/debug.rs b/render-wasm/src/debug.rs deleted file mode 100644 index ff427339ca..0000000000 --- a/render-wasm/src/debug.rs +++ /dev/null @@ -1 +0,0 @@ -pub const DEBUG_VISIBLE: u32 = 0x01; diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index 3ea0e1a6a1..c00c20f2c5 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -1,10 +1,10 @@ use skia_safe as skia; -mod debug; #[cfg(target_arch = "wasm32")] mod emscripten; mod math; mod mem; +mod options; mod performance; mod render; mod shapes; @@ -140,7 +140,11 @@ pub extern "C" fn set_view(zoom: f32, x: f32, y: f32) { render_state.viewbox.set_all(zoom, x, y); if zoom_changed { with_state!(state, { - state.rebuild_tiles(); + if state.render_state.options.is_profile_rebuild_tiles() { + state.rebuild_tiles(); + } else { + state.rebuild_tiles_shallow(); + } }); } }); diff --git a/render-wasm/src/options.rs b/render-wasm/src/options.rs new file mode 100644 index 0000000000..37afacfc21 --- /dev/null +++ b/render-wasm/src/options.rs @@ -0,0 +1,2 @@ +pub const DEBUG_VISIBLE: u32 = 0x01; +pub const PROFILE_REBUILD_TILES: u32 = 0x02; diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index fdf0443b9e..b2bddb0a0b 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -4,8 +4,6 @@ use crate::uuid::Uuid; use std::collections::{HashMap, HashSet, VecDeque}; use crate::performance; -#[cfg(target_arch = "wasm32")] -use crate::run_script; use crate::view::Viewbox; use crate::wapi; @@ -154,7 +152,7 @@ impl RenderState { } pub fn set_debug_flags(&mut self, debug: u32) { - self.options.debug_flags = debug; + self.options.flags = debug; } pub fn set_dpr(&mut self, dpr: f32) { @@ -640,6 +638,12 @@ impl RenderState { .to_string(), )?; + // If the shape is not in the tile set, then we update + // it. + if let None = self.tiles.get_tiles_of(node_id) { + self.update_tile_for(element); + } + if visited_children { if !visited_mask { match element.shape_type { @@ -810,13 +814,13 @@ impl RenderState { Ok(()) } - pub fn get_tiles_for_rect(&mut self, shape: &Shape) -> (i32, i32, i32, i32) { + pub fn get_tiles_for_shape(&mut self, shape: &Shape) -> (i32, i32, i32, i32) { let tile_size = tiles::get_tile_size(self.viewbox); tiles::get_tiles_for_rect(shape.extrect(), tile_size) } pub fn update_tile_for(&mut self, shape: &Shape) { - let (rsx, rsy, rex, rey) = self.get_tiles_for_rect(shape); + let (rsx, rsy, rex, rey) = self.get_tiles_for_shape(shape); let new_tiles: HashSet<(i32, i32)> = (rsx..=rex) .flat_map(|x| (rsy..=rey).map(move |y| (x, y))) .collect(); @@ -840,6 +844,36 @@ impl RenderState { } } + pub fn rebuild_tiles_shallow( + &mut self, + tree: &mut HashMap, + modifiers: &HashMap, + structure: &HashMap>, + ) { + performance::begin_measure!("rebuild_tiles_shallow"); + self.tiles.invalidate(); + self.surfaces.remove_cached_tiles(); + let mut nodes = vec![Uuid::nil()]; + while let Some(shape_id) = nodes.pop() { + if let Some(shape) = tree.get(&shape_id) { + let mut shape = shape.clone(); + if shape_id != Uuid::nil() { + if let Some(modifier) = modifiers.get(&shape_id) { + shape.apply_transform(modifier); + } + self.update_tile_for(&shape); + } else { + // We only need to rebuild tiles from the first level. + let children = modified_children_ids(&shape, structure.get(&shape.id)); + for child_id in children.iter() { + nodes.push(*child_id); + } + } + } + } + performance::end_measure!("rebuild_tiles_shallow"); + } + pub fn rebuild_tiles( &mut self, tree: &mut HashMap, diff --git a/render-wasm/src/render/options.rs b/render-wasm/src/render/options.rs index 5e27f674b8..fc80bf2014 100644 --- a/render-wasm/src/render/options.rs +++ b/render-wasm/src/render/options.rs @@ -1,15 +1,15 @@ -use crate::debug; +use crate::options; #[derive(Debug, Copy, Clone, PartialEq)] pub struct RenderOptions { - pub debug_flags: u32, + pub flags: u32, pub dpr: Option, } impl Default for RenderOptions { fn default() -> Self { Self { - debug_flags: 0x00, + flags: 0x00, dpr: None, } } @@ -17,7 +17,11 @@ impl Default for RenderOptions { impl RenderOptions { pub fn is_debug_visible(&self) -> bool { - self.debug_flags & debug::DEBUG_VISIBLE == debug::DEBUG_VISIBLE + self.flags & options::DEBUG_VISIBLE == options::DEBUG_VISIBLE + } + + pub fn is_profile_rebuild_tiles(&self) -> bool { + self.flags & options::PROFILE_REBUILD_TILES == options::PROFILE_REBUILD_TILES } pub fn dpr(&self) -> f32 { diff --git a/render-wasm/src/state.rs b/render-wasm/src/state.rs index f92a5d9dea..67f9129c17 100644 --- a/render-wasm/src/state.rs +++ b/render-wasm/src/state.rs @@ -73,7 +73,7 @@ impl<'a> State<'a> { pub fn delete_shape(&mut self, id: Uuid) { // We don't really do a self.shapes.remove so that redo/undo keep working if let Some(shape) = self.shapes.get(&id) { - let (rsx, rsy, rex, rey) = self.render_state.get_tiles_for_rect(&shape); + let (rsx, rsy, rex, rey) = self.render_state.get_tiles_for_shape(&shape); for x in rsx..=rex { for y in rsy..=rey { let tile = (x, y); @@ -118,6 +118,11 @@ impl<'a> State<'a> { } } + pub fn rebuild_tiles_shallow(&mut self) { + self.render_state + .rebuild_tiles_shallow(&mut self.shapes, &self.modifiers, &self.structure); + } + pub fn rebuild_tiles(&mut self) { self.render_state .rebuild_tiles(&mut self.shapes, &self.modifiers, &self.structure);