xref: /aosp_15_r20/external/skia/modules/canvaskit/WasmCommon.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2019 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef WasmCommon_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define WasmCommon_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten.h>
12*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten/bind.h>
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSpan.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
17*c8dee2aaSAndroid Build Coastguard Worker 
18*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
19*c8dee2aaSAndroid Build Coastguard Worker 
20*c8dee2aaSAndroid Build Coastguard Worker class SkData;
21*c8dee2aaSAndroid Build Coastguard Worker class SkCodec;
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker using namespace emscripten;
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker // Self-documenting types
26*c8dee2aaSAndroid Build Coastguard Worker using JSColor = int32_t;
27*c8dee2aaSAndroid Build Coastguard Worker using JSArray = emscripten::val;
28*c8dee2aaSAndroid Build Coastguard Worker using JSObject = emscripten::val;
29*c8dee2aaSAndroid Build Coastguard Worker using JSString = emscripten::val;
30*c8dee2aaSAndroid Build Coastguard Worker using SkPathOrNull = emscripten::val;
31*c8dee2aaSAndroid Build Coastguard Worker using TypedArray = emscripten::val;
32*c8dee2aaSAndroid Build Coastguard Worker using Uint8Array = emscripten::val;
33*c8dee2aaSAndroid Build Coastguard Worker using Uint16Array = emscripten::val;
34*c8dee2aaSAndroid Build Coastguard Worker using Uint32Array = emscripten::val;
35*c8dee2aaSAndroid Build Coastguard Worker using Float32Array = emscripten::val;
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker // If we are using C++ and EMSCRIPTEN_BINDINGS, we can't have primitive pointers in our function
38*c8dee2aaSAndroid Build Coastguard Worker // type signatures. (this gives an error message like "Cannot call foo due to unbound
39*c8dee2aaSAndroid Build Coastguard Worker // types Pi, Pf").  But, we can just pretend they are numbers and cast them to be pointers and
40*c8dee2aaSAndroid Build Coastguard Worker // the compiler is happy.
41*c8dee2aaSAndroid Build Coastguard Worker // These types refer to the TypedArray that the JS interface wrote into or will read out of.
42*c8dee2aaSAndroid Build Coastguard Worker // This doesn't stop us from using these as different types; e.g. a float* can be treated as an
43*c8dee2aaSAndroid Build Coastguard Worker // SkPoint* in some APIs.
44*c8dee2aaSAndroid Build Coastguard Worker using WASMPointerF32 = uintptr_t;
45*c8dee2aaSAndroid Build Coastguard Worker using WASMPointerI32 = uintptr_t;
46*c8dee2aaSAndroid Build Coastguard Worker using WASMPointerU8  = uintptr_t;
47*c8dee2aaSAndroid Build Coastguard Worker using WASMPointerU16 = uintptr_t;
48*c8dee2aaSAndroid Build Coastguard Worker using WASMPointerU32 = uintptr_t;
49*c8dee2aaSAndroid Build Coastguard Worker using WASMPointer = uintptr_t;
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker #define SPECIALIZE_JSARRAYTYPE(type, name)                  \
52*c8dee2aaSAndroid Build Coastguard Worker     template <> struct JSArrayType<type> {                  \
53*c8dee2aaSAndroid Build Coastguard Worker         static constexpr const char* const gName = name;    \
54*c8dee2aaSAndroid Build Coastguard Worker     }
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker template <typename T> struct JSArrayType {};
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker SPECIALIZE_JSARRAYTYPE( int8_t,    "Int8Array");
59*c8dee2aaSAndroid Build Coastguard Worker SPECIALIZE_JSARRAYTYPE(uint8_t,   "Uint8Array");
60*c8dee2aaSAndroid Build Coastguard Worker SPECIALIZE_JSARRAYTYPE( int16_t,  "Int16Array");
61*c8dee2aaSAndroid Build Coastguard Worker SPECIALIZE_JSARRAYTYPE(uint16_t, "Uint16Array");
62*c8dee2aaSAndroid Build Coastguard Worker SPECIALIZE_JSARRAYTYPE( int32_t,  "Int32Array");
63*c8dee2aaSAndroid Build Coastguard Worker SPECIALIZE_JSARRAYTYPE(uint32_t, "Uint32Array");
64*c8dee2aaSAndroid Build Coastguard Worker SPECIALIZE_JSARRAYTYPE(float,   "Float32Array");
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker #undef SPECIALIZE_JSARRAYTYPE
67*c8dee2aaSAndroid Build Coastguard Worker 
68*c8dee2aaSAndroid Build Coastguard Worker /**
69*c8dee2aaSAndroid Build Coastguard Worker  *  Create a typed-array (in the JS heap) and initialize it with the provided
70*c8dee2aaSAndroid Build Coastguard Worker  *  data (from the wasm heap).
71*c8dee2aaSAndroid Build Coastguard Worker  */
MakeTypedArray(int count,const T src[])72*c8dee2aaSAndroid Build Coastguard Worker template <typename T> TypedArray MakeTypedArray(int count, const T src[]) {
73*c8dee2aaSAndroid Build Coastguard Worker     emscripten::val length = emscripten::val(count);
74*c8dee2aaSAndroid Build Coastguard Worker     emscripten::val jarray = emscripten::val::global(JSArrayType<T>::gName).new_(count);
75*c8dee2aaSAndroid Build Coastguard Worker     jarray.call<void>("set", val(typed_memory_view(count, src)));
76*c8dee2aaSAndroid Build Coastguard Worker     return jarray;
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker SkColor4f ptrToSkColor4f(WASMPointerF32);
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkCodec> DecodeImageData(sk_sp<SkData>);
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker /**
84*c8dee2aaSAndroid Build Coastguard Worker  *  Gives read access to a JSArray
85*c8dee2aaSAndroid Build Coastguard Worker  *
86*c8dee2aaSAndroid Build Coastguard Worker  *  We explicitly use malloc/free (not new/delete) so this can be used with allocations from the JS
87*c8dee2aaSAndroid Build Coastguard Worker  *  side (ala CanvasKit.Malloc).
88*c8dee2aaSAndroid Build Coastguard Worker  */
89*c8dee2aaSAndroid Build Coastguard Worker template <typename T> class JSSpan {
90*c8dee2aaSAndroid Build Coastguard Worker public:
91*c8dee2aaSAndroid Build Coastguard Worker     // Note: Use of this constructor is 5-20x slower than manually copying the data on the JS side
92*c8dee2aaSAndroid Build Coastguard Worker     // and sending over a pointer, length, and boolean for the other constructor.
JSSpan(JSArray src)93*c8dee2aaSAndroid Build Coastguard Worker     JSSpan(JSArray src) {
94*c8dee2aaSAndroid Build Coastguard Worker         const size_t len = src["length"].as<size_t>();
95*c8dee2aaSAndroid Build Coastguard Worker         T* data;
96*c8dee2aaSAndroid Build Coastguard Worker 
97*c8dee2aaSAndroid Build Coastguard Worker         // If the buffer was allocated via CanvasKit' Malloc, we can peek directly at it!
98*c8dee2aaSAndroid Build Coastguard Worker         if (src["_ck"].isTrue()) {
99*c8dee2aaSAndroid Build Coastguard Worker             fOwned = false;
100*c8dee2aaSAndroid Build Coastguard Worker             data = reinterpret_cast<T*>(src["byteOffset"].as<size_t>());
101*c8dee2aaSAndroid Build Coastguard Worker         } else {
102*c8dee2aaSAndroid Build Coastguard Worker             fOwned = true;
103*c8dee2aaSAndroid Build Coastguard Worker             data = static_cast<T*>(sk_malloc_throw(len, sizeof(T)));
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker             // now actually copy into 'data'
106*c8dee2aaSAndroid Build Coastguard Worker             if (src.instanceof(emscripten::val::global(JSArrayType<T>::gName))) {
107*c8dee2aaSAndroid Build Coastguard Worker                 auto dst_view = emscripten::val(typed_memory_view(len, data));
108*c8dee2aaSAndroid Build Coastguard Worker                 dst_view.call<void>("set", src);
109*c8dee2aaSAndroid Build Coastguard Worker             } else {
110*c8dee2aaSAndroid Build Coastguard Worker                 for (size_t i = 0; i < len; ++i) {
111*c8dee2aaSAndroid Build Coastguard Worker                     data[i] = src[i].as<T>();
112*c8dee2aaSAndroid Build Coastguard Worker                 }
113*c8dee2aaSAndroid Build Coastguard Worker             }
114*c8dee2aaSAndroid Build Coastguard Worker         }
115*c8dee2aaSAndroid Build Coastguard Worker         fSpan = SkSpan(data, len);
116*c8dee2aaSAndroid Build Coastguard Worker     }
117*c8dee2aaSAndroid Build Coastguard Worker 
JSSpan(WASMPointer ptr,size_t len,bool takeOwnership)118*c8dee2aaSAndroid Build Coastguard Worker     JSSpan(WASMPointer ptr, size_t len, bool takeOwnership): fOwned(takeOwnership) {
119*c8dee2aaSAndroid Build Coastguard Worker         fSpan = SkSpan(reinterpret_cast<T*>(ptr), len);
120*c8dee2aaSAndroid Build Coastguard Worker     }
121*c8dee2aaSAndroid Build Coastguard Worker 
~JSSpan()122*c8dee2aaSAndroid Build Coastguard Worker     ~JSSpan() {
123*c8dee2aaSAndroid Build Coastguard Worker         if (fOwned) {
124*c8dee2aaSAndroid Build Coastguard Worker             sk_free(fSpan.data());
125*c8dee2aaSAndroid Build Coastguard Worker         }
126*c8dee2aaSAndroid Build Coastguard Worker     }
127*c8dee2aaSAndroid Build Coastguard Worker 
data()128*c8dee2aaSAndroid Build Coastguard Worker     const T* data() const { return fSpan.data(); }
size()129*c8dee2aaSAndroid Build Coastguard Worker     size_t size() const { return fSpan.size(); }
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker private:
132*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<T>   fSpan;
133*c8dee2aaSAndroid Build Coastguard Worker     bool        fOwned;
134*c8dee2aaSAndroid Build Coastguard Worker };
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker #endif
137