mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 14:00:37 +00:00
WIP
This commit is contained in:
parent
10a2c9bc5c
commit
f2412ab0c7
@ -44,11 +44,13 @@
|
||||
[app.main.ui.workspace.tokens.themes.create-modal]
|
||||
[app.main.ui.workspace.viewport :refer [viewport*]]
|
||||
[app.main.ui.workspace.webgl-unavailable-modal]
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[app.util.debug :as dbg]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[goog.events :as events]
|
||||
[okulary.core :as l]
|
||||
[promesa.core :as p]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc workspace-content*
|
||||
@ -193,6 +195,53 @@
|
||||
:layout layout}]
|
||||
[:> workspace-loader*])))
|
||||
|
||||
(mf/defc early-wasm-batch-canvas*
|
||||
"Optional preview canvas while get-file is still in flight. If the batch
|
||||
arrives first, paints geometry immediately. Unmounts as soon as the file
|
||||
loads — never delays workspace-inner."
|
||||
{::mf/private true}
|
||||
[{:keys [background]}]
|
||||
(let [canvas-ref (mf/use-ref nil)]
|
||||
(mf/with-effect [background]
|
||||
(when-let [canvas (mf/ref-val canvas-ref)]
|
||||
(let [unmounted? (volatile! false)
|
||||
interval-id (volatile! nil)
|
||||
try-paint
|
||||
(fn []
|
||||
(when-not @unmounted?
|
||||
(when (wasm.api/try-early-structural-paint!
|
||||
{:background background})
|
||||
(when-let [id @interval-id]
|
||||
(js/clearInterval id)
|
||||
(vreset! interval-id nil)))))]
|
||||
(->> @wasm.api/module
|
||||
(p/fmap
|
||||
(fn [ready?]
|
||||
(when (and ready? (not @unmounted?))
|
||||
(when (try
|
||||
(wasm.api/init-canvas-context canvas)
|
||||
(catch :default e
|
||||
(js/console.error
|
||||
"early-wasm-batch-canvas init failed" e)
|
||||
false))
|
||||
(wasm.api/resize-canvas! canvas)
|
||||
(try-paint)
|
||||
(vreset! interval-id (js/setInterval try-paint 50)))))))
|
||||
(fn []
|
||||
(vreset! unmounted? true)
|
||||
(when-let [id @interval-id] (js/clearInterval id))
|
||||
(wasm.api/clear-canvas)))))
|
||||
|
||||
[:canvas {:id "render-early-batch"
|
||||
:data-testid "canvas-wasm-early-batch"
|
||||
:ref canvas-ref
|
||||
:style {:position "absolute"
|
||||
:inset 0
|
||||
:width "100%"
|
||||
:height "100%"
|
||||
:z-index 2
|
||||
:pointer-events "none"}}]))
|
||||
|
||||
(mf/defc workspace*
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [team-id project-id file-id page-id layout-name]}]
|
||||
@ -219,11 +268,20 @@
|
||||
design-tokens? (features/use-feature "design-tokens/v1")
|
||||
|
||||
wasm-renderer-enabled? (features/use-feature "render-wasm/v1")
|
||||
wasm-batch-enabled? (wasm.api/wasm-shapes-batch-enabled?)
|
||||
|
||||
first-frame-rendered? (mf/use-state false)
|
||||
|
||||
background-color (:background-color wglobal)]
|
||||
|
||||
(mf/with-effect []
|
||||
(let [handle-wasm-render
|
||||
(fn [_]
|
||||
(reset! first-frame-rendered? true))
|
||||
listener-key (events/listen js/document "penpot:wasm:render" handle-wasm-render)]
|
||||
(fn []
|
||||
(events/unlistenByKey listener-key))))
|
||||
|
||||
(mf/with-effect []
|
||||
(st/emit! (dps/initialize-persistence)
|
||||
(dpl/update-plugins-permissions-peek)))
|
||||
@ -252,14 +310,6 @@
|
||||
(mf/with-effect [file-id page-id]
|
||||
(reset! first-frame-rendered? false))
|
||||
|
||||
(mf/with-effect []
|
||||
(let [handle-wasm-render
|
||||
(fn [_]
|
||||
(reset! first-frame-rendered? true))
|
||||
listener-key (events/listen js/document "penpot:wasm:render" handle-wasm-render)]
|
||||
(fn []
|
||||
(events/unlistenByKey listener-key))))
|
||||
|
||||
[:> (mf/provider ctx/current-project-id) {:value project-id}
|
||||
[:> (mf/provider ctx/current-file-id) {:value file-id}
|
||||
[:> (mf/provider ctx/current-page-id) {:value page-id}
|
||||
@ -272,6 +322,12 @@
|
||||
:touch-action "none"
|
||||
:position "relative"}}
|
||||
[:> context-menu*]
|
||||
;; Parallel preview only: never blocks get-file / workspace-inner.
|
||||
(when (and wasm-renderer-enabled?
|
||||
wasm-batch-enabled?
|
||||
(uuid? page-id)
|
||||
(not file-loaded?))
|
||||
[:> early-wasm-batch-canvas* {:background background-color}])
|
||||
(when (and file-loaded? page-id)
|
||||
[:> workspace-inner*
|
||||
{:page-id page-id
|
||||
@ -279,12 +335,10 @@
|
||||
:file file
|
||||
:wglobal wglobal
|
||||
:layout layout}])
|
||||
(when (or (not (and file-loaded? page-id))
|
||||
;; in wasm renderer, extend the pixel loader until the first frame is rendered
|
||||
;; but do not apply it when switching pages
|
||||
(and wasm-renderer-enabled?
|
||||
(not file-loaded?)
|
||||
(not @first-frame-rendered?)))
|
||||
(when (or (not page-id)
|
||||
(and (not file-loaded?)
|
||||
(or (not wasm-renderer-enabled?)
|
||||
(not @first-frame-rendered?))))
|
||||
[:> workspace-loader*])]]]]]]))
|
||||
|
||||
(mf/defc workspace-page*
|
||||
|
||||
@ -76,13 +76,72 @@
|
||||
(contains? cf/flags :wasm-shapes-batch))
|
||||
|
||||
;; Prefetched `_set_shapes_batch` bytes for the next cold load.
|
||||
;; Shape: {:file-id uuid :page-id uuid :promise Promise<Uint8Array|nil>}
|
||||
;; Shape: {:file-id uuid :page-id uuid :promise Promise :u8 Uint8Array?
|
||||
;; :preview-painted? bool}
|
||||
(defonce ^:private cold-load-batch* (atom nil))
|
||||
|
||||
(declare paint-after-structural-ingest!)
|
||||
(declare stop-progressive-render!)
|
||||
|
||||
(defn clear-cold-load-batch!
|
||||
[]
|
||||
(reset! cold-load-batch* nil))
|
||||
|
||||
(defn- batch-shape-count
|
||||
"Shape count is the leading LE u32 of an encode-shapes-batch buffer."
|
||||
[u8]
|
||||
(when (and u8 (>= (.-byteLength ^js u8) 4))
|
||||
(let [view (js/DataView. (.-buffer ^js u8)
|
||||
(.-byteOffset ^js u8)
|
||||
(.-byteLength ^js u8))]
|
||||
(.getUint32 view 0 true))))
|
||||
|
||||
(defn- store-batch-bytes!
|
||||
[file-id page-id u8]
|
||||
(swap! cold-load-batch*
|
||||
(fn [entry]
|
||||
(if (and entry
|
||||
(= file-id (:file-id entry))
|
||||
(= page-id (:page-id entry)))
|
||||
(assoc entry :u8 u8)
|
||||
entry))))
|
||||
|
||||
(defn try-early-structural-paint!
|
||||
"Flush + sync-paint a prefetched server batch without CLJS shape maps.
|
||||
Fires only when an early canvas is already live AND the batch arrived
|
||||
before get-file unmounted it. Never blocks get-file or workspace mount.
|
||||
Does not consume the batch — set-objects re-ingests on the real viewport."
|
||||
([]
|
||||
(try-early-structural-paint! nil))
|
||||
([{:keys [zoom vbox background]}]
|
||||
(when (and (wasm-shapes-batch-enabled?) (wasm/live?))
|
||||
(let [{:keys [u8 preview-painted?] :as entry} @cold-load-batch*
|
||||
n (batch-shape-count u8)]
|
||||
(when (and (some? entry)
|
||||
(some? u8)
|
||||
(number? n)
|
||||
(pos? n)
|
||||
(not preview-painted?))
|
||||
(let [zoom (or zoom 1)
|
||||
vbox (or vbox {:x 0 :y 0 :width 1920 :height 1080})
|
||||
rgba (when background (sr-clr/hex->u32argb background 1))]
|
||||
(stop-progressive-render!)
|
||||
(when rgba
|
||||
(h/call wasm/internal-module "_set_canvas_background" rgba))
|
||||
(h/call wasm/internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)))
|
||||
(h/call wasm/internal-module "_init_shapes_pool" n)
|
||||
(upload/flush-shapes-batch-bytes! u8)
|
||||
(paint-after-structural-ingest! nil)
|
||||
(swap! cold-load-batch*
|
||||
(fn [e]
|
||||
(cond-> e
|
||||
(and e (= (:file-id e) (:file-id entry))
|
||||
(= (:page-id e) (:page-id entry)))
|
||||
(assoc :preview-painted? true))))
|
||||
(ug/dispatch! (ug/event "penpot:wasm:render"))
|
||||
(js/console.info "[wasm-batch] early structural paint" n "shapes")
|
||||
true))))))
|
||||
|
||||
(defn prefetch-cold-load-batch!
|
||||
"Start downloading the server-encoded shapes batch for `file-id`/`page-id`.
|
||||
Safe to call multiple times; only the latest pair is kept."
|
||||
@ -91,7 +150,7 @@
|
||||
(let [t0 (js/performance.now)
|
||||
prom
|
||||
(p/create
|
||||
(fn [resolve reject]
|
||||
(fn [resolve _reject]
|
||||
(->> (rp/cmd! :get-file-wasm-shapes-batch
|
||||
{:file-id file-id
|
||||
:page-id page-id})
|
||||
@ -104,7 +163,9 @@
|
||||
"[wasm-batch] download"
|
||||
(.-byteLength u8) "bytes in"
|
||||
(.toFixed ms 1) "ms")
|
||||
(resolve u8)))
|
||||
(store-batch-bytes! file-id page-id u8)
|
||||
(resolve u8)
|
||||
(try-early-structural-paint!)))
|
||||
(fn [err]
|
||||
(js/console.warn "[wasm-batch] download failed" err)
|
||||
(resolve nil))))))]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user