0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-24 07:46:13 -05:00

Merge pull request #5827 from penpot/superalex-fix-wasm-glitches

🐛 Fix wasm glitches
This commit is contained in:
Aitor Moreno 2025-02-13 15:25:24 +01:00 committed by GitHub
commit 39bbb4c2bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 68 additions and 14 deletions

View file

@ -18,7 +18,6 @@
[app.main.render :as render]
[app.render-wasm.helpers :as h]
[app.util.debug :as dbg]
[app.util.functions :as fns]
[app.util.http :as http]
[app.util.webapi :as wapi]
[beicon.v2.core :as rx]
@ -522,13 +521,13 @@
(h/call internal-module "_add_shape_shadow" rgba blur spread x y (translate-shadow-style style) hidden)
(recur (inc index)))))))
(def debounce-render (fns/debounce render 100))
(defn set-view-box
[zoom vbox]
(h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)))
(h/call internal-module "_render_from_cache")
(debounce-render))
(render nil))
(defn clear-cache []
(h/call internal-module "_clear_cache"))
(defn set-objects
[objects]
@ -589,6 +588,7 @@
(let [pending' (concat (set-shape-fills fills) (set-shape-strokes strokes))]
(recur (inc index) (into pending pending'))))
pending))]
(clear-cache)
(request-render "set-objects")
(when-let [pending (seq pending)]
(->> (rx/from pending)

View file

@ -142,6 +142,7 @@
;; when something synced with wasm
;; is modified, we need to request
;; a new render.
(api/clear-cache)
(api/request-render "set-wasm-attrs")))
(defn- impl-assoc

View file

@ -47,6 +47,13 @@ pub extern "C" fn clean_up() {
mem::free_bytes();
}
#[no_mangle]
pub extern "C" fn clear_cache() {
let state = unsafe { STATE.as_mut() }.expect("Got an invalid state pointer");
let render_state = state.render_state();
render_state.clear_cache();
}
#[no_mangle]
pub extern "C" fn set_render_options(debug: u32, dpr: f32) {
let state = unsafe { STATE.as_mut() }.expect("Got an invalid state pointer");
@ -98,7 +105,9 @@ pub extern "C" fn resize_viewbox(width: i32, height: i32) {
#[no_mangle]
pub extern "C" fn set_view(zoom: f32, x: f32, y: f32) {
let state = unsafe { STATE.as_mut() }.expect("Got an invalid state pointer");
state.render_state().viewbox.set_all(zoom, x, y);
let render_state = state.render_state();
render_state.invalidate_cache_if_needed();
render_state.viewbox.set_all(zoom, x, y);
}
#[no_mangle]

View file

@ -1,3 +1,4 @@
use skia::Contains;
use skia_safe as skia;
use std::collections::HashMap;
use uuid::Uuid;
@ -71,6 +72,7 @@ pub(crate) struct RenderState {
pub render_in_progress: bool,
// Stack of nodes pending to be rendered.
pub pending_nodes: Vec<NodeRenderState>,
pub render_complete: bool,
}
impl RenderState {
@ -112,6 +114,7 @@ impl RenderState {
render_request_id: None,
render_in_progress: false,
pending_nodes: vec![],
render_complete: true,
}
}
@ -236,6 +239,12 @@ impl RenderState {
.clear(skia::Color::TRANSPARENT);
}
pub fn invalidate_cache_if_needed(&mut self) {
if let Some(ref mut cached_surface_image) = self.cached_surface_image {
cached_surface_image.invalidate_if_dirty(&self.viewbox);
}
}
pub fn render_shape(
&mut self,
shape: &mut Shape,
@ -325,6 +334,7 @@ impl RenderState {
}];
self.render_in_progress = true;
self.process_animation_frame(tree, modifiers, timestamp)?;
self.render_complete = true;
Ok(())
}
@ -359,11 +369,27 @@ impl RenderState {
}
// self.render_in_progress can have changed
if !self.render_in_progress {
if self.render_in_progress {
if self.cached_surface_image.is_some() {
self.render_from_cache()?;
}
return Ok(());
}
// Chech if cached_surface_image is not set or is invalid
if self
.cached_surface_image
.as_ref()
.map_or(true, |img| img.invalid)
{
self.cached_surface_image = Some(CachedSurfaceImage {
image: self.render_surface.image_snapshot(),
viewbox: self.viewbox,
invalid: false,
has_all_shapes: self.render_complete,
});
}
if self.options.is_debug_visible() {
self.render_debug();
}
@ -371,10 +397,13 @@ impl RenderState {
debug::render_wasm_label(self);
self.apply_render_to_final_canvas();
self.flush();
}
Ok(())
}
pub fn clear_cache(&mut self) {
self.cached_surface_image = None;
}
pub fn render_from_cache(&mut self) -> Result<(), String> {
let cached = self
.cached_surface_image
@ -397,6 +426,7 @@ impl RenderState {
navigate_x * self.options.dpr(),
navigate_y * self.options.dpr(),
));
self.final_surface.canvas().clear(self.background_color);
self.final_surface
.canvas()
.draw_image(image, (0, 0), Some(&paint));
@ -437,6 +467,7 @@ impl RenderState {
.to_string(),
)?;
let render_complete = self.viewbox.area.contains(element.bounds());
if visited_children {
if !visited_mask {
match element.kind {
@ -488,6 +519,7 @@ impl RenderState {
if !node_render_state.id.is_nil() {
if !element.bounds().intersects(self.viewbox.area) || element.hidden() {
debug::render_debug_shape(self, element, false);
self.render_complete = render_complete;
continue;
} else {
debug::render_debug_shape(self, element, true);

View file

@ -1,6 +1,18 @@
use super::{Image, Viewbox};
use skia::Contains;
use skia_safe as skia;
pub(crate) struct CachedSurfaceImage {
pub image: Image,
pub viewbox: Viewbox,
pub invalid: bool,
pub has_all_shapes: bool,
}
impl CachedSurfaceImage {
pub fn invalidate_if_dirty(&mut self, viewbox: &Viewbox) {
if !self.has_all_shapes && !self.viewbox.area.contains(viewbox.area) {
self.invalid = true;
}
}
}