Merge pull request #5190 from penpot/ladybenko-9046-emscripten

🎉 Switch new renderer to Emscripten (from wasm-bindgen)
This commit is contained in:
Belén Albeza 2024-10-23 17:44:44 +02:00 committed by GitHub
commit 09e1bac41c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 1009 additions and 457 deletions

View file

@ -21,7 +21,6 @@
"build:storybook": "yarn run build:storybook:assets && yarn run build:storybook:cljs && storybook build",
"build:storybook:assets": "node ./scripts/build-storybook-assets.js",
"build:storybook:cljs": "clojure -M:dev:shadow-cljs compile storybook",
"build:renderer": "yarn run wasm-pack build ./renderer --target web --out-dir ../resources/public/js/renderer --release",
"build:app": "clojure -M:dev:shadow-cljs release main",
"e2e:server": "node ./scripts/e2e-server.js",
"fmt:clj": "cljfmt fix --parallel=true src/ test/",

View file

@ -1,5 +0,0 @@
target/
debug/
**/*.rs.bk

View file

@ -1,324 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "cc"
version = "1.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
"cfg-if",
"wasm-bindgen",
]
[[package]]
name = "js-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "minicov"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169"
dependencies = [
"cc",
"walkdir",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "renderer"
version = "0.1.0"
dependencies = [
"wasm-bindgen",
"wasm-bindgen-test",
]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
version = "2.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
"cfg-if",
"once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
name = "wasm-bindgen-test"
version = "0.3.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9"
dependencies = [
"console_error_panic_hook",
"js-sys",
"minicov",
"scoped-tls",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-test-macro",
]
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "web-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View file

@ -1,19 +0,0 @@
[package]
name = "renderer"
version = "0.1.0"
edition = "2021"
repository = "https://github.com/penpot/penpot"
license-file = "../../../../LICENSE"
description = "Wasm-based canvas renderer for Penpot"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.93"
[profile.release]
opt-level = "s"
[dev-dependencies]
wasm-bindgen-test = "0.3.43"

View file

@ -1,36 +0,0 @@
use wasm_bindgen::prelude::*;
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
#[wasm_bindgen]
pub fn print(msg: &str) {
log(msg);
}
#[cfg(test)]
mod tests {
use super::*;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
#[wasm_bindgen_test]
fn it_works_in_wasm() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

View file

@ -75,7 +75,6 @@
[app.main.repo :as rp]
[app.main.streams :as ms]
[app.main.worker :as uw]
[app.renderer-v2 :as renderer]
[app.util.dom :as dom]
[app.util.globals :as ug]
[app.util.http :as http]
@ -357,8 +356,8 @@
(dcm/retrieve-comment-threads file-id)
(fetch-bundle project-id file-id))
(when (contains? cf/flags :renderer-v2)
(rx/of (renderer/init)))
;; (when (contains? cf/flags :renderer-v2)
;; (rx/of (renderer/init)))
(->> stream
(rx/filter dch/commit?)

View file

@ -8,7 +8,6 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.data.macros :as dm]
[app.config :as cf]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.persistence :as dps]
@ -32,7 +31,6 @@
[app.main.ui.workspace.sidebar.collapsable-button :refer [collapsed-button]]
[app.main.ui.workspace.sidebar.history :refer [history-toolbox]]
[app.main.ui.workspace.viewport :refer [viewport]]
[app.renderer-v2 :as renderer]
[app.util.debug :as dbg]
[app.util.dom :as dom]
[app.util.globals :as globals]
@ -204,10 +202,6 @@
(ntf/hide)
(dw/finalize-file project-id file-id))))
(mf/with-effect [file-ready?]
(when (and file-ready? (contains? cf/flags :renderer-v2))
(renderer/print-msg "hello from wasm fn!")))
[:& (mf/provider ctx/current-file-id) {:value file-id}
[:& (mf/provider ctx/current-project-id) {:value project-id}
[:& (mf/provider ctx/current-team-id) {:value team-id}

View file

@ -50,8 +50,10 @@
[app.main.ui.workspace.viewport.utils :as utils]
[app.main.ui.workspace.viewport.viewport-ref :refer [create-viewport-ref]]
[app.main.ui.workspace.viewport.widgets :as widgets]
[app.render-wasm :as render.wasm]
[app.util.debug :as dbg]
[beicon.v2.core :as rx]
[promesa.core :as p]
[rumext.v2 :as mf]))
;; --- Viewport
@ -137,6 +139,9 @@
[viewport-ref
on-viewport-ref] (create-viewport-ref)
canvas-ref (mf/use-ref nil)
canvas-init (mf/use-ref false)
;; VARS
disable-paste (mf/use-var false)
in-viewport? (mf/use-var false)
@ -269,6 +274,21 @@
rule-area-size (/ rulers/ruler-area-size zoom)]
(when ^boolean render.wasm/enabled?
(mf/with-effect []
(when-let [canvas (mf/ref-val canvas-ref)]
(->> render.wasm/module
(p/fmap (fn [ready?]
(when ready?
(mf/set-ref-val! canvas-init true)
(render.wasm/assign-canvas canvas)))))
(fn []
(render.wasm/clear-canvas))))
(mf/with-effect [vbox' base-objects]
(when (mf/ref-val canvas-init)
(render.wasm/draw-objects base-objects zoom vbox'))))
(hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool drawing-path?)
(hooks/setup-viewport-size vport viewport-ref)
(hooks/setup-cursor cursor alt? mod? space? panning drawing-tool drawing-path? node-editing? z? read-only?)
@ -312,50 +332,59 @@
:layout layout
:viewport-ref viewport-ref}])]
[:svg
{:id "render"
:class (stl/css :render-shapes)
:xmlns "http://www.w3.org/2000/svg"
:xmlnsXlink "http://www.w3.org/1999/xlink"
:xmlns:penpot "https://penpot.app/xmlns"
:preserveAspectRatio "xMidYMid meet"
:key (str "render" page-id)
:width (:width vport 0)
:height (:height vport 0)
:view-box (utils/format-viewbox vbox)
:style {:background-color background
:pointer-events "none"}
:fill "none"}
(if ^boolean render.wasm/enabled?
[:canvas {:id "render"
:ref canvas-ref
:class (stl/css :render-shapes)
:key (dm/str "render" page-id)
:width (:width vport 0)
:height (:height vport 0)
:style {:background-color background
:pointer-events "none"}}]
[:svg
{:id "render"
:class (stl/css :render-shapes)
:xmlns "http://www.w3.org/2000/svg"
:xmlnsXlink "http://www.w3.org/1999/xlink"
:xmlns:penpot "https://penpot.app/xmlns"
:preserveAspectRatio "xMidYMid meet"
:key (str "render" page-id)
:width (:width vport 0)
:height (:height vport 0)
:view-box (utils/format-viewbox vbox)
:style {:background-color background
:pointer-events "none"}
:fill "none"}
[:defs
[:linearGradient {:id "frame-placeholder-gradient"}
[:animateTransform
{:attributeName "gradientTransform"
:type "translate"
:from "-1 0"
:to "1 0"
:dur "2s"
:repeatCount "indefinite"}]
[:stop {:offset "0%" :stop-color (str "color-mix(in srgb-linear, " background " 90%, #777)") :stop-opacity 1}]
[:stop {:offset "50%" :stop-color (str "color-mix(in srgb-linear, " background " 80%, #777)") :stop-opacity 1}]
[:stop {:offset "100%" :stop-color (str "color-mix(in srgb-linear, " background " 90%, #777)") :stop-opacity 1}]]]
[:defs
[:linearGradient {:id "frame-placeholder-gradient"}
[:animateTransform
{:attributeName "gradientTransform"
:type "translate"
:from "-1 0"
:to "1 0"
:dur "2s"
:repeatCount "indefinite"}]
[:stop {:offset "0%" :stop-color (str "color-mix(in srgb-linear, " background " 90%, #777)") :stop-opacity 1}]
[:stop {:offset "50%" :stop-color (str "color-mix(in srgb-linear, " background " 80%, #777)") :stop-opacity 1}]
[:stop {:offset "100%" :stop-color (str "color-mix(in srgb-linear, " background " 90%, #777)") :stop-opacity 1}]]]
(when (dbg/enabled? :show-export-metadata)
[:& use/export-page {:page page}])
(when (dbg/enabled? :show-export-metadata)
[:& use/export-page {:page page}])
;; We need a "real" background shape so layer transforms work properly in firefox
[:rect {:width (:width vbox 0)
:height (:height vbox 0)
:x (:x vbox 0)
:y (:y vbox 0)
:fill background}]
;; We need a "real" background shape so layer transforms work properly in firefox
[:rect {:width (:width vbox 0)
:height (:height vbox 0)
:x (:x vbox 0)
:y (:y vbox 0)
:fill background}]
[:& (mf/provider ctx/current-vbox) {:value vbox'}
[:& (mf/provider use/include-metadata-ctx) {:value (dbg/enabled? :show-export-metadata)}
;; Render root shape
[:& shapes/root-shape {:key page-id
:objects base-objects
:active-frames @active-frames}]]]]
[:& (mf/provider ctx/current-vbox) {:value vbox'}
[:& (mf/provider use/include-metadata-ctx) {:value (dbg/enabled? :show-export-metadata)}
;; Render root shape
[:& shapes/root-shape {:key page-id
:objects base-objects
:active-frames @active-frames}]]]])
[:svg.viewport-controls
{:xmlns "http://www.w3.org/2000/svg"

View file

@ -0,0 +1,88 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.render-wasm
"A WASM based render API"
(:require
[app.common.data.macros :as dm]
[app.config :as cf]
[promesa.core :as p]))
(def enabled?
(contains? cf/flags :render-wasm))
(defonce ^:dynamic internal-module #js {})
(defonce ^:dynamic internal-gpu-state #js {})
(defn draw-objects [objects zoom vbox]
(let [draw-rect (unchecked-get internal-module "_draw_rect")
translate (unchecked-get internal-module "_translate")
reset-canvas (unchecked-get internal-module "_reset_canvas")
scale (unchecked-get internal-module "_scale")
flush (unchecked-get internal-module "_flush")
gpu-state internal-gpu-state]
(js/requestAnimationFrame
(fn []
(reset-canvas gpu-state)
(scale gpu-state zoom zoom)
(let [x (dm/get-prop vbox :x)
y (dm/get-prop vbox :y)]
(translate gpu-state (- x) (- y)))
(run! (fn [shape]
(let [selrect (dm/get-prop shape :selrect)
x1 (dm/get-prop selrect :x1)
y1 (dm/get-prop selrect :y1)
x2 (dm/get-prop selrect :x2)
y2 (dm/get-prop selrect :y2)]
(draw-rect gpu-state x1 y1 x2 y2)))
(vals objects))
(flush gpu-state)))))
(def canvas-options
#js {:antialias true
:depth true
:stencil true
:alpha true})
(defn clear-canvas
[]
;; TODO: perform corresponding cleaning
)
(defn assign-canvas
[canvas]
(let [gl (unchecked-get internal-module "GL")
init-fn (unchecked-get internal-module "_init")
context (.getContext ^js canvas "webgl2" canvas-options)
;; Register the context with emscripten
handle (.registerContext ^js gl context #js {"majorVersion" 2})
_ (.makeContextCurrent ^js gl handle)
;; Initialize Skia
state (init-fn (.-width ^js canvas)
(.-height ^js canvas))]
(set! (.-width canvas) (.-clientWidth ^js canvas))
(set! (.-height canvas) (.-clientHeight ^js canvas))
(set! internal-gpu-state state)))
(defonce module
(->> (js/dynamicImport "/js/render_wasm.js")
(p/mcat (fn [module]
(let [default (unchecked-get module "default")]
(default))))
(p/fmap (fn [module]
(set! internal-module module)
true))
(p/merr (fn [cause]
(js/console.error cause)
(p/resolved false)))))

View file

@ -1,38 +0,0 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.renderer-v2
(:require
[app.config :as cf]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
(defonce internal-module #js {})
(defn on-module-loaded
[module']
(let [init-fn (.-default ^js module')]
(->> (rx/from (init-fn))
(rx/map (constantly module')))))
(defn- on-module-initialized
[module]
(set! internal-module module))
(defn print-msg [msg]
(let [print-fn (.-print internal-module)]
(print-fn msg)))
(defn init
[]
(ptk/reify ::init
ptk/WatchEvent
(watch [_ _ _]
(let [module-uri (assoc cf/public-uri :path "/js/renderer/renderer.js")]
(->> (rx/from (js/dynamicImport (str module-uri)))
(rx/mapcat on-module-loaded)
(rx/tap on-module-initialized)
(rx/ignore))))))