@shopify/react-native-skia 2.4.15 → 2.4.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/android/CMakeLists.txt +69 -0
  2. package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java +19 -7
  3. package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseViewManager.java +7 -0
  4. package/apple/RNSkApplePlatformContext.mm +4 -0
  5. package/cpp/api/JsiSkApi.h +31 -0
  6. package/cpp/api/JsiSkImageFactory.h +69 -1
  7. package/cpp/api/JsiSkImageFilter.h +1 -0
  8. package/cpp/api/JsiSkPath.h +1 -1
  9. package/cpp/jsi/RuntimeAwareCache.h +0 -2
  10. package/cpp/jsi2/EnumMapper.h +45 -0
  11. package/cpp/jsi2/JSIConverter.h +468 -0
  12. package/cpp/jsi2/NativeObject.h +598 -0
  13. package/cpp/jsi2/Promise.cpp +44 -0
  14. package/cpp/jsi2/Promise.h +35 -0
  15. package/cpp/rnskia/RNDawnContext.h +114 -0
  16. package/cpp/rnskia/RNSkManager.cpp +41 -1
  17. package/cpp/rnwgpu/ArrayBuffer.h +68 -0
  18. package/cpp/rnwgpu/api/Convertors.h +761 -0
  19. package/cpp/rnwgpu/api/External.h +12 -0
  20. package/cpp/rnwgpu/api/GPU.cpp +129 -0
  21. package/cpp/rnwgpu/api/GPU.h +57 -0
  22. package/cpp/rnwgpu/api/GPUAdapter.cpp +178 -0
  23. package/cpp/rnwgpu/api/GPUAdapter.h +59 -0
  24. package/cpp/rnwgpu/api/GPUAdapterInfo.h +57 -0
  25. package/cpp/rnwgpu/api/GPUBindGroup.cpp +3 -0
  26. package/cpp/rnwgpu/api/GPUBindGroup.h +51 -0
  27. package/cpp/rnwgpu/api/GPUBindGroupLayout.h +52 -0
  28. package/cpp/rnwgpu/api/GPUBuffer.cpp +97 -0
  29. package/cpp/rnwgpu/api/GPUBuffer.h +87 -0
  30. package/cpp/rnwgpu/api/GPUCommandBuffer.h +45 -0
  31. package/cpp/rnwgpu/api/GPUCommandEncoder.cpp +179 -0
  32. package/cpp/rnwgpu/api/GPUCommandEncoder.h +111 -0
  33. package/cpp/rnwgpu/api/GPUCompilationInfo.h +79 -0
  34. package/cpp/rnwgpu/api/GPUCompilationMessage.h +36 -0
  35. package/cpp/rnwgpu/api/GPUComputePassEncoder.cpp +60 -0
  36. package/cpp/rnwgpu/api/GPUComputePassEncoder.h +85 -0
  37. package/cpp/rnwgpu/api/GPUComputePipeline.cpp +12 -0
  38. package/cpp/rnwgpu/api/GPUComputePipeline.h +60 -0
  39. package/cpp/rnwgpu/api/GPUDevice.cpp +434 -0
  40. package/cpp/rnwgpu/api/GPUDevice.h +174 -0
  41. package/cpp/rnwgpu/api/GPUDeviceLostInfo.cpp +7 -0
  42. package/cpp/rnwgpu/api/GPUDeviceLostInfo.h +40 -0
  43. package/cpp/rnwgpu/api/GPUError.h +35 -0
  44. package/cpp/rnwgpu/api/GPUExtent3D.h +66 -0
  45. package/cpp/rnwgpu/api/GPUExternalTexture.h +45 -0
  46. package/cpp/rnwgpu/api/GPUFeatures.h +212 -0
  47. package/cpp/rnwgpu/api/GPUInternalError.h +31 -0
  48. package/cpp/rnwgpu/api/GPUOrigin2D.h +55 -0
  49. package/cpp/rnwgpu/api/GPUOrigin3D.h +62 -0
  50. package/cpp/rnwgpu/api/GPUOutOfMemoryError.h +33 -0
  51. package/cpp/rnwgpu/api/GPUPipelineLayout.h +45 -0
  52. package/cpp/rnwgpu/api/GPUQuerySet.cpp +11 -0
  53. package/cpp/rnwgpu/api/GPUQuerySet.h +73 -0
  54. package/cpp/rnwgpu/api/GPUQueue.cpp +169 -0
  55. package/cpp/rnwgpu/api/GPUQueue.h +84 -0
  56. package/cpp/rnwgpu/api/GPURenderBundle.h +44 -0
  57. package/cpp/rnwgpu/api/GPURenderBundleEncoder.cpp +131 -0
  58. package/cpp/rnwgpu/api/GPURenderBundleEncoder.h +110 -0
  59. package/cpp/rnwgpu/api/GPURenderPassEncoder.cpp +165 -0
  60. package/cpp/rnwgpu/api/GPURenderPassEncoder.h +130 -0
  61. package/cpp/rnwgpu/api/GPURenderPipeline.cpp +13 -0
  62. package/cpp/rnwgpu/api/GPURenderPipeline.h +61 -0
  63. package/cpp/rnwgpu/api/GPUSampler.h +44 -0
  64. package/cpp/rnwgpu/api/GPUShaderModule.cpp +51 -0
  65. package/cpp/rnwgpu/api/GPUShaderModule.h +66 -0
  66. package/cpp/rnwgpu/api/GPUSupportedLimits.cpp +129 -0
  67. package/cpp/rnwgpu/api/GPUSupportedLimits.h +131 -0
  68. package/cpp/rnwgpu/api/GPUTexture.cpp +47 -0
  69. package/cpp/rnwgpu/api/GPUTexture.h +150 -0
  70. package/cpp/rnwgpu/api/GPUTextureView.h +44 -0
  71. package/cpp/rnwgpu/api/GPUValidationError.h +32 -0
  72. package/cpp/rnwgpu/api/descriptors/GPUBindGroupDescriptor.h +64 -0
  73. package/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h +71 -0
  74. package/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutDescriptor.h +56 -0
  75. package/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutEntry.h +97 -0
  76. package/cpp/rnwgpu/api/descriptors/GPUBlendComponent.h +57 -0
  77. package/cpp/rnwgpu/api/descriptors/GPUBlendState.h +52 -0
  78. package/cpp/rnwgpu/api/descriptors/GPUBufferBinding.h +56 -0
  79. package/cpp/rnwgpu/api/descriptors/GPUBufferBindingLayout.h +56 -0
  80. package/cpp/rnwgpu/api/descriptors/GPUBufferDescriptor.h +59 -0
  81. package/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h +39 -0
  82. package/cpp/rnwgpu/api/descriptors/GPUColor.h +66 -0
  83. package/cpp/rnwgpu/api/descriptors/GPUColorTargetState.h +58 -0
  84. package/cpp/rnwgpu/api/descriptors/GPUColorWrite.h +29 -0
  85. package/cpp/rnwgpu/api/descriptors/GPUCommandBufferDescriptor.h +45 -0
  86. package/cpp/rnwgpu/api/descriptors/GPUCommandEncoderDescriptor.h +45 -0
  87. package/cpp/rnwgpu/api/descriptors/GPUComputePassDescriptor.h +56 -0
  88. package/cpp/rnwgpu/api/descriptors/GPUComputePassTimestampWrites.h +58 -0
  89. package/cpp/rnwgpu/api/descriptors/GPUComputePipelineDescriptor.h +67 -0
  90. package/cpp/rnwgpu/api/descriptors/GPUDepthStencilState.h +103 -0
  91. package/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h +99 -0
  92. package/cpp/rnwgpu/api/descriptors/GPUExternalTextureBindingLayout.h +38 -0
  93. package/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +71 -0
  94. package/cpp/rnwgpu/api/descriptors/GPUFragmentState.h +73 -0
  95. package/cpp/rnwgpu/api/descriptors/GPUImageCopyBuffer.h +62 -0
  96. package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +62 -0
  97. package/cpp/rnwgpu/api/descriptors/GPUImageCopyTexture.h +65 -0
  98. package/cpp/rnwgpu/api/descriptors/GPUImageCopyTextureTagged.h +81 -0
  99. package/cpp/rnwgpu/api/descriptors/GPUImageDataLayout.h +54 -0
  100. package/cpp/rnwgpu/api/descriptors/GPUMapMode.h +22 -0
  101. package/cpp/rnwgpu/api/descriptors/GPUMultisampleState.h +54 -0
  102. package/cpp/rnwgpu/api/descriptors/GPUPipelineLayoutDescriptor.h +57 -0
  103. package/cpp/rnwgpu/api/descriptors/GPUPrimitiveState.h +69 -0
  104. package/cpp/rnwgpu/api/descriptors/GPUProgrammableStage.h +61 -0
  105. package/cpp/rnwgpu/api/descriptors/GPUQuerySetDescriptor.h +55 -0
  106. package/cpp/rnwgpu/api/descriptors/GPUQueueDescriptor.h +43 -0
  107. package/cpp/rnwgpu/api/descriptors/GPURenderBundleDescriptor.h +45 -0
  108. package/cpp/rnwgpu/api/descriptors/GPURenderBundleEncoderDescriptor.h +80 -0
  109. package/cpp/rnwgpu/api/descriptors/GPURenderPassColorAttachment.h +81 -0
  110. package/cpp/rnwgpu/api/descriptors/GPURenderPassDepthStencilAttachment.h +101 -0
  111. package/cpp/rnwgpu/api/descriptors/GPURenderPassDescriptor.h +92 -0
  112. package/cpp/rnwgpu/api/descriptors/GPURenderPassTimestampWrites.h +58 -0
  113. package/cpp/rnwgpu/api/descriptors/GPURenderPipelineDescriptor.h +103 -0
  114. package/cpp/rnwgpu/api/descriptors/GPURequestAdapterOptions.h +51 -0
  115. package/cpp/rnwgpu/api/descriptors/GPUSamplerBindingLayout.h +45 -0
  116. package/cpp/rnwgpu/api/descriptors/GPUSamplerDescriptor.h +110 -0
  117. package/cpp/rnwgpu/api/descriptors/GPUShaderModuleCompilationHint.h +60 -0
  118. package/cpp/rnwgpu/api/descriptors/GPUShaderModuleDescriptor.h +62 -0
  119. package/cpp/rnwgpu/api/descriptors/GPUShaderStage.h +25 -0
  120. package/cpp/rnwgpu/api/descriptors/GPUStencilFaceState.h +64 -0
  121. package/cpp/rnwgpu/api/descriptors/GPUStorageTextureBindingLayout.h +59 -0
  122. package/cpp/rnwgpu/api/descriptors/GPUTextureBindingLayout.h +59 -0
  123. package/cpp/rnwgpu/api/descriptors/GPUTextureDescriptor.h +91 -0
  124. package/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h +29 -0
  125. package/cpp/rnwgpu/api/descriptors/GPUTextureViewDescriptor.h +91 -0
  126. package/cpp/rnwgpu/api/descriptors/GPUUncapturedErrorEventInit.h +64 -0
  127. package/cpp/rnwgpu/api/descriptors/GPUVertexAttribute.h +53 -0
  128. package/cpp/rnwgpu/api/descriptors/GPUVertexBufferLayout.h +62 -0
  129. package/cpp/rnwgpu/api/descriptors/GPUVertexState.h +73 -0
  130. package/cpp/rnwgpu/api/descriptors/Unions.h +1984 -0
  131. package/cpp/rnwgpu/async/AsyncDispatcher.h +28 -0
  132. package/cpp/rnwgpu/async/AsyncRunner.cpp +181 -0
  133. package/cpp/rnwgpu/async/AsyncRunner.h +56 -0
  134. package/cpp/rnwgpu/async/AsyncTaskHandle.cpp +181 -0
  135. package/cpp/rnwgpu/async/AsyncTaskHandle.h +55 -0
  136. package/cpp/rnwgpu/async/JSIMicrotaskDispatcher.cpp +23 -0
  137. package/cpp/rnwgpu/async/JSIMicrotaskDispatcher.h +22 -0
  138. package/lib/commonjs/Platform/Platform.web.js +1 -2
  139. package/lib/commonjs/Platform/Platform.web.js.map +1 -1
  140. package/lib/commonjs/external/reanimated/buffers.js.map +1 -1
  141. package/lib/commonjs/external/reanimated/interpolators.d.ts +1 -4
  142. package/lib/commonjs/renderer/Canvas.js +4 -3
  143. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  144. package/lib/commonjs/renderer/components/Group.js +1 -2
  145. package/lib/commonjs/renderer/components/Group.js.map +1 -1
  146. package/lib/commonjs/renderer/components/shapes/FitBox.js +1 -2
  147. package/lib/commonjs/renderer/components/shapes/FitBox.js.map +1 -1
  148. package/lib/commonjs/skia/types/ContourMeasure.js.map +1 -1
  149. package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +20 -0
  150. package/lib/commonjs/skia/types/Image/ImageFactory.js.map +1 -1
  151. package/lib/commonjs/skia/types/RuntimeEffect/RuntimeEffect.js.map +1 -1
  152. package/lib/commonjs/skia/types/Skia.d.ts +17 -0
  153. package/lib/commonjs/skia/types/Skia.js.map +1 -1
  154. package/lib/commonjs/skia/web/JsiSkImageFactory.d.ts +2 -0
  155. package/lib/commonjs/skia/web/JsiSkImageFactory.js +6 -0
  156. package/lib/commonjs/skia/web/JsiSkImageFactory.js.map +1 -1
  157. package/lib/commonjs/skia/web/JsiSkParagraphStyle.js +2 -2
  158. package/lib/commonjs/skia/web/JsiSkParagraphStyle.js.map +1 -1
  159. package/lib/commonjs/skia/web/JsiSkia.js +6 -0
  160. package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
  161. package/lib/commonjs/sksg/Recorder/commands/ColorFilters.js.map +1 -1
  162. package/lib/commonjs/sksg/Recorder/commands/ImageFilters.js.map +1 -1
  163. package/lib/commonjs/sksg/Recorder/commands/PathEffects.js.map +1 -1
  164. package/lib/commonjs/sksg/Recorder/commands/Shaders.js.map +1 -1
  165. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.d.ts +2 -0
  166. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.js +2 -0
  167. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.js.map +1 -1
  168. package/lib/commonjs/views/SkiaPictureView.web.js +4 -4
  169. package/lib/commonjs/views/SkiaPictureView.web.js.map +1 -1
  170. package/lib/commonjs/web/WithSkiaWeb.js +1 -2
  171. package/lib/commonjs/web/WithSkiaWeb.js.map +1 -1
  172. package/lib/module/external/reanimated/buffers.js.map +1 -1
  173. package/lib/module/external/reanimated/interpolators.d.ts +1 -4
  174. package/lib/module/renderer/Canvas.js +3 -1
  175. package/lib/module/renderer/Canvas.js.map +1 -1
  176. package/lib/module/skia/types/ContourMeasure.js.map +1 -1
  177. package/lib/module/skia/types/Image/ImageFactory.d.ts +20 -0
  178. package/lib/module/skia/types/Image/ImageFactory.js.map +1 -1
  179. package/lib/module/skia/types/RuntimeEffect/RuntimeEffect.js.map +1 -1
  180. package/lib/module/skia/types/Skia.d.ts +17 -0
  181. package/lib/module/skia/types/Skia.js.map +1 -1
  182. package/lib/module/skia/web/JsiSkImageFactory.d.ts +2 -0
  183. package/lib/module/skia/web/JsiSkImageFactory.js +6 -0
  184. package/lib/module/skia/web/JsiSkImageFactory.js.map +1 -1
  185. package/lib/module/skia/web/JsiSkParagraphStyle.js +2 -2
  186. package/lib/module/skia/web/JsiSkParagraphStyle.js.map +1 -1
  187. package/lib/module/skia/web/JsiSkia.js +6 -0
  188. package/lib/module/skia/web/JsiSkia.js.map +1 -1
  189. package/lib/module/sksg/Recorder/commands/ColorFilters.js.map +1 -1
  190. package/lib/module/sksg/Recorder/commands/ImageFilters.js.map +1 -1
  191. package/lib/module/sksg/Recorder/commands/PathEffects.js.map +1 -1
  192. package/lib/module/sksg/Recorder/commands/Shaders.js.map +1 -1
  193. package/lib/module/specs/SkiaPictureViewNativeComponent.d.ts +2 -0
  194. package/lib/module/specs/SkiaPictureViewNativeComponent.js +4 -0
  195. package/lib/module/specs/SkiaPictureViewNativeComponent.js.map +1 -1
  196. package/lib/module/views/SkiaPictureView.web.js +3 -2
  197. package/lib/module/views/SkiaPictureView.web.js.map +1 -1
  198. package/lib/typescript/lib/commonjs/skia/web/JsiSkImageFactory.d.ts +2 -0
  199. package/lib/typescript/lib/commonjs/skia/web/JsiSkia.d.ts +2 -0
  200. package/lib/typescript/lib/module/renderer/Canvas.d.ts +1 -1
  201. package/lib/typescript/lib/module/skia/Skia.web.d.ts +2 -0
  202. package/lib/typescript/lib/module/skia/web/JsiSkImageFactory.d.ts +2 -0
  203. package/lib/typescript/lib/module/skia/web/JsiSkia.d.ts +2 -0
  204. package/lib/typescript/lib/module/views/SkiaPictureView.d.ts +1 -1
  205. package/lib/typescript/src/external/reanimated/interpolators.d.ts +1 -4
  206. package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +20 -0
  207. package/lib/typescript/src/skia/types/Skia.d.ts +17 -0
  208. package/lib/typescript/src/skia/web/JsiSkImageFactory.d.ts +2 -0
  209. package/lib/typescript/src/specs/SkiaPictureViewNativeComponent.d.ts +2 -0
  210. package/package.json +20 -16
  211. package/react-native-skia.podspec +52 -13
  212. package/scripts/install-skia.mjs +99 -48
  213. package/src/external/reanimated/buffers.ts +1 -1
  214. package/src/renderer/Canvas.tsx +3 -2
  215. package/src/skia/types/ContourMeasure.tsx +1 -2
  216. package/src/skia/types/Image/ImageFactory.ts +22 -0
  217. package/src/skia/types/RuntimeEffect/RuntimeEffect.ts +1 -2
  218. package/src/skia/types/Skia.ts +17 -0
  219. package/src/skia/web/JsiSkImageFactory.ts +8 -0
  220. package/src/skia/web/JsiSkia.ts +6 -0
  221. package/src/sksg/Recorder/commands/ColorFilters.ts +3 -2
  222. package/src/sksg/Recorder/commands/ImageFilters.ts +3 -2
  223. package/src/sksg/Recorder/commands/PathEffects.ts +3 -2
  224. package/src/sksg/Recorder/commands/Shaders.ts +3 -2
  225. package/src/specs/SkiaPictureViewNativeComponent.ts +7 -0
  226. package/src/views/SkiaPictureView.web.tsx +4 -1
@@ -0,0 +1,598 @@
1
+ //
2
+ // NativeObject base class for JSI NativeState pattern
3
+ //
4
+
5
+ #pragma once
6
+
7
+ #include <functional>
8
+ #include <jsi/jsi.h>
9
+ #include <memory>
10
+ #include <mutex>
11
+ #include <optional>
12
+ #include <string>
13
+ #include <type_traits>
14
+ #include <unordered_map>
15
+ #include <utility>
16
+
17
+ #include "jsi/RuntimeAwareCache.h" // Use Skia's RuntimeAwareCache
18
+
19
+ // Forward declare to avoid circular dependency
20
+ namespace rnwgpu {
21
+ template <typename ArgType, typename SFINAE> struct JSIConverter;
22
+ } // namespace rnwgpu
23
+
24
+ // Include the converter - must come after forward declaration
25
+ #include "JSIConverter.h"
26
+
27
+ namespace rnwgpu {
28
+
29
+ namespace jsi = facebook::jsi;
30
+
31
+ // Forward declaration
32
+ template <typename Derived> class NativeObject;
33
+
34
+ /**
35
+ * Registry for NativeObject prototype installers.
36
+ * This allows BoxedWebGPUObject::unbox() to install prototypes on any runtime
37
+ * by looking up the brand name and calling the appropriate installer.
38
+ */
39
+ class NativeObjectRegistry {
40
+ public:
41
+ using InstallerFunc = std::function<void(jsi::Runtime &)>;
42
+
43
+ static NativeObjectRegistry &getInstance() {
44
+ static NativeObjectRegistry instance;
45
+ return instance;
46
+ }
47
+
48
+ void registerInstaller(const std::string &brand, InstallerFunc installer) {
49
+ std::lock_guard<std::mutex> lock(_mutex);
50
+ _installers[brand] = std::move(installer);
51
+ }
52
+
53
+ bool installPrototype(jsi::Runtime &runtime, const std::string &brand) {
54
+ std::lock_guard<std::mutex> lock(_mutex);
55
+ auto it = _installers.find(brand);
56
+ if (it != _installers.end()) {
57
+ it->second(runtime);
58
+ return true;
59
+ }
60
+ return false;
61
+ }
62
+
63
+ private:
64
+ NativeObjectRegistry() = default;
65
+ std::mutex _mutex;
66
+ std::unordered_map<std::string, InstallerFunc> _installers;
67
+ };
68
+
69
+ /**
70
+ * Per-runtime cache entry for a prototype object.
71
+ * Uses std::optional<jsi::Object> so the prototype is stored directly
72
+ * without extra indirection.
73
+ */
74
+ struct PrototypeCacheEntry {
75
+ std::optional<jsi::Object> prototype;
76
+ };
77
+
78
+ /**
79
+ * Wrapper for static RuntimeAwareCache that handles hot reload.
80
+ *
81
+ * When used with static storage (like prototype caches), the cache persists
82
+ * across hot reloads. But the JSI objects inside become invalid when the
83
+ * runtime is destroyed. This wrapper tracks which runtime the cache was
84
+ * created for and allocates a new cache when the runtime changes.
85
+ *
86
+ * The old cache is intentionally leaked - we cannot safely destroy JSI
87
+ * objects after their runtime is gone.
88
+ */
89
+ template <typename T> struct StaticRuntimeAwareCache {
90
+ RNJsi::RuntimeAwareCache<T> *cache = nullptr;
91
+ jsi::Runtime *cacheRuntime = nullptr;
92
+
93
+ RNJsi::RuntimeAwareCache<T> &get(jsi::Runtime &rt) {
94
+ auto mainRuntime = RNJsi::BaseRuntimeAwareCache::getMainJsRuntime();
95
+ if (&rt == mainRuntime && cacheRuntime != mainRuntime) {
96
+ // Main runtime changed (hot reload) - allocate new cache, leak old one
97
+ cache = new RNJsi::RuntimeAwareCache<T>();
98
+ cacheRuntime = mainRuntime;
99
+ }
100
+ if (cache == nullptr) {
101
+ cache = new RNJsi::RuntimeAwareCache<T>();
102
+ cacheRuntime = mainRuntime;
103
+ }
104
+ return *cache;
105
+ }
106
+ };
107
+
108
+ /**
109
+ * BoxedWebGPUObject is a HostObject wrapper that holds a reference to ANY
110
+ * WebGPU NativeObject. This is used for Reanimated/Worklets serialization.
111
+ *
112
+ * Since NativeObject uses NativeState (not HostObject), Worklets can't
113
+ * serialize them directly. But Worklets CAN serialize HostObjects.
114
+ *
115
+ * This class stores:
116
+ * - The NativeState from the original object
117
+ * - The brand name for prototype reconstruction
118
+ *
119
+ * Usage pattern with registerCustomSerializable:
120
+ * - pack(): Call WebGPU.box(obj) to create a BoxedWebGPUObject (HostObject)
121
+ * - The HostObject is serialized by Worklets and transferred to UI runtime
122
+ * - unpack(): Call boxed.unbox() to get back the original object with prototype
123
+ *
124
+ * This is similar to NitroModules.box()/unbox() pattern.
125
+ */
126
+ class BoxedWebGPUObject : public jsi::HostObject {
127
+ public:
128
+ BoxedWebGPUObject(std::shared_ptr<jsi::NativeState> nativeState,
129
+ const std::string &brand)
130
+ : _nativeState(std::move(nativeState)), _brand(brand) {}
131
+
132
+ jsi::Value get(jsi::Runtime &runtime, const jsi::PropNameID &name) override {
133
+ auto propName = name.utf8(runtime);
134
+ if (propName == "unbox") {
135
+ return jsi::Function::createFromHostFunction(
136
+ runtime, jsi::PropNameID::forUtf8(runtime, "unbox"), 0,
137
+ [this](jsi::Runtime &rt, const jsi::Value & /*thisVal*/,
138
+ const jsi::Value * /*args*/,
139
+ size_t /*count*/) -> jsi::Value {
140
+ // Try to get the prototype from the global constructor
141
+ auto ctor = rt.global().getProperty(rt, _brand.c_str());
142
+ if (!ctor.isObject()) {
143
+ // Constructor doesn't exist on this runtime - install it
144
+ NativeObjectRegistry::getInstance().installPrototype(rt, _brand);
145
+ ctor = rt.global().getProperty(rt, _brand.c_str());
146
+ }
147
+
148
+ // Create a new object and attach the native state
149
+ jsi::Object obj(rt);
150
+ obj.setNativeState(rt, _nativeState);
151
+
152
+ // Set the prototype if constructor exists
153
+ if (ctor.isObject()) {
154
+ auto ctorObj = ctor.getObject(rt);
155
+ auto proto = ctorObj.getProperty(rt, "prototype");
156
+ if (proto.isObject()) {
157
+ auto objectCtor =
158
+ rt.global().getPropertyAsObject(rt, "Object");
159
+ auto setPrototypeOf =
160
+ objectCtor.getPropertyAsFunction(rt, "setPrototypeOf");
161
+ setPrototypeOf.call(rt, obj, proto);
162
+ }
163
+ }
164
+
165
+ return std::move(obj);
166
+ });
167
+ }
168
+ if (propName == "__boxedWebGPU") {
169
+ return jsi::Value(true);
170
+ }
171
+ if (propName == "__brand") {
172
+ return jsi::String::createFromUtf8(runtime, _brand);
173
+ }
174
+ return jsi::Value::undefined();
175
+ }
176
+
177
+ void set(jsi::Runtime &runtime, const jsi::PropNameID &name,
178
+ const jsi::Value &value) override {
179
+ throw jsi::JSError(runtime, "BoxedWebGPUObject is read-only");
180
+ }
181
+
182
+ std::vector<jsi::PropNameID>
183
+ getPropertyNames(jsi::Runtime &runtime) override {
184
+ std::vector<jsi::PropNameID> names;
185
+ names.reserve(3);
186
+ names.push_back(jsi::PropNameID::forUtf8(runtime, "unbox"));
187
+ names.push_back(jsi::PropNameID::forUtf8(runtime, "__boxedWebGPU"));
188
+ names.push_back(jsi::PropNameID::forUtf8(runtime, "__brand"));
189
+ return names;
190
+ }
191
+
192
+ private:
193
+ std::shared_ptr<jsi::NativeState> _nativeState;
194
+ std::string _brand;
195
+ };
196
+
197
+ /**
198
+ * Base class for native objects using the NativeState pattern.
199
+ *
200
+ * Instead of using HostObject (which intercepts all property access),
201
+ * this pattern:
202
+ * 1. Stores native data via jsi::Object::setNativeState()
203
+ * 2. Installs methods on a shared prototype object (once per runtime)
204
+ * 3. Creates plain JS objects that use the prototype chain
205
+ *
206
+ * Usage:
207
+ * ```cpp
208
+ * class MyClass : public NativeObject<MyClass> {
209
+ * public:
210
+ * static constexpr const char* CLASS_NAME = "MyClass";
211
+ *
212
+ * MyClass(...) : NativeObject(CLASS_NAME), ... {}
213
+ *
214
+ * std::string getValue() { return _value; }
215
+ *
216
+ * static void definePrototype(jsi::Runtime& rt, jsi::Object& proto) {
217
+ * installGetter(rt, proto, "value", &MyClass::getValue);
218
+ * }
219
+ *
220
+ * private:
221
+ * std::string _value;
222
+ * };
223
+ * ```
224
+ */
225
+ template <typename Derived>
226
+ class NativeObject : public jsi::NativeState,
227
+ public std::enable_shared_from_this<Derived> {
228
+ public:
229
+ // Marker type for SFINAE detection in JSIConverter
230
+ using IsNativeObject = std::true_type;
231
+
232
+ /**
233
+ * Get the prototype cache for this type.
234
+ * Each NativeObject<Derived> type has its own static cache.
235
+ * Uses StaticRuntimeAwareCache to properly handle runtime lifecycle
236
+ * and hot reload (where the main runtime is destroyed and recreated).
237
+ */
238
+ static RNJsi::RuntimeAwareCache<PrototypeCacheEntry> &
239
+ getPrototypeCache(jsi::Runtime &runtime) {
240
+ static StaticRuntimeAwareCache<PrototypeCacheEntry> cache;
241
+ return cache.get(runtime);
242
+ }
243
+
244
+ /**
245
+ * Ensure the prototype is installed for this runtime.
246
+ * Called automatically by create(), but can be called manually.
247
+ */
248
+ static void installPrototype(jsi::Runtime &runtime) {
249
+ auto &entry = getPrototypeCache(runtime).get(runtime);
250
+ if (entry.prototype.has_value()) {
251
+ return; // Already installed
252
+ }
253
+
254
+ // Create prototype object
255
+ jsi::Object prototype(runtime);
256
+
257
+ // Let derived class define its methods/properties
258
+ Derived::definePrototype(runtime, prototype);
259
+
260
+ // Add Symbol.toStringTag for proper object identification in console.log
261
+ auto symbolCtor = runtime.global().getPropertyAsObject(runtime, "Symbol");
262
+ auto toStringTag = symbolCtor.getProperty(runtime, "toStringTag");
263
+ if (!toStringTag.isUndefined()) {
264
+ // Use Object.defineProperty to set symbol property since setProperty
265
+ // doesn't support symbols directly
266
+ auto objectCtor =
267
+ runtime.global().getPropertyAsObject(runtime, "Object");
268
+ auto defineProperty =
269
+ objectCtor.getPropertyAsFunction(runtime, "defineProperty");
270
+ jsi::Object descriptor(runtime);
271
+ descriptor.setProperty(
272
+ runtime, "value",
273
+ jsi::String::createFromUtf8(runtime, Derived::CLASS_NAME));
274
+ descriptor.setProperty(runtime, "writable", false);
275
+ descriptor.setProperty(runtime, "enumerable", false);
276
+ descriptor.setProperty(runtime, "configurable", true);
277
+ defineProperty.call(runtime, prototype, toStringTag, descriptor);
278
+ }
279
+
280
+ // Cache the prototype
281
+ entry.prototype = std::move(prototype);
282
+ }
283
+
284
+ /**
285
+ * Install a constructor function on the global object.
286
+ * This enables `instanceof` checks: `obj instanceof ClassName`
287
+ *
288
+ * The constructor throws if called directly (these objects are only
289
+ * created internally by the native code).
290
+ *
291
+ * Also registers this class with NativeObjectRegistry so that
292
+ * BoxedWebGPUObject::unbox() can install prototypes on secondary runtimes.
293
+ */
294
+ static void installConstructor(jsi::Runtime &runtime) {
295
+ // Register this class's installer in the registry (only needs to happen once)
296
+ static std::once_flag registryFlag;
297
+ std::call_once(registryFlag, []() {
298
+ NativeObjectRegistry::getInstance().registerInstaller(
299
+ Derived::CLASS_NAME,
300
+ [](jsi::Runtime &rt) { Derived::installConstructor(rt); });
301
+ });
302
+
303
+ installPrototype(runtime);
304
+
305
+ auto &entry = getPrototypeCache(runtime).get(runtime);
306
+ if (!entry.prototype.has_value()) {
307
+ return;
308
+ }
309
+
310
+ // Create a constructor function that throws when called directly
311
+ auto ctor = jsi::Function::createFromHostFunction(
312
+ runtime, jsi::PropNameID::forUtf8(runtime, Derived::CLASS_NAME), 0,
313
+ [](jsi::Runtime &rt, const jsi::Value & /*thisVal*/,
314
+ const jsi::Value * /*args*/, size_t /*count*/) -> jsi::Value {
315
+ throw jsi::JSError(
316
+ rt, std::string("Illegal constructor: ") + Derived::CLASS_NAME +
317
+ " objects are created by the WebGPU API");
318
+ });
319
+
320
+ // Set the prototype property on the constructor
321
+ // This is what makes `instanceof` work
322
+ ctor.setProperty(runtime, "prototype", *entry.prototype);
323
+
324
+ // Set constructor property on prototype pointing back to constructor
325
+ entry.prototype->setProperty(runtime, "constructor", ctor);
326
+
327
+ // Install on global
328
+ runtime.global().setProperty(runtime, Derived::CLASS_NAME, std::move(ctor));
329
+ }
330
+
331
+ /**
332
+ * Create a JS object with native state attached.
333
+ */
334
+ static jsi::Value create(jsi::Runtime &runtime,
335
+ std::shared_ptr<Derived> instance) {
336
+ installPrototype(runtime);
337
+
338
+ // Store creation runtime for logging etc.
339
+ instance->setCreationRuntime(&runtime);
340
+
341
+ // Create a new object
342
+ jsi::Object obj(runtime);
343
+
344
+ // Attach native state
345
+ obj.setNativeState(runtime, instance);
346
+
347
+ // Set prototype
348
+ auto &entry = getPrototypeCache(runtime).get(runtime);
349
+ if (entry.prototype.has_value()) {
350
+ // Use Object.setPrototypeOf to set the prototype
351
+ auto objectCtor =
352
+ runtime.global().getPropertyAsObject(runtime, "Object");
353
+ auto setPrototypeOf =
354
+ objectCtor.getPropertyAsFunction(runtime, "setPrototypeOf");
355
+ setPrototypeOf.call(runtime, obj, *entry.prototype);
356
+ }
357
+
358
+ // Set memory pressure hint for GC
359
+ auto pressure = instance->getMemoryPressure();
360
+ if (pressure > 0) {
361
+ obj.setExternalMemoryPressure(runtime, pressure);
362
+ }
363
+
364
+ return std::move(obj);
365
+ }
366
+
367
+ /**
368
+ * Get the native state from a JS value.
369
+ * Throws if the value doesn't have the expected native state.
370
+ */
371
+ static std::shared_ptr<Derived> fromValue(jsi::Runtime &runtime,
372
+ const jsi::Value &value) {
373
+ if (!value.isObject()) {
374
+ throw jsi::JSError(runtime, std::string("Expected ") +
375
+ Derived::CLASS_NAME +
376
+ " but got non-object");
377
+ }
378
+ jsi::Object obj = value.getObject(runtime);
379
+ if (!obj.hasNativeState<Derived>(runtime)) {
380
+ throw jsi::JSError(runtime, std::string("Expected ") +
381
+ Derived::CLASS_NAME +
382
+ " but got different type");
383
+ }
384
+ return obj.getNativeState<Derived>(runtime);
385
+ }
386
+
387
+ /**
388
+ * Memory pressure for GC hints. Override in derived classes.
389
+ */
390
+ virtual size_t getMemoryPressure() { return 1024; }
391
+
392
+ /**
393
+ * Set the creation runtime. Called during create().
394
+ */
395
+ void setCreationRuntime(jsi::Runtime *runtime) { _creationRuntime = runtime; }
396
+
397
+ /**
398
+ * Get the creation runtime.
399
+ * WARNING: This pointer may become invalid if the runtime is destroyed.
400
+ */
401
+ jsi::Runtime *getCreationRuntime() const { return _creationRuntime; }
402
+
403
+ protected:
404
+ explicit NativeObject(const char *name) : _name(name) {}
405
+
406
+ virtual ~NativeObject() {}
407
+
408
+ const char *_name;
409
+ jsi::Runtime *_creationRuntime = nullptr;
410
+
411
+ // ============================================================
412
+ // Helper methods for definePrototype() implementations
413
+ // ============================================================
414
+
415
+ /**
416
+ * Install a method on the prototype.
417
+ */
418
+ template <typename ReturnType, typename... Args>
419
+ static void installMethod(jsi::Runtime &runtime, jsi::Object &prototype,
420
+ const char *name,
421
+ ReturnType (Derived::*method)(Args...)) {
422
+ auto func = jsi::Function::createFromHostFunction(
423
+ runtime, jsi::PropNameID::forUtf8(runtime, name), sizeof...(Args),
424
+ [method](jsi::Runtime &rt, const jsi::Value &thisVal,
425
+ const jsi::Value *args, size_t count) -> jsi::Value {
426
+ auto native = Derived::fromValue(rt, thisVal);
427
+ return callMethod(native.get(), method, rt, args,
428
+ std::index_sequence_for<Args...>{}, count);
429
+ });
430
+ prototype.setProperty(runtime, name, func);
431
+ }
432
+
433
+ /**
434
+ * Install a getter on the prototype.
435
+ */
436
+ template <typename ReturnType>
437
+ static void installGetter(jsi::Runtime &runtime, jsi::Object &prototype,
438
+ const char *name, ReturnType (Derived::*getter)()) {
439
+ // Create a getter function
440
+ auto getterFunc = jsi::Function::createFromHostFunction(
441
+ runtime, jsi::PropNameID::forUtf8(runtime, std::string("get_") + name),
442
+ 0,
443
+ [getter](jsi::Runtime &rt, const jsi::Value &thisVal,
444
+ const jsi::Value *args, size_t count) -> jsi::Value {
445
+ auto native = Derived::fromValue(rt, thisVal);
446
+ if constexpr (std::is_same_v<ReturnType, void>) {
447
+ (native.get()->*getter)();
448
+ return jsi::Value::undefined();
449
+ } else {
450
+ ReturnType result = (native.get()->*getter)();
451
+ return rnwgpu::JSIConverter<std::decay_t<ReturnType>>::toJSI(
452
+ rt, std::move(result));
453
+ }
454
+ });
455
+
456
+ // Use Object.defineProperty to create a proper getter
457
+ auto objectCtor = runtime.global().getPropertyAsObject(runtime, "Object");
458
+ auto defineProperty =
459
+ objectCtor.getPropertyAsFunction(runtime, "defineProperty");
460
+
461
+ jsi::Object descriptor(runtime);
462
+ descriptor.setProperty(runtime, "get", getterFunc);
463
+ descriptor.setProperty(runtime, "enumerable", true);
464
+ descriptor.setProperty(runtime, "configurable", true);
465
+
466
+ defineProperty.call(runtime, prototype,
467
+ jsi::String::createFromUtf8(runtime, name), descriptor);
468
+ }
469
+
470
+ /**
471
+ * Install a setter on the prototype.
472
+ */
473
+ template <typename ValueType>
474
+ static void installSetter(jsi::Runtime &runtime, jsi::Object &prototype,
475
+ const char *name,
476
+ void (Derived::*setter)(ValueType)) {
477
+ auto setterFunc = jsi::Function::createFromHostFunction(
478
+ runtime, jsi::PropNameID::forUtf8(runtime, std::string("set_") + name),
479
+ 1,
480
+ [setter](jsi::Runtime &rt, const jsi::Value &thisVal,
481
+ const jsi::Value *args, size_t count) -> jsi::Value {
482
+ if (count < 1) {
483
+ throw jsi::JSError(rt, "Setter requires a value argument");
484
+ }
485
+ auto native = Derived::fromValue(rt, thisVal);
486
+ auto value =
487
+ rnwgpu::JSIConverter<std::decay_t<ValueType>>::fromJSI(rt, args[0], false);
488
+ (native.get()->*setter)(std::move(value));
489
+ return jsi::Value::undefined();
490
+ });
491
+
492
+ // Use Object.defineProperty to create a proper setter
493
+ auto objectCtor = runtime.global().getPropertyAsObject(runtime, "Object");
494
+ auto defineProperty =
495
+ objectCtor.getPropertyAsFunction(runtime, "defineProperty");
496
+
497
+ // Check if property already has a getter
498
+ auto getOwnPropertyDescriptor =
499
+ objectCtor.getPropertyAsFunction(runtime, "getOwnPropertyDescriptor");
500
+ auto existingDesc = getOwnPropertyDescriptor.call(
501
+ runtime, prototype, jsi::String::createFromUtf8(runtime, name));
502
+
503
+ jsi::Object descriptor(runtime);
504
+ if (existingDesc.isObject()) {
505
+ auto existingDescObj = existingDesc.getObject(runtime);
506
+ if (existingDescObj.hasProperty(runtime, "get")) {
507
+ descriptor.setProperty(
508
+ runtime, "get", existingDescObj.getProperty(runtime, "get"));
509
+ }
510
+ }
511
+ descriptor.setProperty(runtime, "set", setterFunc);
512
+ descriptor.setProperty(runtime, "enumerable", true);
513
+ descriptor.setProperty(runtime, "configurable", true);
514
+
515
+ defineProperty.call(runtime, prototype,
516
+ jsi::String::createFromUtf8(runtime, name), descriptor);
517
+ }
518
+
519
+ /**
520
+ * Install both getter and setter for a property.
521
+ */
522
+ template <typename ReturnType, typename ValueType>
523
+ static void installGetterSetter(jsi::Runtime &runtime, jsi::Object &prototype,
524
+ const char *name,
525
+ ReturnType (Derived::*getter)(),
526
+ void (Derived::*setter)(ValueType)) {
527
+ auto getterFunc = jsi::Function::createFromHostFunction(
528
+ runtime, jsi::PropNameID::forUtf8(runtime, std::string("get_") + name),
529
+ 0,
530
+ [getter](jsi::Runtime &rt, const jsi::Value &thisVal,
531
+ const jsi::Value *args, size_t count) -> jsi::Value {
532
+ auto native = Derived::fromValue(rt, thisVal);
533
+ ReturnType result = (native.get()->*getter)();
534
+ return rnwgpu::JSIConverter<std::decay_t<ReturnType>>::toJSI(rt,
535
+ std::move(result));
536
+ });
537
+
538
+ auto setterFunc = jsi::Function::createFromHostFunction(
539
+ runtime, jsi::PropNameID::forUtf8(runtime, std::string("set_") + name),
540
+ 1,
541
+ [setter](jsi::Runtime &rt, const jsi::Value &thisVal,
542
+ const jsi::Value *args, size_t count) -> jsi::Value {
543
+ if (count < 1) {
544
+ throw jsi::JSError(rt, "Setter requires a value argument");
545
+ }
546
+ auto native = Derived::fromValue(rt, thisVal);
547
+ auto value =
548
+ rnwgpu::JSIConverter<std::decay_t<ValueType>>::fromJSI(rt, args[0], false);
549
+ (native.get()->*setter)(std::move(value));
550
+ return jsi::Value::undefined();
551
+ });
552
+
553
+ auto objectCtor = runtime.global().getPropertyAsObject(runtime, "Object");
554
+ auto defineProperty =
555
+ objectCtor.getPropertyAsFunction(runtime, "defineProperty");
556
+
557
+ jsi::Object descriptor(runtime);
558
+ descriptor.setProperty(runtime, "get", getterFunc);
559
+ descriptor.setProperty(runtime, "set", setterFunc);
560
+ descriptor.setProperty(runtime, "enumerable", true);
561
+ descriptor.setProperty(runtime, "configurable", true);
562
+
563
+ defineProperty.call(runtime, prototype,
564
+ jsi::String::createFromUtf8(runtime, name), descriptor);
565
+ }
566
+
567
+ private:
568
+ // Helper to call a method with JSI argument conversion
569
+ template <typename ReturnType, typename... Args, size_t... Is>
570
+ static jsi::Value callMethod(Derived *obj,
571
+ ReturnType (Derived::*method)(Args...),
572
+ jsi::Runtime &runtime, const jsi::Value *args,
573
+ std::index_sequence<Is...>, size_t count) {
574
+ if constexpr (std::is_same_v<ReturnType, void>) {
575
+ (obj->*method)(rnwgpu::JSIConverter<std::decay_t<Args>>::fromJSI(
576
+ runtime, args[Is], Is >= count)...);
577
+ return jsi::Value::undefined();
578
+ } else if constexpr (std::is_same_v<ReturnType, jsi::Value>) {
579
+ // Special case: if return type is jsi::Value, method has full control
580
+ // This requires the method signature to match HostFunction
581
+ return (obj->*method)(runtime, jsi::Value::undefined(), args, count);
582
+ } else {
583
+ ReturnType result = (obj->*method)(rnwgpu::JSIConverter<std::decay_t<Args>>::fromJSI(
584
+ runtime, args[Is], Is >= count)...);
585
+ return rnwgpu::JSIConverter<std::decay_t<ReturnType>>::toJSI(runtime,
586
+ std::move(result));
587
+ }
588
+ }
589
+ };
590
+
591
+ // Type trait to detect NativeObject-derived classes
592
+ template <typename T> struct is_native_object : std::false_type {};
593
+
594
+ template <typename T>
595
+ struct is_native_object<std::shared_ptr<T>>
596
+ : std::bool_constant<std::is_base_of_v<NativeObject<T>, T>> {};
597
+
598
+ } // namespace rnwgpu
@@ -0,0 +1,44 @@
1
+ #include "Promise.h"
2
+ #include <future>
3
+ #include <jsi/jsi.h>
4
+ #include <memory>
5
+ #include <string>
6
+ #include <utility>
7
+ #include <vector>
8
+
9
+ namespace rnwgpu {
10
+
11
+ namespace jsi = facebook::jsi;
12
+
13
+ Promise::Promise(jsi::Runtime& runtime, jsi::Function&& resolver, jsi::Function&& rejecter)
14
+ : runtime(runtime), _resolver(std::move(resolver)), _rejecter(std::move(rejecter)) {}
15
+
16
+ jsi::Value Promise::createPromise(jsi::Runtime& runtime, RunPromise run) {
17
+ // Get Promise ctor from global
18
+ auto promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
19
+
20
+ auto promiseCallback = jsi::Function::createFromHostFunction(
21
+ runtime, jsi::PropNameID::forUtf8(runtime, "PromiseCallback"), 2,
22
+ [=](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value {
23
+ // Call function
24
+ auto resolver = arguments[0].asObject(runtime).asFunction(runtime);
25
+ auto rejecter = arguments[1].asObject(runtime).asFunction(runtime);
26
+ auto promise = std::make_shared<Promise>(runtime, std::move(resolver), std::move(rejecter));
27
+ run(runtime, promise);
28
+
29
+ return jsi::Value::undefined();
30
+ });
31
+
32
+ return promiseCtor.callAsConstructor(runtime, promiseCallback);
33
+ }
34
+
35
+ void Promise::resolve(jsi::Value&& result) {
36
+ _resolver.call(runtime, std::move(result));
37
+ }
38
+
39
+ void Promise::reject(std::string message) {
40
+ jsi::JSError error(runtime, message);
41
+ _rejecter.call(runtime, error.value());
42
+ }
43
+
44
+ } // namespace rnwgpu
@@ -0,0 +1,35 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+ #include <utility>
5
+ #include <vector>
6
+ #include <string>
7
+ #include <memory>
8
+
9
+ namespace rnwgpu {
10
+
11
+ namespace jsi = facebook::jsi;
12
+
13
+ class Promise {
14
+ public:
15
+ Promise(jsi::Runtime& runtime, jsi::Function&& resolver, jsi::Function&& rejecter);
16
+
17
+ void resolve(jsi::Value&& result);
18
+ void reject(std::string error);
19
+
20
+ public:
21
+ jsi::Runtime& runtime;
22
+
23
+ private:
24
+ jsi::Function _resolver;
25
+ jsi::Function _rejecter;
26
+
27
+ public:
28
+ using RunPromise = std::function<void(jsi::Runtime& runtime, std::shared_ptr<Promise> promise)>;
29
+ /**
30
+ Create a new Promise and runs the given `run` function.
31
+ */
32
+ static jsi::Value createPromise(jsi::Runtime& runtime, RunPromise run);
33
+ };
34
+
35
+ } // namespace rnwgpu