From ec8799d806bf509b5026dbe083d585f50fa78d41 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 19 Nov 2024 08:58:35 +0100 Subject: [PATCH] :tada: Improve performace for zoom and pan with wasm render --- frontend/src/app/render_wasm/api.cljs | 9 ++-- render-wasm/src/main.rs | 15 +++++-- render-wasm/src/render.rs | 60 ++++++++++++++++++++++++--- render-wasm/src/state.rs | 11 ++++- render-wasm/src/view.rs | 3 ++ 5 files changed, 84 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index dd38899cd..fa17a80f6 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -11,6 +11,7 @@ [app.common.uuid :as uuid] [app.config :as cf] [app.render-wasm.helpers :as h] + [app.util.functions :as fns] [promesa.core :as p])) (defonce internal-frame-id nil) @@ -119,15 +120,17 @@ ;; https://rust-skia.github.io/doc/skia_safe/enum.BlendMode.html (h/call internal-module "_set_shape_blend_mode" (translate-blend-mode blend-mode))) +(def debounce_render (fns/debounce render 100)) + (defn set-view [zoom vbox] - (h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox))) - (request-render)) + (h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)) (:width vbox) (:height vbox)) + (h/call internal-module "_navigate") + (debounce_render)) (defn set-objects [objects] (let [shapes (into [] (vals objects)) - total-shapes (count shapes)] (loop [index 0] (when (< index total-shapes) diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index 3b5f3f2a3..9baff4fdf 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -3,6 +3,7 @@ pub mod shapes; pub mod state; pub mod utils; pub mod view; +pub mod images; use skia_safe as skia; @@ -46,7 +47,13 @@ pub unsafe extern "C" fn resize_surface(width: i32, height: i32) { #[no_mangle] pub unsafe extern "C" fn render() { let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); - state.draw_all_shapes(state.view.zoom, state.view.x, state.view.y); + state.draw_all_shapes(); +} + +#[no_mangle] + pub unsafe extern "C" fn navigate() { + let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); + state.navigate(); } #[no_mangle] @@ -56,11 +63,13 @@ pub extern "C" fn reset_canvas() { } #[no_mangle] -pub extern "C" fn set_view(zoom: f32, x: f32, y: f32) { +pub extern "C" fn set_view(zoom: f32, x: f32, y: f32, width: f32, height: f32) { let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); + state.view.zoom = zoom; state.view.x = x; state.view.y = y; - state.view.zoom = zoom; + state.view.width = width; + state.view.height = height; } #[no_mangle] diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index b1ffea2d0..ea08e9cf8 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -4,6 +4,8 @@ use std::collections::HashMap; use uuid::Uuid; use crate::shapes::Shape; +use crate::view::View; +use crate::images::Image; struct GpuState { pub context: DirectContext, @@ -48,10 +50,16 @@ impl GpuState { } } +pub(crate) struct CachedSurfaceImage { + pub image: Image, + pub view: View, +} + pub(crate) struct RenderState { gpu_state: GpuState, pub final_surface: skia::Surface, pub drawing_surface: skia::Surface, + pub cached_surface_image: Option, } impl RenderState { @@ -67,6 +75,7 @@ impl RenderState { gpu_state, final_surface, drawing_surface, + cached_surface_image: None, } } @@ -154,20 +163,59 @@ impl RenderState { .clear(skia::Color::TRANSPARENT); } - pub fn draw_all_shapes( + pub fn navigate( &mut self, - zoom: f32, - pan_x: f32, - pan_y: f32, + view: &View, shapes: &HashMap, ) { self.reset_canvas(); - self.scale(zoom, zoom); - self.translate(pan_x, pan_y); + if let Some(cached_surface_image) = &self.cached_surface_image { + // If we are drawing something bigger than the visible let's do a redraw + if (view.x > cached_surface_image.view.x) || + (-view.x + view.width > -cached_surface_image.view.x + cached_surface_image.view.width) || + (view.y > cached_surface_image.view.y) || + (-view.y + view.height > -cached_surface_image.view.y + cached_surface_image.view.height) { + self.draw_all_shapes(view, shapes); + } + else { + let image = &cached_surface_image.image; + let paint = skia::Paint::default(); + self.final_surface.canvas().save(); + self.drawing_surface.canvas().save(); + + let navigate_zoom = view.zoom / cached_surface_image.view.zoom; + let navigate_x = cached_surface_image.view.zoom * (view.x - cached_surface_image.view.x); + let navigate_y = cached_surface_image.view.zoom * (view.y - cached_surface_image.view.y); + + self.final_surface.canvas().scale((navigate_zoom, navigate_zoom)); + self.final_surface.canvas().translate((navigate_x, navigate_y)); + self.final_surface.canvas().draw_image(image.clone(), (0, 0), Some(&paint)); + + self.final_surface.canvas().restore(); + self.drawing_surface.canvas().restore(); + } + } + + self.flush(); + } + + pub fn draw_all_shapes( + &mut self, + view: &View, + shapes: &HashMap, + ) { + self.reset_canvas(); + self.scale(view.zoom, view.zoom); + self.translate(view.x, view.y); self.render_shape_tree(Uuid::nil(), shapes); + self.cached_surface_image = Some(CachedSurfaceImage { + image: self.final_surface.image_snapshot(), + view: view.clone(), + }); + self.flush(); } diff --git a/render-wasm/src/state.rs b/render-wasm/src/state.rs index 630bfa051..fdbb06807 100644 --- a/render-wasm/src/state.rs +++ b/render-wasm/src/state.rs @@ -29,6 +29,8 @@ impl<'a> State<'a> { x: 0., y: 0., zoom: 1., + width: 0., + height: 0., } } } @@ -37,9 +39,14 @@ impl<'a> State<'a> { &mut self.render_state } - pub fn draw_all_shapes(&mut self, zoom: f32, pan_x: f32, pan_y: f32) { + pub fn navigate(&mut self) { self.render_state - .draw_all_shapes(zoom, pan_x, pan_y, &self.shapes); + .navigate(&self.view, &self.shapes); + } + + pub fn draw_all_shapes(&mut self) { + self.render_state + .draw_all_shapes(&self.view, &self.shapes); } pub fn use_shape(&'a mut self, id: Uuid) { diff --git a/render-wasm/src/view.rs b/render-wasm/src/view.rs index c2c857384..f2892f34e 100644 --- a/render-wasm/src/view.rs +++ b/render-wasm/src/view.rs @@ -1,6 +1,9 @@ +#[derive(Debug, Clone, Copy)] pub(crate) struct View { pub x: f32, pub y: f32, pub zoom: f32, + pub width: f32, + pub height: f32, }