Hot swap of viewport when renderer changes

This commit is contained in:
Belén Albeza 2026-04-23 16:01:19 +02:00
parent 222c0d5b73
commit 9feaac3e05
7 changed files with 109 additions and 76 deletions

View File

@ -15,6 +15,7 @@
[app.main.data.media :as di] [app.main.data.media :as di]
[app.main.data.notifications :as ntf] [app.main.data.notifications :as ntf]
[app.main.data.team :as-alias dtm] [app.main.data.team :as-alias dtm]
[app.main.features :as features]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.router :as rt] [app.main.router :as rt]
[app.plugins.register :as plugins.register] [app.plugins.register :as plugins.register]
@ -291,8 +292,13 @@
;; FIXME ;; FIXME
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ _ _]
(->> (rp/cmd! :update-profile-props {:props props}) (let [refresh-profile$ (->> (rp/cmd! :update-profile-props {:props props})
(rx/map (constantly (refresh-profile))))))) (rx/map (constantly (refresh-profile))))
recompute$ (when (contains? props :renderer)
(rx/of (features/recompute-features)))]
(if recompute$
(rx/concat recompute$ refresh-profile$)
refresh-profile$)))))
(defn mark-onboarding-as-viewed (defn mark-onboarding-as-viewed
([] (mark-onboarding-as-viewed nil)) ([] (mark-onboarding-as-viewed nil))

View File

@ -72,6 +72,7 @@
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.router :as rt] [app.main.router :as rt]
[app.main.store :as st]
[app.render-wasm :as wasm] [app.render-wasm :as wasm]
[app.render-wasm.api :as wasm.api] [app.render-wasm.api :as wasm.api]
[app.util.dom :as dom] [app.util.dom :as dom]
@ -318,7 +319,7 @@
(let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream) (let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
rparams (rt/get-params state) rparams (rt/get-params state)
features (features/get-enabled-features state team-id) features (features/get-enabled-features state team-id)
render-wasm? (contains? features "render-wasm/v1")] render-wasm? #(features/active-feature? @st/state "render-wasm/v1")]
(log/debug :hint "initialize-workspace" (log/debug :hint "initialize-workspace"
:team-id (dm/str team-id) :team-id (dm/str team-id)
@ -329,7 +330,7 @@
(rx/concat (rx/concat
;; Fetch all essential data that should be loaded before the file ;; Fetch all essential data that should be loaded before the file
(rx/merge (rx/merge
(if ^boolean render-wasm? (if ^boolean (render-wasm?)
(->> (rx/from @wasm/module) (->> (rx/from @wasm/module)
(rx/filter true?) (rx/filter true?)
(rx/tap (fn [_] (rx/tap (fn [_]
@ -405,72 +406,72 @@
(rx/take 1) (rx/take 1)
(rx/map #(dwcm/navigate-to-comment-id comment-id)))) (rx/map #(dwcm/navigate-to-comment-id comment-id))))
(when render-wasm? (->> stream
(->> stream (rx/filter dch/commit?)
(rx/filter dch/commit?) (rx/filter (fn [_] (render-wasm?)))
(rx/map deref) (rx/map deref)
(rx/mapcat (rx/mapcat
(fn [{:keys [redo-changes]}] (fn [{:keys [redo-changes]}]
(let [added (->> redo-changes (let [added (->> redo-changes
(filter #(= (:type %) :add-obj)) (filter #(= (:type %) :add-obj))
(map :id))] (map :id))]
(->> (rx/from added) (->> (rx/from added)
(rx/map process-wasm-object))))))) (rx/map process-wasm-object))))))
(when render-wasm? (let [local-commits-s
(let [local-commits-s (->> stream
(->> stream (rx/filter dch/commit?)
(rx/filter dch/commit?) (rx/filter (fn [_] (render-wasm?)))
(rx/map deref) (rx/map deref)
(rx/filter #(and (= :local (:source %)) (rx/filter #(and (= :local (:source %))
(not (contains? (:tags %) :position-data)))) (not (contains? (:tags %) :position-data))))
(rx/filter (complement empty?))) (rx/filter (complement empty?)))
notifier-s notifier-s
(rx/merge (rx/merge
(->> local-commits-s (rx/debounce 1000)) (->> local-commits-s (rx/debounce 1000))
(->> stream (rx/filter dps/force-persist?))) (->> stream (rx/filter dps/force-persist?)))
objects-s objects-s
(rx/from-atom refs/workspace-page-objects {:emit-current-value? true}) (rx/from-atom refs/workspace-page-objects {:emit-current-value? true})
current-page-id-s current-page-id-s
(rx/from-atom refs/current-page-id {:emit-current-value? true})] (rx/from-atom refs/current-page-id {:emit-current-value? true})]
(->> local-commits-s (->> local-commits-s
(rx/buffer-until notifier-s) (rx/buffer-until notifier-s)
(rx/with-latest-from objects-s) (rx/with-latest-from objects-s)
(rx/map (rx/map
(fn [[commits objects]] (fn [[commits objects]]
(->> commits (->> commits
(mapcat :redo-changes) (mapcat :redo-changes)
(filter #(contains? #{:mod-obj :add-obj} (:type %))) (filter #(contains? #{:mod-obj :add-obj} (:type %)))
(filter #(cfh/text-shape? objects (:id %))) (filter #(cfh/text-shape? objects (:id %)))
(map #(vector (map #(vector
(:id %) (:id %)
(wasm.api/calculate-position-data (get objects (:id %)))))))) (wasm.api/calculate-position-data (get objects (:id %))))))))
(rx/with-latest-from current-page-id-s) (rx/with-latest-from current-page-id-s)
(rx/map (rx/map
(fn [[text-position-data page-id]] (fn [[text-position-data page-id]]
(let [changes (let [changes
(->> text-position-data (->> text-position-data
(mapv (fn [[id position-data]] (mapv (fn [[id position-data]]
{:type :mod-obj {:type :mod-obj
:id id :id id
:page-id page-id :page-id page-id
:operations :operations
[{:type :set [{:type :set
:attr :position-data :attr :position-data
:val position-data :val position-data
:ignore-touched true :ignore-touched true
:ignore-geometry true}]})))] :ignore-geometry true}]})))]
(when (d/not-empty? changes) (when (d/not-empty? changes)
(dch/commit-changes (dch/commit-changes
{:redo-changes changes :undo-changes [] {:redo-changes changes :undo-changes []
:save-undo? false :save-undo? false
:tags #{:position-data}}))))) :tags #{:position-data}})))))
(rx/take-until stoper-s)))) (rx/take-until stoper-s)))
(->> stream (->> stream
(rx/filter dch/commit?) (rx/filter dch/commit?)

View File

@ -30,9 +30,9 @@
[features state] [features state]
(let [params (rt/get-params state) (let [params (rt/get-params state)
wasm (get params :wasm) wasm (get params :wasm)
enable-wasm (= "true" wasm)
renderer (-> state :profile :props :renderer) renderer (-> state :profile :props :renderer)
disable-wasm (or (= "false" wasm) (= renderer :svg)) enable-wasm (or (= "true" wasm) (and (= renderer :wasm) (not= "false" wasm)))
disable-wasm (or (= "false" wasm) (and (= renderer :svg) (not= "true" wasm)))
features (cond-> features features (cond-> features
enable-wasm (conj "render-wasm/v1") enable-wasm (conj "render-wasm/v1")
disable-wasm (disj "render-wasm/v1"))] disable-wasm (disj "render-wasm/v1"))]
@ -178,3 +178,24 @@
(log/inf :hint "initialized" (log/inf :hint "initialized"
:enabled (str/join " " features)))))) :enabled (str/join " " features))))))
(defn recompute-features
[]
(ptk/reify ::recompute-features
ptk/UpdateEvent
(update [_ state]
(let [previous (or (get state :features) #{})
features (setup-wasm-features previous state)]
(if (= previous features)
state
(assoc state :features features))))
ptk/EffectEvent
(effect [_ state _]
(let [features (get state :features)]
(if (contains? features "render-wasm/v1")
(wasm/initialize true)
(wasm/initialize false))
(log/inf :hint "recomputed features"
:enabled (str/join " " features))))))

View File

@ -902,6 +902,7 @@
toggle-render toggle-render
(mf/use-fn (mf/use-fn
(mf/deps profile)
(fn [event] (fn [event]
(dom/stop-propagation event) (dom/stop-propagation event)
(let [renderer (or (-> profile :props :renderer) :svg) (let [renderer (or (-> profile :props :renderer) :svg)

View File

@ -31,6 +31,7 @@
[app.main.ui.workspace.viewport.utils :as utils] [app.main.ui.workspace.viewport.utils :as utils]
[app.main.worker :as mw] [app.main.worker :as mw]
[app.render-wasm.api :as wasm.api] [app.render-wasm.api :as wasm.api]
[app.render-wasm.wasm :as wasm]
[app.util.debug :as dbg] [app.util.debug :as dbg]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.globals :as globals] [app.util.globals :as globals]

View File

@ -375,6 +375,7 @@
(vreset! unmounted? true) (vreset! unmounted? true)
(when-let [timeout-id @timeout-id-ref] (when-let [timeout-id @timeout-id-ref]
(js/clearTimeout timeout-id)) (js/clearTimeout timeout-id))
(wasm.api/end-page-transition!)
(wasm.api/clear-canvas))))) (wasm.api/clear-canvas)))))
(mf/with-effect [show-text-editor? workspace-editor-state edition] (mf/with-effect [show-text-editor? workspace-editor-state edition]

View File

@ -1075,16 +1075,18 @@
(defn intersect-position-in-shape (defn intersect-position-in-shape
[id position] [id position]
(let [buffer (uuid/get-u32 id) (if (and wasm/context-initialized? (not @wasm/context-lost?))
result (let [buffer (uuid/get-u32 id)
(h/call wasm/internal-module "_intersect_position_in_shape" result
(aget buffer 0) (h/call wasm/internal-module "_intersect_position_in_shape"
(aget buffer 1) (aget buffer 0)
(aget buffer 2) (aget buffer 1)
(aget buffer 3) (aget buffer 2)
(:x position) (aget buffer 3)
(:y position))] (:x position)
(= result 1))) (:y position))]
(= result 1))
false))
(def render-finish (def render-finish
(letfn [(do-render [] (letfn [(do-render []