react-native-webgpu 0.19.2 → 0.20.0

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 (65) hide show
  1. package/Package.swift +19 -7
  2. package/android/build.gradle +7 -0
  3. package/apple/ApplePlatformContext.h +6 -1
  4. package/apple/ApplePlatformContext.mm +7 -8
  5. package/apple/MetalLayerColorSpace.mm +17 -1
  6. package/apple/WebGPUModule.mm +15 -1
  7. package/cpp/jsi/Promise.cpp +4 -0
  8. package/cpp/jsi/Promise.h +3 -0
  9. package/cpp/rnwgpu/CanvasColorSpace.h +5 -0
  10. package/cpp/rnwgpu/RNWebGPUManager.cpp +2 -4
  11. package/cpp/rnwgpu/SurfaceRegistry.h +16 -7
  12. package/cpp/rnwgpu/WebGPURuntime.cpp +2 -1
  13. package/cpp/rnwgpu/api/GPU.cpp +6 -6
  14. package/cpp/rnwgpu/api/GPU.h +1 -1
  15. package/cpp/rnwgpu/api/GPUAdapter.cpp +28 -2
  16. package/cpp/rnwgpu/api/GPUBuffer.cpp +5 -6
  17. package/cpp/rnwgpu/api/GPUCanvasContext.cpp +2 -1
  18. package/cpp/rnwgpu/api/GPUDevice.cpp +38 -47
  19. package/cpp/rnwgpu/api/GPUDevice.h +4 -5
  20. package/cpp/rnwgpu/api/GPUQueue.cpp +4 -2
  21. package/cpp/rnwgpu/api/GPUShaderModule.cpp +2 -2
  22. package/cpp/rnwgpu/api/RNWebGPU.h +9 -9
  23. package/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +24 -0
  24. package/cpp/rnwgpu/async/AsyncTaskHandle.cpp +33 -45
  25. package/cpp/rnwgpu/async/AsyncTaskHandle.h +5 -6
  26. package/cpp/rnwgpu/async/RuntimeContext.cpp +321 -112
  27. package/cpp/rnwgpu/async/RuntimeContext.h +90 -82
  28. package/lib/commonjs/Canvas.js +1 -0
  29. package/lib/commonjs/Canvas.js.map +1 -1
  30. package/lib/commonjs/WebGPUViewNativeComponent.js.map +1 -1
  31. package/lib/commonjs/WebGPUViewNativeComponent.web.js.map +1 -1
  32. package/lib/commonjs/external/reanimated/registerWebGPUForReanimated.js +19 -1
  33. package/lib/commonjs/external/reanimated/registerWebGPUForReanimated.js.map +1 -1
  34. package/lib/commonjs/install.js +6 -5
  35. package/lib/commonjs/install.js.map +1 -1
  36. package/lib/module/Canvas.js +1 -0
  37. package/lib/module/Canvas.js.map +1 -1
  38. package/lib/module/WebGPUViewNativeComponent.js.map +1 -1
  39. package/lib/module/WebGPUViewNativeComponent.web.js.map +1 -1
  40. package/lib/module/external/reanimated/registerWebGPUForReanimated.js +19 -1
  41. package/lib/module/external/reanimated/registerWebGPUForReanimated.js.map +1 -1
  42. package/lib/module/install.js +6 -5
  43. package/lib/module/install.js.map +1 -1
  44. package/lib/typescript/lib/commonjs/Canvas.d.ts.map +1 -1
  45. package/lib/typescript/lib/commonjs/external/reanimated/registerWebGPUForReanimated.d.ts.map +1 -1
  46. package/lib/typescript/lib/commonjs/install.d.ts +6 -5
  47. package/lib/typescript/lib/commonjs/install.d.ts.map +1 -1
  48. package/lib/typescript/lib/module/Canvas.d.ts.map +1 -1
  49. package/lib/typescript/lib/module/external/reanimated/registerWebGPUForReanimated.d.ts.map +1 -1
  50. package/lib/typescript/lib/module/install.d.ts.map +1 -1
  51. package/lib/typescript/src/Canvas.d.ts.map +1 -1
  52. package/lib/typescript/src/WebGPUViewNativeComponent.d.ts +6 -7
  53. package/lib/typescript/src/WebGPUViewNativeComponent.d.ts.map +1 -1
  54. package/lib/typescript/src/WebGPUViewNativeComponent.web.d.ts +2 -3
  55. package/lib/typescript/src/WebGPUViewNativeComponent.web.d.ts.map +1 -1
  56. package/lib/typescript/src/external/reanimated/registerWebGPUForReanimated.d.ts +1 -0
  57. package/lib/typescript/src/external/reanimated/registerWebGPUForReanimated.d.ts.map +1 -1
  58. package/lib/typescript/src/install.d.ts +6 -5
  59. package/lib/typescript/src/install.d.ts.map +1 -1
  60. package/package.json +2 -2
  61. package/src/Canvas.tsx +4 -2
  62. package/src/WebGPUViewNativeComponent.ts +6 -10
  63. package/src/WebGPUViewNativeComponent.web.ts +2 -3
  64. package/src/external/reanimated/registerWebGPUForReanimated.ts +21 -1
  65. package/src/install.ts +6 -5
@@ -14,12 +14,12 @@
14
14
  #include "GPUCanvasContext.h"
15
15
  #include "GPUDevice.h"
16
16
  #include "GPUTexture.h"
17
- #include "rnwgpu/async/RuntimeContext.h"
18
17
  #include "ImageBitmap.h"
19
18
  #include "PlatformContext.h"
20
19
  #include "VideoFrame.h"
21
20
  #include "VideoPlayer.h"
22
21
  #include "WebGPURuntime.h"
22
+ #include "rnwgpu/async/RuntimeContext.h"
23
23
 
24
24
  #include <ReactCommon/CallInvoker.h>
25
25
 
@@ -132,8 +132,8 @@ public:
132
132
  // Skia's Graphite device from Skia.getNativeDevice()) in a GPUDevice.
133
133
  // AddRefs the handle, so the original owner keeps its reference. Only sound
134
134
  // because the process links a single Dawn copy. The device's async
135
- // callbacks are pumped on the instance that owns it (RuntimeContext is per
136
- // runtime and per instance), which is not necessarily the shared one:
135
+ // callbacks are waited for on the instance that owns it (RuntimeContext is
136
+ // per runtime and per instance), which is not necessarily the shared one:
137
137
  // WebGPURuntime adopts Skia's instance only when Skia's getter is reachable
138
138
  // as the instance is first used (on Android, only once librnskia.so is
139
139
  // loaded), and other exporters have their own.
@@ -240,14 +240,14 @@ public:
240
240
  std::vector<uint8_t> dataCopy(data.begin(), data.end());
241
241
 
242
242
  return Promise::createPromise(
243
- runtime,
244
- [platformContext, callInvoker, toRequestedAlpha,
245
- dataCopy = std::move(dataCopy)](
246
- jsi::Runtime & /*runtime*/,
247
- std::shared_ptr<Promise> promise) mutable {
243
+ runtime, [platformContext, callInvoker, toRequestedAlpha,
244
+ dataCopy = std::move(dataCopy)](
245
+ jsi::Runtime & /*runtime*/,
246
+ std::shared_ptr<Promise> promise) mutable {
248
247
  platformContext->createImageBitmapFromDataAsync(
249
248
  dataCopy,
250
- [callInvoker, promise, toRequestedAlpha](ImageData imageData) {
249
+ [callInvoker, promise,
250
+ toRequestedAlpha](ImageData imageData) {
251
251
  toRequestedAlpha(imageData);
252
252
  auto imageBitmap = std::make_shared<ImageBitmap>(imageData);
253
253
  callInvoker->invokeAsync([promise, imageBitmap]() {
@@ -22,6 +22,7 @@ struct GPUCanvasConfiguration {
22
22
  viewFormats; // Iterable<GPUTextureFormat>
23
23
  wgpu::CompositeAlphaMode alphaMode = wgpu::CompositeAlphaMode::Opaque;
24
24
  CanvasColorSpace colorSpace = CanvasColorSpace::SRGB;
25
+ CanvasToneMappingMode toneMappingMode = CanvasToneMappingMode::Standard;
25
26
  };
26
27
 
27
28
  } // namespace rnwgpu
@@ -81,6 +82,29 @@ struct JSIConverter<std::shared_ptr<rnwgpu::GPUCanvasConfiguration>> {
81
82
  }
82
83
  }
83
84
  }
85
+ if (value.hasProperty(runtime, "toneMapping")) {
86
+ auto prop = value.getProperty(runtime, "toneMapping");
87
+ if (prop.isObject()) {
88
+ auto toneMapping = prop.getObject(runtime);
89
+ if (toneMapping.hasProperty(runtime, "mode")) {
90
+ auto mode = toneMapping.getProperty(runtime, "mode");
91
+ if (!mode.isUndefined()) {
92
+ auto name = mode.asString(runtime).utf8(runtime);
93
+ if (name == "extended") {
94
+ result->toneMappingMode = CanvasToneMappingMode::Extended;
95
+ } else if (name != "standard") {
96
+ throw jsi::JSError(
97
+ runtime,
98
+ "Failed to execute 'configure' on 'GPUCanvasContext': "
99
+ "The provided value '" +
100
+ name +
101
+ "' is not a valid enum value of type "
102
+ "GPUCanvasToneMappingMode.");
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
84
108
  }
85
109
 
86
110
  return result;
@@ -15,8 +15,8 @@ using Action = std::function<void(jsi::Runtime &, rnwgpu::Promise &)>;
15
15
 
16
16
  struct AsyncTaskHandle::State
17
17
  : public std::enable_shared_from_this<AsyncTaskHandle::State> {
18
- State(std::shared_ptr<RuntimeContext> context, bool keepPumping)
19
- : context(std::move(context)), keepPumping(keepPumping) {}
18
+ explicit State(std::shared_ptr<RuntimeContext> context)
19
+ : context(std::move(context)) {}
20
20
 
21
21
  void settle(Action action);
22
22
  void attachPromise(const std::shared_ptr<rnwgpu::Promise> &promise);
@@ -29,7 +29,6 @@ struct AsyncTaskHandle::State
29
29
 
30
30
  std::mutex mutex;
31
31
  std::shared_ptr<RuntimeContext> context;
32
- bool keepPumping;
33
32
  std::shared_ptr<rnwgpu::Promise> promise;
34
33
  std::optional<Action> pendingAction;
35
34
  bool settled = false;
@@ -92,47 +91,37 @@ void AsyncTaskHandle::State::schedule(Action action) {
92
91
  return;
93
92
  }
94
93
 
94
+ // Any thread here: the settle (the only JSI-touching work) runs on the
95
+ // owning runtime's thread, however the context reaches it. A settle that
96
+ // throws (a value factory that cannot make its value, say) rejects the
97
+ // promise rather than leaving it pending, and ends the operation all the
98
+ // same, so that a runtime polling its mailbox stops.
95
99
  auto self = shared_from_this();
96
-
97
- if (!keepPumping) {
98
- // Spontaneous task (e.g. device.lost): not driven by the ProcessEvents pump.
99
- // Settle on the owning runtime's JS thread via its CallInvoker, which is
100
- // wired only for the main JS runtime. A device created on a worklet runtime
101
- // has no invoker, so its device.lost is dropped (best-effort; see the README
102
- // "Threading model"). invokeAsync runs the closure on the main JS thread,
103
- // where promiseRef->runtime lives for a main-runtime device.
104
- auto invoker = context->callInvoker();
105
- if (invoker) {
106
- invoker->invokeAsync(
107
- [self, action = std::move(action), promiseRef]() mutable {
108
- action(promiseRef->runtime, *promiseRef);
109
- std::lock_guard<std::mutex> lock(self->mutex);
110
- self->keepAlive.reset();
111
- });
112
- } else {
113
- std::lock_guard<std::mutex> lock(mutex);
114
- keepAlive.reset();
100
+ context->post([self, action = std::move(action),
101
+ promiseRef](jsi::Runtime &runtime) mutable {
102
+ try {
103
+ action(runtime, *promiseRef);
104
+ } catch (const jsi::JSError &error) {
105
+ try {
106
+ // The JS error itself (a RangeError for a typed array too large,
107
+ // say), name and stack kept.
108
+ promiseRef->reject(error);
109
+ } catch (...) {
110
+ // Rejected already, or the runtime refused: nothing more to do.
111
+ }
112
+ } catch (const std::exception &error) {
113
+ try {
114
+ promiseRef->reject(error.what());
115
+ } catch (...) {
116
+ // Rejected already, or the runtime refused: nothing more to do.
117
+ }
115
118
  }
116
- return;
117
- }
118
-
119
- // Pumping task (request/response op). The resolve/reject callback may fire on
120
- // a thread that is NOT the owning runtime's thread: with a shared
121
- // wgpu::Instance, another runtime's ProcessEvents() pump can consume this Dawn
122
- // event. Touching the Promise's runtime off-thread would corrupt Hermes. So we
123
- // deposit the actual settle (the only JSI-touching work) into the owning
124
- // context's mailbox; the context drains it on its own thread during its next
125
- // tick. The deposited closure captures only C++ state and runs no JSI until
126
- // drained, so depositing from any thread is safe.
127
- context->postSettle(
128
- [self, action = std::move(action), promiseRef]() mutable {
129
- action(promiseRef->runtime, *promiseRef);
130
- if (self->context) {
131
- self->context->onTaskSettled(/*keepPumping=*/true);
132
- }
133
- std::lock_guard<std::mutex> lock(self->mutex);
134
- self->keepAlive.reset();
135
- });
119
+ if (self->context) {
120
+ self->context->onTaskSettled();
121
+ }
122
+ std::lock_guard<std::mutex> lock(self->mutex);
123
+ self->keepAlive.reset();
124
+ });
136
125
  }
137
126
 
138
127
  AsyncTaskHandle::ResolveFunction
@@ -181,9 +170,8 @@ AsyncTaskHandle::AsyncTaskHandle(std::shared_ptr<State> state)
181
170
  bool AsyncTaskHandle::valid() const { return _state != nullptr; }
182
171
 
183
172
  AsyncTaskHandle
184
- AsyncTaskHandle::create(const std::shared_ptr<RuntimeContext> &context,
185
- bool keepPumping) {
186
- auto state = std::make_shared<State>(context, keepPumping);
173
+ AsyncTaskHandle::create(const std::shared_ptr<RuntimeContext> &context) {
174
+ auto state = std::make_shared<State>(context);
187
175
  state->keepAlive = state;
188
176
  return AsyncTaskHandle(std::move(state));
189
177
  }
@@ -20,10 +20,10 @@ class RuntimeContext;
20
20
  * Represents a pending asynchronous WebGPU operation that can be converted into
21
21
  * a JavaScript Promise.
22
22
  *
23
- * In the ProcessEvents model the resolve/reject callbacks are invoked on the
24
- * owning runtime's own thread (synchronously from instance.ProcessEvents()
25
- * during the RuntimeContext tick, or synchronously from postTask), so the
26
- * Promise is settled directly without any thread marshalling.
23
+ * The resolve and reject functions run on any thread (the instance's waiter
24
+ * thread, usually) and never touch JSI: they hand the settling to the owning
25
+ * RuntimeContext, which runs it on its runtime's own thread (see
26
+ * RuntimeContext::post).
27
27
  */
28
28
  class AsyncTaskHandle {
29
29
  public:
@@ -48,8 +48,7 @@ public:
48
48
 
49
49
  void attachPromise(const std::shared_ptr<rnwgpu::Promise> &promise) const;
50
50
 
51
- static AsyncTaskHandle create(const std::shared_ptr<RuntimeContext> &context,
52
- bool keepPumping);
51
+ static AsyncTaskHandle create(const std::shared_ptr<RuntimeContext> &context);
53
52
 
54
53
  private:
55
54
  std::shared_ptr<State> _state;