react-native-webgpu 0.9.0 → 0.10.1

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 (143) hide show
  1. package/Package.swift +191 -0
  2. package/android/CMakeLists.txt +1 -2
  3. package/android/src/main/java/com/webgpu/WebGPUSurfaceView.java +10 -1
  4. package/android/src/main/java/com/webgpu/WebGPUTextureView.java +2 -2
  5. package/android/src/main/java/com/webgpu/WebGPUView.java +48 -16
  6. package/android/src/main/java/com/webgpu/WebGPUViewManager.java +21 -4
  7. package/cpp/jsi/JSICache.cpp +97 -0
  8. package/cpp/jsi/JSICache.h +90 -0
  9. package/cpp/jsi/NativeObject.h +24 -86
  10. package/cpp/rnwgpu/RNWebGPUManager.cpp +0 -3
  11. package/cpp/rnwgpu/SurfaceRegistry.h +153 -3
  12. package/cpp/rnwgpu/api/GPUAdapter.cpp +43 -1
  13. package/cpp/rnwgpu/api/GPUDevice.cpp +6 -1
  14. package/cpp/rnwgpu/api/GPUExternalTexture.cpp +5 -7
  15. package/cpp/rnwgpu/api/GPUExternalTexture.h +40 -3
  16. package/cpp/rnwgpu/api/GPUFeatures.h +2 -1
  17. package/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp +2 -2
  18. package/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h +11 -0
  19. package/cpp/webgpu/webgpu.h +63 -29
  20. package/cpp/webgpu/webgpu_cpp.h +415 -367
  21. package/cpp/webgpu/webgpu_cpp_print.h +21 -9
  22. package/cpp/webgpu/webgpu_enum_class_bitmasks.h +2 -1
  23. package/lib/commonjs/Canvas.js +8 -2
  24. package/lib/commonjs/Canvas.js.map +1 -1
  25. package/lib/commonjs/WebGPUViewNativeComponent.js.map +1 -1
  26. package/lib/commonjs/WebGPUViewNativeComponent.web.js +4 -2
  27. package/lib/commonjs/WebGPUViewNativeComponent.web.js.map +1 -1
  28. package/lib/commonjs/mock.js +3 -1
  29. package/lib/commonjs/mock.js.map +1 -1
  30. package/lib/module/Canvas.js +8 -2
  31. package/lib/module/Canvas.js.map +1 -1
  32. package/lib/module/WebGPUViewNativeComponent.js.map +1 -1
  33. package/lib/module/WebGPUViewNativeComponent.web.js +4 -2
  34. package/lib/module/WebGPUViewNativeComponent.web.js.map +1 -1
  35. package/lib/module/mock.js +3 -1
  36. package/lib/module/mock.js.map +1 -1
  37. package/lib/typescript/lib/commonjs/Canvas.d.ts +3 -2
  38. package/lib/typescript/lib/commonjs/Canvas.d.ts.map +1 -1
  39. package/lib/typescript/lib/commonjs/WebGPUViewNativeComponent.web.d.ts.map +1 -1
  40. package/lib/typescript/lib/commonjs/mock.d.ts +3 -2
  41. package/lib/typescript/lib/commonjs/mock.d.ts.map +1 -1
  42. package/lib/typescript/lib/module/Canvas.d.ts +3 -2
  43. package/lib/typescript/lib/module/Canvas.d.ts.map +1 -1
  44. package/lib/typescript/lib/module/WebGPUViewNativeComponent.web.d.ts.map +1 -1
  45. package/lib/typescript/lib/module/mock.d.ts +3 -2
  46. package/lib/typescript/lib/module/mock.d.ts.map +1 -1
  47. package/lib/typescript/src/Canvas.d.ts +24 -3
  48. package/lib/typescript/src/Canvas.d.ts.map +1 -1
  49. package/lib/typescript/src/WebGPUViewNativeComponent.d.ts +4 -2
  50. package/lib/typescript/src/WebGPUViewNativeComponent.d.ts.map +1 -1
  51. package/lib/typescript/src/WebGPUViewNativeComponent.web.d.ts +3 -1
  52. package/lib/typescript/src/WebGPUViewNativeComponent.web.d.ts.map +1 -1
  53. package/lib/typescript/src/index.d.ts +1 -0
  54. package/lib/typescript/src/index.d.ts.map +1 -1
  55. package/lib/typescript/src/mock.d.ts +3 -7
  56. package/lib/typescript/src/mock.d.ts.map +1 -1
  57. package/lib/typescript/src/types.d.ts.map +1 -1
  58. package/libs/android/arm64-v8a/libwebgpu_dawn.so +0 -0
  59. package/libs/android/armeabi-v7a/libwebgpu_dawn.so +0 -0
  60. package/libs/android/x86/libwebgpu_dawn.so +0 -0
  61. package/libs/android/x86_64/libwebgpu_dawn.so +0 -0
  62. package/libs/apple/libwebgpu_dawn.xcframework/Info.plist +12 -6
  63. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/dawn_proc_table.h +329 -0
  64. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/native/DawnNative.h +367 -0
  65. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/native/NullBackend.h +39 -0
  66. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/native/OpenGLBackend.h +89 -0
  67. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/native/VulkanBackend.h +183 -0
  68. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/native/dawn_native_export.h +49 -0
  69. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/webgpu.h +5063 -0
  70. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/webgpu.ixx +358 -0
  71. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/webgpu_cpp.h +10401 -0
  72. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/webgpu_cpp_print.h +2868 -0
  73. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/wire/client/webgpu.h +369 -0
  74. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/wire/client/webgpu_cpp.h +10584 -0
  75. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/dawn/wire/client/webgpu_cpp_print.h +2868 -0
  76. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/webgpu/webgpu.h +33 -0
  77. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/webgpu/webgpu_cpp.h +33 -0
  78. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/webgpu/webgpu_cpp_chained_struct.h +57 -0
  79. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/webgpu/webgpu_cpp_print.h +33 -0
  80. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/webgpu/webgpu_enum_class_bitmasks.h +163 -0
  81. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/webgpu_upstream/webgpu/webgpu_cpp.h +5932 -0
  82. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/webgpu_upstream/webgpu/webgpu_cpp_chained_struct.h +54 -0
  83. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/webgpu_upstream/webgpu/webgpu_cpp_print.h +2059 -0
  84. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/Headers/webgpu_upstream/webgpu/webgpu_enum_class_bitmasks.h +163 -0
  85. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/libwebgpu_dawn.a +0 -0
  86. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/dawn_proc_table.h +329 -0
  87. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/native/DawnNative.h +367 -0
  88. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/native/NullBackend.h +39 -0
  89. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/native/OpenGLBackend.h +89 -0
  90. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/native/VulkanBackend.h +183 -0
  91. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/native/dawn_native_export.h +49 -0
  92. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/webgpu.h +5063 -0
  93. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/webgpu.ixx +358 -0
  94. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/webgpu_cpp.h +10401 -0
  95. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/webgpu_cpp_print.h +2868 -0
  96. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/wire/client/webgpu.h +369 -0
  97. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/wire/client/webgpu_cpp.h +10584 -0
  98. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/dawn/wire/client/webgpu_cpp_print.h +2868 -0
  99. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/webgpu/webgpu.h +33 -0
  100. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/webgpu/webgpu_cpp.h +33 -0
  101. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/webgpu/webgpu_cpp_chained_struct.h +57 -0
  102. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/webgpu/webgpu_cpp_print.h +33 -0
  103. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/webgpu/webgpu_enum_class_bitmasks.h +163 -0
  104. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/webgpu_upstream/webgpu/webgpu_cpp.h +5932 -0
  105. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/webgpu_upstream/webgpu/webgpu_cpp_chained_struct.h +54 -0
  106. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/webgpu_upstream/webgpu/webgpu_cpp_print.h +2059 -0
  107. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/Headers/webgpu_upstream/webgpu/webgpu_enum_class_bitmasks.h +163 -0
  108. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/libwebgpu_dawn.a +0 -0
  109. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/dawn_proc_table.h +329 -0
  110. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/native/DawnNative.h +367 -0
  111. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/native/NullBackend.h +39 -0
  112. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/native/OpenGLBackend.h +89 -0
  113. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/native/VulkanBackend.h +183 -0
  114. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/native/dawn_native_export.h +49 -0
  115. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/webgpu.h +5063 -0
  116. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/webgpu.ixx +358 -0
  117. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/webgpu_cpp.h +10401 -0
  118. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/webgpu_cpp_print.h +2868 -0
  119. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/wire/client/webgpu.h +369 -0
  120. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/wire/client/webgpu_cpp.h +10584 -0
  121. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/dawn/wire/client/webgpu_cpp_print.h +2868 -0
  122. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/webgpu/webgpu.h +33 -0
  123. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/webgpu/webgpu_cpp.h +33 -0
  124. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/webgpu/webgpu_cpp_chained_struct.h +57 -0
  125. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/webgpu/webgpu_cpp_print.h +33 -0
  126. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/webgpu/webgpu_enum_class_bitmasks.h +163 -0
  127. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/webgpu_upstream/webgpu/webgpu_cpp.h +5932 -0
  128. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/webgpu_upstream/webgpu/webgpu_cpp_chained_struct.h +54 -0
  129. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/webgpu_upstream/webgpu/webgpu_cpp_print.h +2059 -0
  130. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/Headers/webgpu_upstream/webgpu/webgpu_enum_class_bitmasks.h +163 -0
  131. package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/libwebgpu_dawn.a +0 -0
  132. package/package.json +7 -5
  133. package/react-native-webgpu.podspec +33 -9
  134. package/src/Canvas.tsx +43 -4
  135. package/src/WebGPUViewNativeComponent.ts +10 -2
  136. package/src/WebGPUViewNativeComponent.web.ts +12 -3
  137. package/src/index.tsx +7 -0
  138. package/src/mock.ts +12 -9
  139. package/src/types.ts +1 -3
  140. package/cpp/jsi/RuntimeAwareCache.cpp +0 -8
  141. package/cpp/jsi/RuntimeAwareCache.h +0 -133
  142. package/cpp/jsi/RuntimeLifecycleMonitor.cpp +0 -72
  143. package/cpp/jsi/RuntimeLifecycleMonitor.h +0 -32
@@ -8,14 +8,14 @@
8
8
  #include <jsi/jsi.h>
9
9
  #include <memory>
10
10
  #include <mutex>
11
- #include <optional>
12
11
  #include <stdexcept>
13
12
  #include <string>
14
13
  #include <type_traits>
14
+ #include <typeindex>
15
15
  #include <unordered_map>
16
16
  #include <utility>
17
17
 
18
- #include "RuntimeAwareCache.h"
18
+ #include "JSICache.h"
19
19
  #include "WGPULogger.h"
20
20
 
21
21
  // Forward declare to avoid circular dependency
@@ -74,50 +74,6 @@ private:
74
74
  std::unordered_map<std::string, InstallerFunc> _installers;
75
75
  };
76
76
 
77
- /**
78
- * Per-runtime cache entry for a prototype object.
79
- * Uses std::optional<jsi::Object> so the prototype is stored directly
80
- * without extra indirection.
81
- */
82
- struct PrototypeCacheEntry {
83
- std::optional<jsi::Object> prototype;
84
- };
85
-
86
- /**
87
- * Wrapper for static RuntimeAwareCache that handles hot reload.
88
- *
89
- * When used with static storage (like prototype caches), the cache persists
90
- * across hot reloads. But the JSI objects inside become invalid when the
91
- * runtime is destroyed. This wrapper tracks which main-runtime generation the
92
- * cache was created for and allocates a new cache when the native module is
93
- * reinstalled (RNWebGPUManager construction bumps the generation).
94
- *
95
- * The generation is used instead of the runtime pointer on purpose: on an
96
- * in-process runtime recreate (expo-updates reloadAsync, DevSettings.reload)
97
- * Hermes frequently allocates the new runtime at the address of the freed
98
- * one. A pointer comparison then sees "same runtime", keeps the stale cache,
99
- * and installConstructor() ends up touching a jsi::Object owned by the dead
100
- * runtime (SIGSEGV in jsi::Value::~Value, see issue #461).
101
- *
102
- * The old cache is intentionally leaked - we cannot safely destroy JSI
103
- * objects after their runtime is gone.
104
- */
105
- template <typename T> struct StaticRuntimeAwareCache {
106
- RuntimeAwareCache<T> *cache = nullptr;
107
- uint64_t cacheGeneration = 0;
108
-
109
- RuntimeAwareCache<T> &get(jsi::Runtime & /*rt*/) {
110
- auto generation = BaseRuntimeAwareCache::getMainJsRuntimeGeneration();
111
- if (cache == nullptr || cacheGeneration != generation) {
112
- // First use, or the main runtime was reinstalled (hot reload / OTA):
113
- // allocate a fresh cache and leak the old one.
114
- cache = new RuntimeAwareCache<T>();
115
- cacheGeneration = generation;
116
- }
117
- return *cache;
118
- }
119
- };
120
-
121
77
  /**
122
78
  * BoxedWebGPUObject is a HostObject wrapper that holds a reference to ANY
123
79
  * WebGPU NativeObject. This is used for Reanimated/Worklets serialization.
@@ -243,29 +199,20 @@ public:
243
199
  using IsNativeObject = std::true_type;
244
200
 
245
201
  /**
246
- * Get the prototype cache for this type.
247
- * Each NativeObject<Derived> type has its own static cache.
248
- * Uses StaticRuntimeAwareCache to properly handle runtime lifecycle
249
- * and hot reload (where the main runtime is destroyed and recreated).
250
- *
251
- * Callers must hold getPrototypeCacheMutex(): the cache is reached
252
- * concurrently from the main JS thread (create()) and from worklet
253
- * runtime threads (BoxedWebGPUObject::unbox() -> installPrototype()).
202
+ * Key under which this class's prototype is stored in the per-runtime
203
+ * JSICache: the C++ type of Derived.
254
204
  */
255
- static RuntimeAwareCache<PrototypeCacheEntry> &
256
- getPrototypeCache(jsi::Runtime &runtime) {
257
- static StaticRuntimeAwareCache<PrototypeCacheEntry> cache;
258
- return cache.get(runtime);
205
+ static JSICache::PrototypeKey prototypeKey() {
206
+ return std::type_index(typeid(Derived));
259
207
  }
260
208
 
261
209
  /**
262
- * Per-class mutex guarding getPrototypeCache() and prototype
263
- * installation. Serializes the StaticRuntimeAwareCache pointer swap
264
- * (hot reload) and the per-runtime cache lookups.
210
+ * Returns this class's prototype on `runtime`, or nullptr if it has not
211
+ * been installed there yet. The prototype is owned by the runtime (see
212
+ * JSICache), so the pointer is valid for as long as `runtime` is.
265
213
  */
266
- static std::mutex &getPrototypeCacheMutex() {
267
- static std::mutex mutex;
268
- return mutex;
214
+ static jsi::Object *getCachedPrototype(jsi::Runtime &runtime) {
215
+ return JSICache::get(runtime).getPrototype(prototypeKey());
269
216
  }
270
217
 
271
218
  /**
@@ -273,10 +220,8 @@ public:
273
220
  * Called automatically by create(), but can be called manually.
274
221
  */
275
222
  static void installPrototype(jsi::Runtime &runtime) {
276
- std::lock_guard<std::mutex> lock(getPrototypeCacheMutex());
277
- auto &entry = getPrototypeCache(runtime).get(runtime);
278
- if (entry.prototype.has_value()) {
279
- return; // Already installed
223
+ if (getCachedPrototype(runtime) != nullptr) {
224
+ return; // Already installed on this runtime
280
225
  }
281
226
 
282
227
  // Create prototype object
@@ -348,8 +293,8 @@ public:
348
293
  });
349
294
  prototype.setProperty(runtime, "toJSON", toJSON);
350
295
 
351
- // Cache the prototype
352
- entry.prototype = std::move(prototype);
296
+ // Hand the prototype to the runtime-owned cache
297
+ JSICache::get(runtime).setPrototype(prototypeKey(), std::move(prototype));
353
298
  }
354
299
 
355
300
  /**
@@ -373,9 +318,8 @@ public:
373
318
 
374
319
  installPrototype(runtime);
375
320
 
376
- std::lock_guard<std::mutex> lock(getPrototypeCacheMutex());
377
- auto &entry = getPrototypeCache(runtime).get(runtime);
378
- if (!entry.prototype.has_value()) {
321
+ auto *prototype = getCachedPrototype(runtime);
322
+ if (prototype == nullptr) {
379
323
  return;
380
324
  }
381
325
 
@@ -391,10 +335,10 @@ public:
391
335
 
392
336
  // Set the prototype property on the constructor
393
337
  // This is what makes `instanceof` work
394
- ctor.setProperty(runtime, "prototype", *entry.prototype);
338
+ ctor.setProperty(runtime, "prototype", *prototype);
395
339
 
396
340
  // Set constructor property on prototype pointing back to constructor
397
- entry.prototype->setProperty(runtime, "constructor", ctor);
341
+ prototype->setProperty(runtime, "constructor", ctor);
398
342
 
399
343
  // Install on global
400
344
  runtime.global().setProperty(runtime, Derived::CLASS_NAME, std::move(ctor));
@@ -417,17 +361,11 @@ public:
417
361
  obj.setNativeState(runtime, instance);
418
362
 
419
363
  // Set prototype
420
- {
421
- std::lock_guard<std::mutex> lock(getPrototypeCacheMutex());
422
- auto &entry = getPrototypeCache(runtime).get(runtime);
423
- if (entry.prototype.has_value()) {
424
- // Use Object.setPrototypeOf to set the prototype
425
- auto objectCtor =
426
- runtime.global().getPropertyAsObject(runtime, "Object");
427
- auto setPrototypeOf =
428
- objectCtor.getPropertyAsFunction(runtime, "setPrototypeOf");
429
- setPrototypeOf.call(runtime, obj, *entry.prototype);
430
- }
364
+ if (auto *prototype = getCachedPrototype(runtime)) {
365
+ auto objectCtor = runtime.global().getPropertyAsObject(runtime, "Object");
366
+ auto setPrototypeOf =
367
+ objectCtor.getPropertyAsFunction(runtime, "setPrototypeOf");
368
+ setPrototypeOf.call(runtime, obj, *prototype);
431
369
  }
432
370
 
433
371
  // Set memory pressure hint for GC
@@ -61,9 +61,6 @@ RNWebGPUManager::RNWebGPUManager(
61
61
  : _jsRuntime(jsRuntime), _jsCallInvoker(jsCallInvoker),
62
62
  _platformContext(platformContext) {
63
63
 
64
- // Register main runtime for RuntimeAwareCache
65
- BaseRuntimeAwareCache::setMainJsRuntime(_jsRuntime);
66
-
67
64
  // Register the main runtime + its CallInvoker so spontaneous events
68
65
  // (device.lost / uncapturederror) on main-runtime devices can be delivered to
69
66
  // the JS thread without the ProcessEvents pump. Worklet-runtime devices have
@@ -81,6 +81,10 @@ public:
81
81
  ~SurfaceInfo() {
82
82
  // Drop the Dawn objects before releasing the native surfaces they borrow.
83
83
  _surface = nullptr;
84
+ #if defined(__ANDROID__)
85
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
86
+ _surfaceDevice = nullptr;
87
+ #endif
84
88
  _pendingSurface = nullptr;
85
89
  _texture = nullptr;
86
90
  if (_pendingReleaser && _pendingNativeSurface) {
@@ -170,6 +174,10 @@ public:
170
174
  replacedSurface = _nativeSurface;
171
175
  replacedReleaser = std::move(_releaser);
172
176
  _surface = std::move(_pendingSurface);
177
+ #if defined(__ANDROID__)
178
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
179
+ _surfaceDevice = nullptr;
180
+ #endif
173
181
  _nativeSurface = _pendingNativeSurface;
174
182
  _releaser = std::move(_pendingReleaser);
175
183
  _hasPendingAttach = false;
@@ -187,7 +195,7 @@ public:
187
195
  if (blit) {
188
196
  config.usage |= wgpu::TextureUsage::CopyDst;
189
197
  }
190
- _surface.Configure(&config);
198
+ configureSurfaceLocked(config);
191
199
  #ifdef __APPLE__
192
200
  applyCAMetalLayerColorSpace(_nativeSurface, _config.format);
193
201
  #endif
@@ -275,6 +283,38 @@ public:
275
283
  return _config.device != nullptr;
276
284
  }
277
285
 
286
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
287
+ // Called right before `device` is destroyed. If the Dawn surface holds a
288
+ // swapchain for that device, drop the surface now, while the device is
289
+ // still alive, and recreate an unconfigured one for the same native window
290
+ // so a later configure() with another device still renders on screen.
291
+ //
292
+ // Why: on Vulkan, tearing a swapchain down (SwapChain::DetachFromSurfaceImpl)
293
+ // goes through the device's FencedDeleter. Dawn only tears it down when the
294
+ // surface is reconfigured or destroyed, and Unconfigure() is not enough (it
295
+ // parks the swapchain as "recycled" for the next Configure). So when the
296
+ // native view is dropped after device.destroy(), ~Surface dereferences the
297
+ // dead device (SIGSEGV, fault addr 0x20). Android only: Metal's detach does
298
+ // not touch the device, and this must not change behaviour there.
299
+ //
300
+ // Remove once the pinned Dawn contains the upstream fix; the check in
301
+ // scripts/install-dawn.ts fails the install when the Dawn pin changes so
302
+ // that decision is not forgotten.
303
+ void releaseSurfaceForDevice(const wgpu::Device &device) {
304
+ #if defined(__ANDROID__)
305
+ std::unique_lock<std::shared_mutex> lock(_mutex);
306
+ if (!_surface || !_surfaceDevice || _surfaceDevice.Get() != device.Get()) {
307
+ return;
308
+ }
309
+ // Left unconfigured: _config still names the destroyed device, and
310
+ // configuring against it would only raise a validation error. The next
311
+ // configure() from JS (or a surface re-attach) configures it.
312
+ recreateSurfaceLocked();
313
+ #else
314
+ (void)device;
315
+ #endif
316
+ }
317
+
278
318
  // True while a native view owns a surface for this context (attached or
279
319
  // pending adoption). Used to decide which side retires the registry entry:
280
320
  // the native view's teardown when a surface exists, the JS Canvas cleanup
@@ -384,6 +424,10 @@ private:
384
424
  _texture = createOffscreenTextureLocked();
385
425
  }
386
426
  _surface = nullptr;
427
+ #if defined(__ANDROID__)
428
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
429
+ _surfaceDevice = nullptr;
430
+ #endif
387
431
  // The in-flight frame (if any) rendered into the destroyed surface;
388
432
  // presentFrame() must not present it.
389
433
  _acquiredFromSurface = false;
@@ -432,7 +476,12 @@ private:
432
476
  wgpu::SurfaceGetCurrentTextureStatus::Error) {
433
477
  return nullptr;
434
478
  }
435
- _surface.Configure(&_config);
479
+ configureSurfaceLocked(_config);
480
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE: the reconfigure
481
+ // may have replaced the surface and failed to create a new one.
482
+ if (!_surface) {
483
+ return nullptr;
484
+ }
436
485
  _surface.GetCurrentTexture(&surfaceTexture);
437
486
  if (!isAcquireSuccess(surfaceTexture)) {
438
487
  return nullptr;
@@ -480,7 +529,7 @@ private:
480
529
 
481
530
  void _configureLocked() {
482
531
  if (_surface) {
483
- _surface.Configure(&_config);
532
+ configureSurfaceLocked(_config);
484
533
  #ifdef __APPLE__
485
534
  applyCAMetalLayerColorSpace(_nativeSurface, _config.format);
486
535
  #endif
@@ -489,7 +538,67 @@ private:
489
538
  }
490
539
  }
491
540
 
541
+ // Every Surface::Configure goes through here. Once the
542
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE lines are gone, this
543
+ // is a plain wrapper around _surface.Configure.
544
+ void configureSurfaceLocked(const wgpu::SurfaceConfiguration &config) {
545
+ #if defined(__ANDROID__)
546
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
547
+ // Vulkan refuses to switch a surface to another device and keeps the old
548
+ // swapchain attached, so a device change (device swap, recovery after a
549
+ // lost device, a re-run effect) is done with a fresh surface. This also
550
+ // tears the old swapchain down while its device is still alive.
551
+ if (_surfaceDevice && _surfaceDevice.Get() != config.device.Get()) {
552
+ recreateSurfaceLocked();
553
+ if (!_surface) {
554
+ return;
555
+ }
556
+ }
557
+ #endif
558
+ _surface.Configure(&config);
559
+ #if defined(__ANDROID__)
560
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
561
+ _surfaceDevice = config.device;
562
+ #endif
563
+ }
564
+
565
+ #if defined(__ANDROID__)
566
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
567
+ // Replace _surface with a new, unconfigured surface for the same native
568
+ // window. Dropping the old one runs ~Surface, which detaches both the
569
+ // active and the recycled swapchain against their still-alive device.
570
+ void recreateSurfaceLocked() {
571
+ _surface = nullptr;
572
+ _surfaceDevice = nullptr;
573
+ // A frame acquired from the old surface can no longer be presented.
574
+ _acquiredFromSurface = false;
575
+ _frameEpoch++;
576
+ if (_nativeSurface) {
577
+ wgpu::SurfaceSourceAndroidNativeWindow source;
578
+ source.window = _nativeSurface;
579
+ wgpu::SurfaceDescriptor descriptor;
580
+ descriptor.nextInChain = &source;
581
+ _surface = _gpu.CreateSurface(&descriptor);
582
+ }
583
+ }
584
+ #endif
585
+
492
586
  mutable std::shared_mutex _mutex;
587
+ #if defined(__ANDROID__)
588
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
589
+ // The device _surface was last configured with. Dawn keeps a swapchain for
590
+ // that device inside the surface even after Unconfigure() (it is recycled
591
+ // for the next Configure), so this outlives _config.device on purpose and
592
+ // is only reset when _surface itself is dropped or replaced. Owning: Dawn
593
+ // destroys a device when its last external reference goes away, which
594
+ // would leave the swapchain with a dead device just like an explicit
595
+ // destroy(). Declared before _surface so it is released after it.
596
+ //
597
+ // Android only: this is an extra owning reference to the device, and on
598
+ // Metal (where the detach never touches the device) it would keep a
599
+ // device alive past its last JS reference for no reason.
600
+ wgpu::Device _surfaceDevice = nullptr;
601
+ #endif
493
602
  // Attached on-screen surface (null while offscreen).
494
603
  void *_nativeSurface = nullptr;
495
604
  wgpu::Surface _surface = nullptr;
@@ -579,6 +688,30 @@ public:
579
688
  _registry.erase(it);
580
689
  }
581
690
 
691
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
692
+ // See SurfaceInfo::releaseSurfaceForDevice. Lock order is registry ->
693
+ // SurfaceInfo, matching every other path.
694
+ void releaseSurfacesForDevice(const wgpu::Device &device) {
695
+ std::vector<std::shared_ptr<SurfaceInfo>> infos;
696
+ {
697
+ // Walking _allSurfaces, not _registry: a GPUCanvasContext keeps its own
698
+ // shared_ptr, so an entry erased by clear() (dev reload) or by
699
+ // removeSurfaceInfo() can still be alive and still hold a swapchain for
700
+ // this device.
701
+ std::unique_lock<std::shared_mutex> lock(_mutex);
702
+ pruneAllSurfacesLocked();
703
+ infos.reserve(_allSurfaces.size());
704
+ for (auto &weak : _allSurfaces) {
705
+ if (auto info = weak.lock()) {
706
+ infos.push_back(std::move(info));
707
+ }
708
+ }
709
+ }
710
+ for (auto &info : infos) {
711
+ info->releaseSurfaceForDevice(device);
712
+ }
713
+ }
714
+
582
715
  // Drops all entries. Called when the RN instance tears down (dev reload):
583
716
  // JS context ids restart from scratch, so surviving entries would alias new
584
717
  // canvases onto dead surfaces.
@@ -600,11 +733,28 @@ private:
600
733
  }
601
734
  auto info = std::make_shared<SurfaceInfo>(gpu, width, height);
602
735
  _registry[id] = info;
736
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
737
+ pruneAllSurfacesLocked();
738
+ _allSurfaces.push_back(info);
603
739
  return info;
604
740
  }
605
741
 
742
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
743
+ void pruneAllSurfacesLocked() {
744
+ _allSurfaces.erase(
745
+ std::remove_if(_allSurfaces.begin(), _allSurfaces.end(),
746
+ [](const std::weak_ptr<SurfaceInfo> &weak) {
747
+ return weak.expired();
748
+ }),
749
+ _allSurfaces.end());
750
+ }
751
+
606
752
  mutable std::shared_mutex _mutex;
607
753
  std::unordered_map<int, std::shared_ptr<SurfaceInfo>> _registry;
754
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
755
+ // Every live SurfaceInfo, including the ones no longer in _registry.
756
+ // Non-owning; pruned on insert and on every device destroy.
757
+ std::vector<std::weak_ptr<SurfaceInfo>> _allSurfaces;
608
758
  };
609
759
 
610
760
  } // namespace rnwgpu
@@ -66,6 +66,48 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
66
66
  }
67
67
  }
68
68
 
69
+ // Request Dawn's ImplicitDeviceSynchronization feature by default. Dawn's
70
+ // native API is not thread-safe without it, and the react-native-wgpu model
71
+ // is "create the device on the JS thread, render from a worklet runtime",
72
+ // which uses one device from several threads. The feature wraps device and
73
+ // child-object entry points in a per-device mutex (command *encoding* stays
74
+ // unsynchronized: never share a GPUCommandEncoder across threads). Dawn
75
+ // exposes the feature on every physical device, but keep the support check
76
+ // so a hypothetical adapter without it still vends a device. Callers can opt
77
+ // out with `implicitDeviceSynchronization: false` on the device descriptor
78
+ // to skip the (small) per-call locking overhead when the device is only ever
79
+ // used from a single thread.
80
+ {
81
+ const bool optedOut = descriptor.has_value() &&
82
+ descriptor.value()->implicitDeviceSynchronization ==
83
+ std::optional<bool>(false);
84
+ if (!optedOut) {
85
+ wgpu::SupportedFeatures supported;
86
+ _instance.GetFeatures(&supported);
87
+ const bool isSupported =
88
+ std::find(supported.features,
89
+ supported.features + supported.featureCount,
90
+ wgpu::FeatureName::ImplicitDeviceSynchronization) !=
91
+ supported.features + supported.featureCount;
92
+ if (isSupported) {
93
+ if (!descriptor.has_value()) {
94
+ descriptor = std::make_shared<GPUDeviceDescriptor>();
95
+ }
96
+ auto &desc = descriptor.value();
97
+ if (!desc->requiredFeatures.has_value()) {
98
+ desc->requiredFeatures = std::vector<wgpu::FeatureName>{};
99
+ }
100
+ auto &features = desc->requiredFeatures.value();
101
+ if (std::find(features.begin(), features.end(),
102
+ wgpu::FeatureName::ImplicitDeviceSynchronization) ==
103
+ features.end()) {
104
+ features.push_back(
105
+ wgpu::FeatureName::ImplicitDeviceSynchronization);
106
+ }
107
+ }
108
+ }
109
+ }
110
+
69
111
  wgpu::DeviceDescriptor aDescriptor;
70
112
  Convertor conv;
71
113
  if (!conv(aDescriptor, descriptor)) {
@@ -285,7 +327,7 @@ std::unordered_set<std::string> GPUAdapter::getFeatures() {
285
327
 
286
328
  std::shared_ptr<GPUSupportedLimits> GPUAdapter::getLimits() {
287
329
  wgpu::Limits limits{};
288
- if (!_instance.GetLimits(&limits)) {
330
+ if (_instance.GetLimits(&limits) != wgpu::Status::Success) {
289
331
  throw std::runtime_error("Failed to get limits");
290
332
  }
291
333
  return std::make_shared<GPUSupportedLimits>(limits);
@@ -16,6 +16,7 @@
16
16
  #include "GPUOutOfMemoryError.h"
17
17
  #include "GPUValidationError.h"
18
18
  #include "RnFeatures.h"
19
+ #include "SurfaceRegistry.h"
19
20
 
20
21
  namespace rnwgpu {
21
22
 
@@ -124,7 +125,7 @@ GPUDevice::createBuffer(std::shared_ptr<GPUBufferDescriptor> descriptor) {
124
125
 
125
126
  std::shared_ptr<GPUSupportedLimits> GPUDevice::getLimits() {
126
127
  wgpu::Limits limits{};
127
- if (!_instance.GetLimits(&limits)) {
128
+ if (_instance.GetLimits(&limits) != wgpu::Status::Success) {
128
129
  throw std::runtime_error("failed to get device limits");
129
130
  }
130
131
  return std::make_shared<GPUSupportedLimits>(limits);
@@ -149,6 +150,10 @@ std::shared_ptr<GPUCommandEncoder> GPUDevice::createCommandEncoder(
149
150
  }
150
151
 
151
152
  void GPUDevice::destroy() {
153
+ // DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
154
+ // Any canvas surface holding a swapchain for this device must let go of it
155
+ // while the device is alive (see SurfaceInfo::releaseSurfaceForDevice).
156
+ SurfaceRegistry::getInstance().releaseSurfacesForDevice(_instance);
152
157
  _instance.Destroy();
153
158
  notifyDeviceLost(wgpu::DeviceLostReason::Destroyed, "device was destroyed");
154
159
  }
@@ -190,7 +190,7 @@ std::shared_ptr<GPUExternalTexture> GPUExternalTexture::Create(
190
190
  wgpu::SharedTextureMemoryBeginAccessDescriptor begin{};
191
191
  begin.initialized = true;
192
192
  begin.concurrentRead = false;
193
- if (!memory.BeginAccess(texture, &begin)) {
193
+ if (memory.BeginAccess(texture, &begin) != wgpu::Status::Success) {
194
194
  throw std::runtime_error(
195
195
  "GPUExternalTexture::Create(): BeginAccess failed");
196
196
  }
@@ -240,8 +240,7 @@ std::shared_ptr<GPUExternalTexture> GPUExternalTexture::Create(
240
240
 
241
241
  auto external = device.CreateExternalTexture(&extDesc);
242
242
  if (external == nullptr) {
243
- wgpu::SharedTextureMemoryEndAccessState state{};
244
- (void)memory.EndAccess(texture, &state);
243
+ endAccess(memory, texture);
245
244
  throw std::runtime_error(
246
245
  "GPUExternalTexture::Create(): CreateExternalTexture returned "
247
246
  "null");
@@ -289,7 +288,7 @@ std::shared_ptr<GPUExternalTexture> GPUExternalTexture::Create(
289
288
  begin.concurrentRead = false;
290
289
  wgpu::SharedTextureMemoryVkImageLayoutBeginState beginLayout{};
291
290
  begin.nextInChain = &beginLayout;
292
- if (!memory.BeginAccess(texture, &begin)) {
291
+ if (memory.BeginAccess(texture, &begin) != wgpu::Status::Success) {
293
292
  throw std::runtime_error(
294
293
  "GPUExternalTexture::Create(): BeginAccess failed");
295
294
  }
@@ -310,7 +309,7 @@ std::shared_ptr<GPUExternalTexture> GPUExternalTexture::Create(
310
309
  wgpu::SharedTextureMemoryAHardwareBufferProperties ahbProps{};
311
310
  wgpu::SharedTextureMemoryProperties props{};
312
311
  props.nextInChain = &ahbProps;
313
- if (memory.GetProperties(&props)) {
312
+ if (memory.GetProperties(&props) == wgpu::Status::Success) {
314
313
  yuvToRgbMatrix = makeYuvToRgbMatrix(ahbProps.yCbCrInfo.vkYCbCrModel,
315
314
  ahbProps.yCbCrInfo.vkYCbCrRange);
316
315
  } else {
@@ -345,8 +344,7 @@ std::shared_ptr<GPUExternalTexture> GPUExternalTexture::Create(
345
344
 
346
345
  auto external = device.CreateExternalTexture(&extDesc);
347
346
  if (external == nullptr) {
348
- wgpu::SharedTextureMemoryEndAccessState state{};
349
- (void)memory.EndAccess(texture, &state);
347
+ endAccess(memory, texture);
350
348
  throw std::runtime_error(
351
349
  "GPUExternalTexture::Create(): CreateExternalTexture returned "
352
350
  "null");
@@ -58,19 +58,39 @@ public:
58
58
  // destroy() the producer's surface (e.g. an AVPlayer IOSurface) stays claimed
59
59
  // until GC runs. EndAccess is the designed post-submit call: Dawn keeps the
60
60
  // texture alive for in-flight GPU work via the fences it returns.
61
+ // Destroying the texture and the external texture is what actually frees
62
+ // the import: the ExternalTexture's views keep the imported VkImage /
63
+ // IOSurface texture alive until the object itself is destroyed, which
64
+ // otherwise only happens once the JS wrapper (and any bind group that
65
+ // sampled it) is garbage-collected.
61
66
  void destroy() {
62
67
  if (_memory && _texture) {
63
- wgpu::SharedTextureMemoryEndAccessState state{};
64
- (void)_memory.EndAccess(_texture, &state);
68
+ endAccess(_memory, _texture);
69
+ }
70
+ if (_texture) {
71
+ _texture.Destroy();
72
+ }
73
+ if (_instance) {
74
+ _instance.Destroy();
75
+ }
76
+ if (_texture) {
77
+ _texture.Destroy();
78
+ }
79
+ if (_instance) {
80
+ _instance.Destroy();
65
81
  }
66
82
  _texture = nullptr;
67
83
  _memory = nullptr;
84
+ _instance = nullptr;
85
+ _source = nullptr;
68
86
  }
69
87
 
70
88
  std::string getLabel() { return _label; }
71
89
  void setLabel(const std::string &label) {
72
90
  _label = label;
73
- _instance.SetLabel(_label.c_str());
91
+ if (_instance) {
92
+ _instance.SetLabel(_label.c_str());
93
+ }
74
94
  }
75
95
 
76
96
  // Non-spec extension. A 3x4 row-major matrix mapping the *sampled* texel
@@ -97,6 +117,23 @@ public:
97
117
 
98
118
  inline const wgpu::ExternalTexture get() { return _instance; }
99
119
 
120
+ // End the shared-memory access window on `texture`. Shared by destroy() and
121
+ // the Create() error paths so every EndAccess carries the same chain: Dawn's
122
+ // Vulkan backend rejects the call unless a
123
+ // SharedTextureMemoryVkImageLayoutEndState is chained (it writes the
124
+ // released VkImage layouts there), while the Metal backend only accepts its
125
+ // own optional end state. The returned fences are dropped: Dawn keeps the
126
+ // texture alive for in-flight GPU work on its own.
127
+ static void endAccess(const wgpu::SharedTextureMemory &memory,
128
+ const wgpu::Texture &texture) {
129
+ wgpu::SharedTextureMemoryEndAccessState state{};
130
+ #if defined(__ANDROID__)
131
+ wgpu::SharedTextureMemoryVkImageLayoutEndState vkLayout{};
132
+ state.nextInChain = &vkLayout;
133
+ #endif
134
+ (void)memory.EndAccess(texture, &state);
135
+ }
136
+
100
137
  private:
101
138
  wgpu::ExternalTexture _instance;
102
139
  wgpu::SharedTextureMemory _memory;
@@ -115,7 +115,8 @@ namespace rnwgpu {
115
115
  V(RenderPassRenderArea, "render-pass-render-area") \
116
116
  V(AdapterPropertiesDrm, "adapter-properties-drm") \
117
117
  V(TextureCompressionUnaligned, "texture-compression-unaligned") \
118
- V(DawnAllowUndefinedLoadStoreOp, "dawn-allow-undefined-load-store-op")
118
+ V(DawnAllowUndefinedLoadStoreOp, "dawn-allow-undefined-load-store-op") \
119
+ V(BufferMapWriteExtendedUsages, "buffer-map-write-extended-usages")
119
120
 
120
121
  static void convertEnumToJSUnion(wgpu::FeatureName inEnum,
121
122
  std::string *outUnion) {
@@ -75,7 +75,7 @@ void GPUSharedTextureMemory::beginAccess(
75
75
  #endif
76
76
 
77
77
  auto status = _instance.BeginAccess(texture->get(), &desc);
78
- if (!status) {
78
+ if (status != wgpu::Status::Success) {
79
79
  throw std::runtime_error("GPUSharedTextureMemory::beginAccess() failed");
80
80
  }
81
81
  }
@@ -101,7 +101,7 @@ jsi::Value GPUSharedTextureMemory::endAccess(jsi::Runtime &runtime,
101
101
  #endif
102
102
 
103
103
  auto status = _instance.EndAccess(texture->get(), &state);
104
- if (!status) {
104
+ if (status != wgpu::Status::Success) {
105
105
  throw jsi::JSError(runtime, "GPUSharedTextureMemory::endAccess() failed");
106
106
  }
107
107
 
@@ -29,6 +29,11 @@ struct GPUDeviceDescriptor {
29
29
  // Non-standard Dawn-only device toggles, chained onto the wgpu::Device
30
30
  // descriptor in GPUAdapter::requestDevice.
31
31
  std::optional<std::shared_ptr<GPUDawnTogglesDescriptor>> dawnToggles;
32
+ // Non-standard RN extension. Dawn's ImplicitDeviceSynchronization feature is
33
+ // requested by default so a single device can be used from several runtimes
34
+ // (JS thread + worklet runtimes). Set to false to opt out and get an
35
+ // unsynchronized (single-thread only) device.
36
+ std::optional<bool> implicitDeviceSynchronization;
32
37
  };
33
38
 
34
39
  } // namespace rnwgpu
@@ -108,6 +113,12 @@ template <> struct JSIConverter<std::shared_ptr<rnwgpu::GPUDeviceDescriptor>> {
108
113
  std::optional<std::shared_ptr<GPUDawnTogglesDescriptor>>>::fromJSI(
109
114
  runtime, prop, false);
110
115
  }
116
+ if (value.hasProperty(runtime, "implicitDeviceSynchronization")) {
117
+ auto prop =
118
+ value.getProperty(runtime, "implicitDeviceSynchronization");
119
+ result->implicitDeviceSynchronization =
120
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, prop, false);
121
+ }
111
122
  }
112
123
 
113
124
  return result;