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