diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 6df71e7e4f..9055dea1ec 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -69,12 +69,8 @@ (def ^:const DEBOUNCE_DELAY_MS 100) (def ^:const THROTTLE_DELAY_MS 10) -;; Async chunked processing constants -;; SHAPES_CHUNK_SIZE: Number of shapes to process before yielding to browser -;; Lower values = more responsive UI but slower total processing -;; Higher values = faster total processing but may cause UI jank +;; Number of shapes to process before yielding to browser (def ^:const SHAPES_CHUNK_SIZE 100) - ;; Threshold below which we use synchronous processing (no chunking overhead) (def ^:const ASYNC_THRESHOLD 100) @@ -189,20 +185,6 @@ (when was-loading (request-render "set-objects:flush")))) -(defn- request-progressive-render! - ([reason] - (let [was-loading? @shapes-loading?] - (if was-loading? - (do - (reset! shapes-loading? false) - (try - (request-render reason) - (finally - (reset! shapes-loading? was-loading?)))) - (request-render reason)))) - ([] - (request-progressive-render! "set-objects:chunk"))) - (declare get-text-dimensions) (defn update-text-rect! @@ -982,9 +964,6 @@ svg-attrs (get shape :svg-attrs) shadows (get shape :shadow)] - ;; Batched call: sets id, parent_id, type, clip_content, hidden, blend_mode, - ;; constraints, opacity, rotation, transform, selrect, and corners in one WASM call. - ;; This replaces 12+ individual WASM calls with a single batched operation. (shapes/set-shape-base-props shape) ;; Remaining properties that need separate calls (variable-length or conditional) @@ -1090,12 +1069,11 @@ then does a full tile-based render at the end." [shapes render-callback] (let [total-shapes (count shapes) - ;; Calculate how many chunks we'll process - total-chunks (js/Math.ceil (/ total-shapes SHAPES_CHUNK_SIZE)) + total-chunks (mth/ceil (/ total-shapes SHAPES_CHUNK_SIZE)) ;; Render at 25%, 50%, 75% of loading - render-at-chunks (set [(js/Math.floor (* total-chunks 0.25)) - (js/Math.floor (* total-chunks 0.5)) - (js/Math.floor (* total-chunks 0.75))])] + render-at-chunks (set [(mth/floor (* total-chunks 0.25)) + (mth/floor (* total-chunks 0.5)) + (mth/floor (* total-chunks 0.75))])] (p/create (fn [resolve _reject] (letfn [(process-next-chunk [index thumbnails-acc full-acc chunk-count] @@ -1124,7 +1102,6 @@ (render-finish)) (ug/dispatch! (ug/event "penpot:wasm:set-objects")) (resolve nil))))))] - ;; Start processing (process-next-chunk 0 [] [] 0)))))) (defn- set-objects-sync @@ -1154,7 +1131,6 @@ maintaining proper shape reference consistency in WASM." [objects] ;; Get IDs in tree order starting from root (uuid/zero) - ;; cfh/get-children-ids-with-self returns [root-id, child1-id, grandchild1-id, ...] (let [ordered-ids (cfh/get-children-ids-with-self objects uuid/zero)] (into [] (keep #(get objects %)) @@ -1163,11 +1139,8 @@ (defn set-objects "Set all shape objects for rendering. - IMPORTANT: Shapes are processed in tree order (parents before children) - to maintain proper shape reference consistency in WASM. - - NOTE: Async processing uses render gating to avoid race conditions with - requestAnimationFrame renders during loading." + Shapes are processed in tree order (parents before children) + to maintain proper shape reference consistency in WASM." ([objects] (set-objects objects nil)) ([objects render-callback] diff --git a/frontend/src/app/render_wasm/api/shapes.cljs b/frontend/src/app/render_wasm/api/shapes.cljs index 3ab680dac4..c498c5e922 100644 --- a/frontend/src/app/render_wasm/api/shapes.cljs +++ b/frontend/src/app/render_wasm/api/shapes.cljs @@ -95,23 +95,19 @@ Returns nil." [shape] (when wasm/context-initialized? - (let [;; Extract all properties from shape - id (dm/get-prop shape :id) + (let [id (dm/get-prop shape :id) parent-id (get shape :parent-id) shape-type (dm/get-prop shape :type) - ;; Boolean flags clip-content (if (= shape-type :frame) (not (get shape :show-content)) false) hidden (get shape :hidden false) - ;; Compute flags byte flags (cond-> 0 clip-content (bit-or FLAG-CLIP-CONTENT) hidden (bit-or FLAG-HIDDEN)) - ;; Enum values blend-mode (sr/translate-blend-mode (get shape :blend-mode)) constraint-h (let [c (get shape :constraints-h)] (if (some? c) @@ -122,7 +118,6 @@ (sr/translate-constraint-v c) CONSTRAINT-NONE)) - ;; Float values opacity (d/nilv (get shape :opacity) 1.0) rotation (d/nilv (get shape :rotation) 0.0) @@ -193,7 +188,6 @@ (.setFloat32 dview (+ offset 96) r3 true) (.setFloat32 dview (+ offset 100) r4 true) - ;; Call WASM function (h/call wasm/internal-module "_set_shape_base_props") nil))) diff --git a/render-wasm/src/state.rs b/render-wasm/src/state.rs index 1f80e4a41f..385408d89f 100644 --- a/render-wasm/src/state.rs +++ b/render-wasm/src/state.rs @@ -228,7 +228,7 @@ impl State { } pub fn rebuild_modifier_tiles(&mut self, ids: Vec) { - // No longer need unsafe lifetime extension - index-based storage is safe + // Index-based storage is safe self.render_state .rebuild_modifier_tiles(&mut self.shapes, ids); } diff --git a/render-wasm/src/wasm/shapes/base_props.rs b/render-wasm/src/wasm/shapes/base_props.rs index 4846d9b320..428c5e18fa 100644 --- a/render-wasm/src/wasm/shapes/base_props.rs +++ b/render-wasm/src/wasm/shapes/base_props.rs @@ -27,7 +27,6 @@ use super::RawShapeType; /// | 88 | 16 | corners | 4 × f32 LE (r1,r2,r3,r4) | /// |--------|------|--------------|-----------------------------------| /// | Total | 104 | | | - pub const BASE_PROPS_SIZE: usize = 104; const FLAG_CLIP_CONTENT: u8 = 0b0000_0001; @@ -67,12 +66,6 @@ fn read_uuid(bytes: &[u8], offset: usize) -> Uuid { ) } -/// Sets base shape properties from a pre-allocated buffer in a single WASM call. -/// -/// This replaces multiple individual WASM calls (use_shape, set_parent, set_shape_type, -/// set_shape_clip_content, set_shape_rotation, set_shape_transform, set_shape_blend_mode, -/// set_shape_opacity, set_shape_hidden, set_shape_selrect, set_shape_corners, -/// set_shape_constraints) with a single batched call. #[no_mangle] pub extern "C" fn set_shape_base_props() { let bytes = mem::bytes();