From c88015f70e9792e4506de2aa383cf15abdec2c9f Mon Sep 17 00:00:00 2001 From: Aitor Moreno Date: Wed, 29 Apr 2026 11:41:07 +0200 Subject: [PATCH] :recycle: Change how frames are queued --- frontend/src/app/render_wasm/api.cljs | 42 +++++--------------------- frontend/src/app/render_wasm/wasm.cljs | 31 ++++++++++++++++++- render-wasm/src/main.rs | 9 ------ render-wasm/src/render.rs | 26 ---------------- render-wasm/src/state.rs | 4 --- 5 files changed, 38 insertions(+), 74 deletions(-) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index e42afc9e25..aba6fc7970 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -317,46 +317,23 @@ (aget buffer 3)) (set! wasm/internal-frame-id nil)))) -(defn render-preview! - "Render a lightweight preview without tile caching. - Used during progressive loading for fast feedback." - [] - (when (and wasm/context-initialized? (not @wasm/context-lost?)) - (h/call wasm/internal-module "_render_preview"))) - - -(defonce pending-render (atom false)) (defonce shapes-loading? (atom false)) (defonce deferred-render? (atom false)) -(defn- register-deferred-render! - [] - (reset! deferred-render? true)) - (defn request-render [_requester] - (when (and wasm/context-initialized? (not @wasm/context-lost?) (not @wasm/disable-request-render?)) + (when (and wasm/context-initialized? + (not @wasm/context-lost?) + (not @wasm/disable-request-render?)) (if @shapes-loading? - (register-deferred-render!) - (when-not @pending-render - (reset! pending-render true) - (let [frame-id - (js/requestAnimationFrame - (fn [ts] - (reset! pending-render false) - (set! wasm/internal-frame-id nil) - (render ts)))] - (set! wasm/internal-frame-id frame-id)))))) + (reset! deferred-render? true) + (wasm/request-frame render)))) (defn- begin-shapes-loading! [] (reset! shapes-loading? true) - (let [frame-id wasm/internal-frame-id - was-pending @pending-render] - (when frame-id - (js/cancelAnimationFrame frame-id) - (set! wasm/internal-frame-id nil)) - (reset! pending-render false) + (let [was-pending (wasm/frame-requested?)] + (wasm/cancel-frame) (reset! deferred-render? was-pending))) (defn- end-shapes-loading! @@ -1708,12 +1685,9 @@ (set! wasm/context-initialized? false) ;; Cancel any pending animation frame to prevent race conditions - (when wasm/internal-frame-id - (js/cancelAnimationFrame wasm/internal-frame-id) - (set! wasm/internal-frame-id nil)) + (wasm/cancel-frame) ;; Reset render flags to prevent new renders from being scheduled - (reset! pending-render false) (reset! shapes-loading? false) (reset! deferred-render? false) diff --git a/frontend/src/app/render_wasm/wasm.cljs b/frontend/src/app/render_wasm/wasm.cljs index 25c2908575..d5d6b9aeaf 100644 --- a/frontend/src/app/render_wasm/wasm.cljs +++ b/frontend/src/app/render_wasm/wasm.cljs @@ -10,6 +10,36 @@ (defonce internal-frame-id nil) (defonce internal-module #js {}) +;; Is a frame requested? +(defn frame-requested? + "Returns true if a frame was requested" + [] + (not (nil? internal-frame-id))) + +;; Cancels a frame +(defn cancel-frame + "Cancels the current requested frame" + [] + (when-not (nil? internal-frame-id) + (js/cancelAnimationFrame internal-frame-id) + (set! internal-frame-id nil) + true) + false) + +(defn create-frame-delegate + "Creates a new frame delegate" + [f] + (fn frame-delegate [timestamp] + (let [frame-id internal-frame-id] + (set! internal-frame-id nil) + (f timestamp frame-id)))) + +;; Requests a frame +(defn request-frame + "Requests a new frame" + [f] + (set! internal-frame-id (js/requestAnimationFrame (create-frame-delegate f)))) + ;; Reference to the HTML canvas element. (defonce canvas nil) ;; Snapshot of the current canvas suitable for `` overlays. @@ -29,7 +59,6 @@ ;; When we're rendering in a sync way we want to stop the asynchrous `request-render` (defonce disable-request-render? (atom false)) - (defonce serializers #js {:blur-type shared/RawBlurType :blend-mode shared/RawBlendMode diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index ee53f8a98c..962462216e 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -306,15 +306,6 @@ pub extern "C" fn set_preview_mode(enabled: bool) -> Result<()> { Ok(()) } -#[no_mangle] -#[wasm_error] -pub extern "C" fn render_preview() -> Result<()> { - with_state_mut!(state, { - state.render_preview(performance::get_time()); - }); - Ok(()) -} - /// Enter bulk-loading mode. While active, `state.loading` is `true`. #[no_mangle] #[wasm_error] diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index 897fb733af..c1f08e76e6 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -1864,33 +1864,7 @@ impl RenderState { performance::end_measure!("render_from_cache"); performance::end_timed_log!("render_from_cache", _start); - } - /// Render a preview of the shapes during loading. - /// This rebuilds tiles for touched shapes and renders synchronously. - pub fn render_preview(&mut self, tree: ShapesPoolRef, timestamp: i32) -> Result<()> { - let _start = performance::begin_timed_log!("render_preview"); - performance::begin_measure!("render_preview"); - - // Enable fast_mode during preview to skip expensive effects (blur, shadows). - // Restore the previous state afterward so the final render is full quality. - let current_fast_mode = self.options.is_fast_mode(); - self.options.set_fast_mode(true); - - // Skip tile rebuilding during preview - we'll do it at the end - // Just rebuild tiles for touched shapes and render synchronously - self.rebuild_touched_tiles(tree); - - // Use the sync render path - self.start_render_loop(None, tree, timestamp, true)?; - - self.options.set_fast_mode(current_fast_mode); - - performance::end_measure!("render_preview"); - performance::end_timed_log!("render_preview", _start); - - Ok(()) - } pub fn start_render_loop( &mut self, diff --git a/render-wasm/src/state.rs b/render-wasm/src/state.rs index c624dad43d..0f666fe0b0 100644 --- a/render-wasm/src/state.rs +++ b/render-wasm/src/state.rs @@ -253,10 +253,6 @@ impl State { self.render_state.rebuild_touched_tiles(&self.shapes); } - pub fn render_preview(&mut self, timestamp: i32) { - let _ = self.render_state.render_preview(&self.shapes, timestamp); - } - pub fn rebuild_modifier_tiles(&mut self, ids: Vec) -> Result<()> { // Index-based storage is safe self.render_state