mirror of
https://github.com/penpot/penpot.git
synced 2025-01-07 15:39:42 -05:00
🎉 Improve performace for zoom and pan with wasm render
This commit is contained in:
parent
7b57509d2d
commit
ec8799d806
5 changed files with 84 additions and 14 deletions
|
@ -11,6 +11,7 @@
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.render-wasm.helpers :as h]
|
[app.render-wasm.helpers :as h]
|
||||||
|
[app.util.functions :as fns]
|
||||||
[promesa.core :as p]))
|
[promesa.core :as p]))
|
||||||
|
|
||||||
(defonce internal-frame-id nil)
|
(defonce internal-frame-id nil)
|
||||||
|
@ -119,15 +120,17 @@
|
||||||
;; https://rust-skia.github.io/doc/skia_safe/enum.BlendMode.html
|
;; https://rust-skia.github.io/doc/skia_safe/enum.BlendMode.html
|
||||||
(h/call internal-module "_set_shape_blend_mode" (translate-blend-mode blend-mode)))
|
(h/call internal-module "_set_shape_blend_mode" (translate-blend-mode blend-mode)))
|
||||||
|
|
||||||
|
(def debounce_render (fns/debounce render 100))
|
||||||
|
|
||||||
(defn set-view
|
(defn set-view
|
||||||
[zoom vbox]
|
[zoom vbox]
|
||||||
(h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)))
|
(h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)) (:width vbox) (:height vbox))
|
||||||
(request-render))
|
(h/call internal-module "_navigate")
|
||||||
|
(debounce_render))
|
||||||
|
|
||||||
(defn set-objects
|
(defn set-objects
|
||||||
[objects]
|
[objects]
|
||||||
(let [shapes (into [] (vals objects))
|
(let [shapes (into [] (vals objects))
|
||||||
|
|
||||||
total-shapes (count shapes)]
|
total-shapes (count shapes)]
|
||||||
(loop [index 0]
|
(loop [index 0]
|
||||||
(when (< index total-shapes)
|
(when (< index total-shapes)
|
||||||
|
|
|
@ -3,6 +3,7 @@ pub mod shapes;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod view;
|
pub mod view;
|
||||||
|
pub mod images;
|
||||||
|
|
||||||
use skia_safe as skia;
|
use skia_safe as skia;
|
||||||
|
|
||||||
|
@ -46,7 +47,13 @@ pub unsafe extern "C" fn resize_surface(width: i32, height: i32) {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn render() {
|
pub unsafe extern "C" fn render() {
|
||||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
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]
|
#[no_mangle]
|
||||||
|
@ -56,11 +63,13 @@ pub extern "C" fn reset_canvas() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[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");
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||||
|
state.view.zoom = zoom;
|
||||||
state.view.x = x;
|
state.view.x = x;
|
||||||
state.view.y = y;
|
state.view.y = y;
|
||||||
state.view.zoom = zoom;
|
state.view.width = width;
|
||||||
|
state.view.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -4,6 +4,8 @@ use std::collections::HashMap;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::shapes::Shape;
|
use crate::shapes::Shape;
|
||||||
|
use crate::view::View;
|
||||||
|
use crate::images::Image;
|
||||||
|
|
||||||
struct GpuState {
|
struct GpuState {
|
||||||
pub context: DirectContext,
|
pub context: DirectContext,
|
||||||
|
@ -48,10 +50,16 @@ impl GpuState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct CachedSurfaceImage {
|
||||||
|
pub image: Image,
|
||||||
|
pub view: View,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct RenderState {
|
pub(crate) struct RenderState {
|
||||||
gpu_state: GpuState,
|
gpu_state: GpuState,
|
||||||
pub final_surface: skia::Surface,
|
pub final_surface: skia::Surface,
|
||||||
pub drawing_surface: skia::Surface,
|
pub drawing_surface: skia::Surface,
|
||||||
|
pub cached_surface_image: Option<CachedSurfaceImage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderState {
|
impl RenderState {
|
||||||
|
@ -67,6 +75,7 @@ impl RenderState {
|
||||||
gpu_state,
|
gpu_state,
|
||||||
final_surface,
|
final_surface,
|
||||||
drawing_surface,
|
drawing_surface,
|
||||||
|
cached_surface_image: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,20 +163,59 @@ impl RenderState {
|
||||||
.clear(skia::Color::TRANSPARENT);
|
.clear(skia::Color::TRANSPARENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_all_shapes(
|
pub fn navigate(
|
||||||
&mut self,
|
&mut self,
|
||||||
zoom: f32,
|
view: &View,
|
||||||
pan_x: f32,
|
|
||||||
pan_y: f32,
|
|
||||||
shapes: &HashMap<Uuid, Shape>,
|
shapes: &HashMap<Uuid, Shape>,
|
||||||
) {
|
) {
|
||||||
self.reset_canvas();
|
self.reset_canvas();
|
||||||
|
|
||||||
self.scale(zoom, zoom);
|
if let Some(cached_surface_image) = &self.cached_surface_image {
|
||||||
self.translate(pan_x, pan_y);
|
// 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<Uuid, Shape>,
|
||||||
|
) {
|
||||||
|
self.reset_canvas();
|
||||||
|
self.scale(view.zoom, view.zoom);
|
||||||
|
self.translate(view.x, view.y);
|
||||||
self.render_shape_tree(Uuid::nil(), shapes);
|
self.render_shape_tree(Uuid::nil(), shapes);
|
||||||
|
|
||||||
|
self.cached_surface_image = Some(CachedSurfaceImage {
|
||||||
|
image: self.final_surface.image_snapshot(),
|
||||||
|
view: view.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
self.flush();
|
self.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ impl<'a> State<'a> {
|
||||||
x: 0.,
|
x: 0.,
|
||||||
y: 0.,
|
y: 0.,
|
||||||
zoom: 1.,
|
zoom: 1.,
|
||||||
|
width: 0.,
|
||||||
|
height: 0.,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,9 +39,14 @@ impl<'a> State<'a> {
|
||||||
&mut self.render_state
|
&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
|
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) {
|
pub fn use_shape(&'a mut self, id: Uuid) {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct View
|
pub(crate) struct View
|
||||||
{
|
{
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
pub zoom: f32,
|
pub zoom: f32,
|
||||||
|
pub width: f32,
|
||||||
|
pub height: f32,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue