mirror of
https://github.com/penpot/penpot.git
synced 2026-04-27 20:28:11 +00:00
✨ Use binary fills to write data to wasm memory
This commit is contained in:
parent
8a58b9d459
commit
af99bd620c
@ -6,6 +6,7 @@
|
||||
|
||||
(ns app.common.types.fills
|
||||
(:require
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.types.color :as types.color]
|
||||
[app.common.types.fills.impl :as impl]
|
||||
@ -50,10 +51,6 @@
|
||||
(def check-fill
|
||||
(sm/check-fn schema:fill))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; HELPERS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; CONSTRUCTORS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@ -66,3 +63,48 @@
|
||||
(defn fills?
|
||||
[o]
|
||||
(impl/fills? o))
|
||||
|
||||
(defn coerce
|
||||
[o]
|
||||
(cond
|
||||
(nil? o)
|
||||
(impl/from-plain [])
|
||||
|
||||
(impl/fills? o)
|
||||
o
|
||||
|
||||
(vector? o)
|
||||
(impl/from-plain o)
|
||||
|
||||
:else
|
||||
(ex/raise :type :internal
|
||||
:code :invalid-type
|
||||
:hint (str "cannot coerce " (pr-str o) "to fills"))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; HELPERS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn assoc-fill
|
||||
[fills position fill]
|
||||
(if (nil? fills)
|
||||
(impl/from-plain [fill])
|
||||
(-> (coerce fills)
|
||||
(assoc position fill))))
|
||||
|
||||
(defn get-image-ids
|
||||
[fills]
|
||||
(if (vector? fills)
|
||||
(into #{}
|
||||
(comp (keep :fill-image)
|
||||
(map :id))
|
||||
fills)
|
||||
(impl/-get-image-ids fills)))
|
||||
|
||||
(defn get-byte-size
|
||||
[fills]
|
||||
(impl/-get-byte-size fills))
|
||||
|
||||
(defn write-to
|
||||
[fills buffer offset]
|
||||
(impl/-write-to fills buffer offset))
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
[app.common.buffer :as buf]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.math :as mth]
|
||||
[app.common.transit :as t]))
|
||||
|
||||
@ -35,6 +36,13 @@
|
||||
(def ^:private xf:take-fills
|
||||
(take MAX-FILLS))
|
||||
|
||||
(defprotocol IHeapWritable
|
||||
(-write-to [_ buffer offset] "write the content to the specified buffer")
|
||||
(-get-byte-size [_] "get byte size"))
|
||||
|
||||
(defprotocol IBinaryFills
|
||||
(-get-image-ids [_] "get referenced image ids"))
|
||||
|
||||
(defn- hex->rgb
|
||||
"Encode an hex string as rgb (int32)"
|
||||
[hex]
|
||||
@ -64,16 +72,16 @@
|
||||
n (unsigned-bit-shift-right n 24)]
|
||||
(mth/precision (/ (float n) 0xff) 2)))
|
||||
|
||||
(defn- write-solid-fill
|
||||
[offset buffer color alpha]
|
||||
(defn write-solid-fill
|
||||
[offset buffer opacity color]
|
||||
(buf/write-byte buffer (+ offset 0) 0x00)
|
||||
(buf/write-int buffer (+ offset 4)
|
||||
(-> (hex->rgb color)
|
||||
(rgb->rgba alpha)))
|
||||
(rgb->rgba opacity)))
|
||||
(+ offset FILL-BYTE-SIZE))
|
||||
|
||||
(defn- write-gradient-fill
|
||||
[offset buffer gradient opacity]
|
||||
(defn write-gradient-fill
|
||||
[offset buffer opacity gradient]
|
||||
(let [start-x (:start-x gradient)
|
||||
start-y (:start-y gradient)
|
||||
end-x (:end-x gradient)
|
||||
@ -108,10 +116,10 @@
|
||||
(+ offset' GRADIENT-STOP-SIZE)))
|
||||
(+ offset FILL-BYTE-SIZE)))))
|
||||
|
||||
(defn- write-image-fill
|
||||
(defn write-image-fill
|
||||
[offset buffer opacity image]
|
||||
(let [image-id (get image :id)
|
||||
image-width (get image :width)
|
||||
(let [image-id (get image :id)
|
||||
image-width (get image :width)
|
||||
image-height (get image :height)
|
||||
keep-ratio (get image :keep-aspect-ratio false)]
|
||||
(buf/write-byte buffer (+ offset 0) 0x03)
|
||||
@ -282,7 +290,20 @@
|
||||
|
||||
:cljs
|
||||
#_:clj-kondo/ignore
|
||||
(deftype Fills [size dbuffer mbuffer cache ^:mutable __hash]
|
||||
(deftype Fills [size dbuffer mbuffer image-ids cache ^:mutable __hash]
|
||||
|
||||
IHeapWritable
|
||||
(-get-byte-size [_]
|
||||
(- (.-byteLength dbuffer) 4))
|
||||
|
||||
(-write-to [_ heap offset]
|
||||
(let [buffer' (.-buffer ^js/DataView dbuffer)]
|
||||
(.set heap (js/Uint32Array. buffer' 4) offset)))
|
||||
|
||||
IBinaryFills
|
||||
(-get-image-ids [_]
|
||||
image-ids)
|
||||
|
||||
cljs.core/ISequential
|
||||
cljs.core/IEquiv
|
||||
(-equiv [this other]
|
||||
@ -368,8 +389,9 @@
|
||||
|
||||
(buf/write-byte dbuffer 0 total)
|
||||
|
||||
(loop [index 0]
|
||||
(when (< index total)
|
||||
(loop [index 0
|
||||
image-ids #{}]
|
||||
(if (< index total)
|
||||
(let [fill (nth fills index)
|
||||
doffset (+ 4 (* index FILL-BYTE-SIZE))
|
||||
moffset (* index METADATA-BYTE-SIZE)
|
||||
@ -377,23 +399,26 @@
|
||||
|
||||
(if-let [color (get fill :fill-color)]
|
||||
(do
|
||||
(write-solid-fill doffset dbuffer color opacity)
|
||||
(write-solid-fill doffset dbuffer opacity color)
|
||||
(write-metadata moffset mbuffer fill)
|
||||
(recur (inc index)))
|
||||
(recur (inc index) image-ids))
|
||||
(if-let [gradient (get fill :fill-color-gradient)]
|
||||
(do
|
||||
(write-gradient-fill doffset dbuffer gradient opacity)
|
||||
(write-gradient-fill doffset dbuffer opacity gradient)
|
||||
(write-metadata moffset mbuffer fill)
|
||||
(recur (inc index)))
|
||||
(recur (inc index) image-ids))
|
||||
(if-let [image (get fill :fill-image)]
|
||||
(do
|
||||
(write-image-fill doffset dbuffer opacity image)
|
||||
(write-metadata moffset mbuffer fill)
|
||||
(recur (inc index)))
|
||||
(recur (inc index))))))))
|
||||
(recur (inc index)
|
||||
(conj image-ids (get image :id))))
|
||||
(ex/raise :type :internal
|
||||
:code :invalid-fill
|
||||
:hint "found invalid fill on encoding fills to binary format")))))
|
||||
|
||||
#?(:cljs (Fills. total dbuffer mbuffer (weak-map/create) nil)
|
||||
:clj (Fills. total dbuffer mbuffer nil))))
|
||||
#?(:cljs (Fills. total dbuffer mbuffer image-ids (weak-map/create) nil)
|
||||
:clj (Fills. total dbuffer mbuffer nil))))))
|
||||
|
||||
(defn fills?
|
||||
[o]
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.types.fills :as types.fills]
|
||||
[app.common.types.fills.impl :as types.fills.impl]
|
||||
[app.common.types.path :as path]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.uuid :as uuid]
|
||||
@ -28,7 +29,6 @@
|
||||
[app.render-wasm.performance :as perf]
|
||||
[app.render-wasm.serializers :as sr]
|
||||
[app.render-wasm.serializers.color :as sr-clr]
|
||||
[app.render-wasm.serializers.fills :as sr-fills]
|
||||
[app.render-wasm.wasm :as wasm]
|
||||
[app.util.debug :as dbg]
|
||||
[app.util.functions :as fns]
|
||||
@ -201,6 +201,9 @@
|
||||
(rx/map :body)
|
||||
(rx/mapcat wapi/read-file-as-array-buffer)
|
||||
(rx/map (fn [image]
|
||||
;; FIXME use bigger heap ptr size if it
|
||||
;; is possible (if image size modulo
|
||||
;; permits it)
|
||||
(let [size (.-byteLength image)
|
||||
offset (mem/alloc-bytes size)
|
||||
heap (mem/get-heap-u8)
|
||||
@ -248,28 +251,19 @@
|
||||
[shape-id fills]
|
||||
(if (empty? fills)
|
||||
(h/call wasm/internal-module "_clear_shape_fills")
|
||||
(let [fills (take types.fills/MAX-FILLS fills)
|
||||
image-fills (filter :fill-image fills)
|
||||
offset (mem/alloc-bytes (* (count fills) sr-fills/FILL-BYTE-SIZE))
|
||||
heap (mem/get-heap-u8)
|
||||
dview (js/DataView. (.-buffer heap))]
|
||||
(let [fills (types.fills/coerce fills)
|
||||
offset (mem/alloc-bytes-32 (types.fills/get-byte-size fills))
|
||||
heap (mem/get-heap-u32)]
|
||||
|
||||
;; write fill data to heap
|
||||
(loop [fills (seq fills)
|
||||
current-offset offset]
|
||||
(when-not (empty? fills)
|
||||
(let [fill (first fills)
|
||||
new-offset (sr-fills/write-fill! current-offset dview fill)]
|
||||
(recur (rest fills) new-offset))))
|
||||
;; write fills to the heap
|
||||
(types.fills/write-to fills heap offset)
|
||||
|
||||
;; send fills to wasm
|
||||
(h/call wasm/internal-module "_set_shape_fills")
|
||||
|
||||
;; load images for image fills if not cached
|
||||
(keep (fn [fill]
|
||||
(let [image (:fill-image fill)
|
||||
id (dm/get-prop image :id)
|
||||
buffer (uuid/get-u32 id)
|
||||
(keep (fn [id]
|
||||
(let [buffer (uuid/get-u32 id)
|
||||
cached-image? (h/call wasm/internal-module "_is_image_cached"
|
||||
(aget buffer 0)
|
||||
(aget buffer 1)
|
||||
@ -277,7 +271,8 @@
|
||||
(aget buffer 3))]
|
||||
(when (zero? cached-image?)
|
||||
(fetch-image shape-id id))))
|
||||
image-fills))))
|
||||
|
||||
(types.fills/get-image-ids fills)))))
|
||||
|
||||
(defn set-shape-strokes
|
||||
[shape-id strokes]
|
||||
@ -292,7 +287,7 @@
|
||||
style (-> stroke :stroke-style sr/translate-stroke-style)
|
||||
cap-start (-> stroke :stroke-cap-start sr/translate-stroke-cap)
|
||||
cap-end (-> stroke :stroke-cap-end sr/translate-stroke-cap)
|
||||
offset (mem/alloc-bytes sr-fills/FILL-BYTE-SIZE)
|
||||
offset (mem/alloc-bytes types.fills.impl/FILL-BYTE-SIZE)
|
||||
heap (mem/get-heap-u8)
|
||||
dview (js/DataView. (.-buffer heap))]
|
||||
(case align
|
||||
@ -303,23 +298,21 @@
|
||||
(cond
|
||||
(some? gradient)
|
||||
(do
|
||||
(sr-fills/write-gradient-fill! offset dview gradient opacity)
|
||||
(types.fills.impl/write-gradient-fill offset dview opacity gradient)
|
||||
(h/call wasm/internal-module "_add_shape_stroke_fill"))
|
||||
|
||||
(some? image)
|
||||
(let [image-id (dm/get-prop image :id)
|
||||
buffer (uuid/get-u32 image-id)
|
||||
cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))]
|
||||
(sr-fills/write-image-fill! offset dview image-id opacity
|
||||
(dm/get-prop image :width)
|
||||
(dm/get-prop image :height))
|
||||
(types.fills.impl/write-image-fill offset dview opacity image)
|
||||
(h/call wasm/internal-module "_add_shape_stroke_fill")
|
||||
(when (== cached-image? 0)
|
||||
(fetch-image shape-id image-id)))
|
||||
|
||||
(some? color)
|
||||
(do
|
||||
(sr-fills/write-solid-fill! offset dview (sr-clr/hex->u32argb color opacity))
|
||||
(types.fills.impl/write-solid-fill offset dview opacity color)
|
||||
(h/call wasm/internal-module "_add_shape_stroke_fill")))))
|
||||
strokes))
|
||||
|
||||
|
||||
@ -7,12 +7,11 @@
|
||||
(ns app.render-wasm.api.texts
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.fills.impl :as types.fills.impl]
|
||||
[app.render-wasm.api.fonts :as f]
|
||||
[app.render-wasm.helpers :as h]
|
||||
[app.render-wasm.mem :as mem]
|
||||
[app.render-wasm.serializers :as sr]
|
||||
[app.render-wasm.serializers.color :as sr-clr]
|
||||
[app.render-wasm.serializers.fills :as sr-fills]
|
||||
[app.render-wasm.wasm :as wasm]))
|
||||
|
||||
(defn utf8->buffer [text]
|
||||
@ -26,21 +25,18 @@
|
||||
color (:fill-color fill)
|
||||
gradient (:fill-color-gradient fill)
|
||||
image (:fill-image fill)]
|
||||
|
||||
(cond
|
||||
(some? color)
|
||||
(sr-fills/write-solid-fill! offset dview (sr-clr/hex->u32argb color opacity))
|
||||
(types.fills.impl/write-solid-fill offset dview opacity color)
|
||||
|
||||
(some? gradient)
|
||||
(sr-fills/write-gradient-fill! offset dview gradient opacity)
|
||||
(types.fills.impl/write-gradient-fill offset dview opacity gradient)
|
||||
|
||||
(some? image)
|
||||
(sr-fills/write-image-fill! offset dview
|
||||
(dm/get-prop image :id)
|
||||
opacity
|
||||
(dm/get-prop image :width)
|
||||
(dm/get-prop image :height)))
|
||||
(types.fills.impl/write-image-fill offset dview opacity image))
|
||||
|
||||
(+ offset sr-fills/FILL-BYTE-SIZE)))
|
||||
(+ offset types.fills.impl/FILL-BYTE-SIZE)))
|
||||
current-offset
|
||||
fills))
|
||||
|
||||
@ -56,7 +52,7 @@
|
||||
num-leaves (count leaves)
|
||||
paragraph-attr-size 48
|
||||
total-fills (total-fills-count leaves)
|
||||
total-fills-size (* sr-fills/FILL-BYTE-SIZE total-fills)
|
||||
total-fills-size (* types.fills.impl/FILL-BYTE-SIZE total-fills)
|
||||
leaf-attr-size 56
|
||||
metadata-size (+ paragraph-attr-size (* num-leaves leaf-attr-size) total-fills-size)
|
||||
text-buffer (utf8->buffer text)
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
(ns app.render-wasm.serializers.fills
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.fills :as types.fills]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.render-wasm.serializers.color :as clr]))
|
||||
|
||||
(def ^:private GRADIENT-STOP-SIZE 8)
|
||||
|
||||
(def GRADIENT-BYTE-SIZE 156)
|
||||
(def SOLID-BYTE-SIZE 4)
|
||||
(def IMAGE-BYTE-SIZE 28)
|
||||
|
||||
;; FIXME: get it from the wasm module
|
||||
(def FILL-BYTE-SIZE (+ 4 (max GRADIENT-BYTE-SIZE IMAGE-BYTE-SIZE SOLID-BYTE-SIZE)))
|
||||
|
||||
|
||||
(defn write-solid-fill!
|
||||
[offset dview argb]
|
||||
(.setUint8 dview offset 0x00 true)
|
||||
(.setUint32 dview (+ offset 4) argb true)
|
||||
(+ offset FILL-BYTE-SIZE))
|
||||
|
||||
(defn write-image-fill!
|
||||
[offset dview id opacity width height]
|
||||
(let [uuid-buffer (uuid/get-u32 id)]
|
||||
(.setUint8 dview offset 0x03 true)
|
||||
(.setUint32 dview (+ offset 4) (aget uuid-buffer 0) true)
|
||||
(.setUint32 dview (+ offset 8) (aget uuid-buffer 1) true)
|
||||
(.setUint32 dview (+ offset 12) (aget uuid-buffer 2) true)
|
||||
(.setUint32 dview (+ offset 16) (aget uuid-buffer 3) true)
|
||||
(.setFloat32 dview (+ offset 20) opacity true)
|
||||
(.setInt32 dview (+ offset 24) width true)
|
||||
(.setInt32 dview (+ offset 28) height true)
|
||||
(+ offset FILL-BYTE-SIZE)))
|
||||
|
||||
(defn write-gradient-fill!
|
||||
[offset dview gradient opacity]
|
||||
(let [start-x (:start-x gradient)
|
||||
start-y (:start-y gradient)
|
||||
end-x (:end-x gradient)
|
||||
end-y (:end-y gradient)
|
||||
width (or (:width gradient) 0)
|
||||
stops (take types.fills/MAX-GRADIENT-STOPS (:stops gradient))
|
||||
type (if (= (:type gradient) :linear) 0x01 0x02)]
|
||||
(.setUint8 dview offset type true)
|
||||
(.setFloat32 dview (+ offset 4) start-x true)
|
||||
(.setFloat32 dview (+ offset 8) start-y true)
|
||||
(.setFloat32 dview (+ offset 12) end-x true)
|
||||
(.setFloat32 dview (+ offset 16) end-y true)
|
||||
(.setFloat32 dview (+ offset 20) opacity true)
|
||||
(.setFloat32 dview (+ offset 24) width true)
|
||||
(.setUint8 dview (+ offset 28) (count stops) true)
|
||||
(loop [stops (seq stops) loop-offset (+ offset 32)]
|
||||
(if (empty? stops)
|
||||
(+ offset FILL-BYTE-SIZE)
|
||||
(let [stop (first stops)
|
||||
hex-color (:color stop)
|
||||
stop-opacity (:opacity stop)
|
||||
argb (clr/hex->u32argb hex-color stop-opacity)
|
||||
stop-offset (:offset stop)]
|
||||
(.setUint32 dview loop-offset argb true)
|
||||
(.setFloat32 dview (+ loop-offset 4) stop-offset true)
|
||||
(recur (rest stops) (+ loop-offset GRADIENT-STOP-SIZE)))))))
|
||||
|
||||
(defn write-fill!
|
||||
[offset dview fill]
|
||||
(let [opacity (or (:fill-opacity fill) 1.0)
|
||||
color (:fill-color fill)
|
||||
gradient (:fill-color-gradient fill)
|
||||
image (:fill-image fill)]
|
||||
(cond
|
||||
(some? color)
|
||||
(write-solid-fill! offset dview (clr/hex->u32argb color opacity))
|
||||
|
||||
(some? gradient)
|
||||
(write-gradient-fill! offset dview gradient opacity)
|
||||
|
||||
(some? image)
|
||||
(let [id (dm/get-prop image :id)]
|
||||
(write-image-fill! offset dview id opacity (dm/get-prop image :width) (dm/get-prop image :height))))))
|
||||
Loading…
x
Reference in New Issue
Block a user