react-native-webgpu 0.5.14 → 0.5.15
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.
- package/README.md +19 -6
- package/android/CMakeLists.txt +2 -2
- package/cpp/jsi/NativeObject.h +39 -0
- package/cpp/rnwgpu/RNWebGPUManager.cpp +8 -0
- package/cpp/rnwgpu/SurfaceRegistry.h +33 -1
- package/cpp/rnwgpu/api/GPU.cpp +14 -11
- package/cpp/rnwgpu/api/GPU.h +6 -4
- package/cpp/rnwgpu/api/GPUAdapter.cpp +5 -8
- package/cpp/rnwgpu/api/GPUAdapter.h +3 -3
- package/cpp/rnwgpu/api/GPUBuffer.cpp +23 -24
- package/cpp/rnwgpu/api/GPUBuffer.h +3 -3
- package/cpp/rnwgpu/api/GPUCanvasContext.cpp +13 -16
- package/cpp/rnwgpu/api/GPUCanvasContext.h +3 -0
- package/cpp/rnwgpu/api/GPUDevice.cpp +103 -19
- package/cpp/rnwgpu/api/GPUDevice.h +17 -3
- package/cpp/rnwgpu/api/GPUQueue.h +3 -3
- package/cpp/rnwgpu/api/GPUShaderModule.h +3 -3
- package/cpp/rnwgpu/api/GPUSharedFence.cpp +77 -0
- package/cpp/rnwgpu/api/GPUSharedFence.h +53 -0
- package/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp +60 -11
- package/cpp/rnwgpu/api/GPUSharedTextureMemory.h +13 -9
- package/cpp/rnwgpu/api/descriptors/GPUSharedFenceDescriptor.h +58 -0
- package/cpp/rnwgpu/api/descriptors/GPUSharedFenceState.h +51 -0
- package/cpp/rnwgpu/async/AsyncTaskHandle.cpp +55 -23
- package/cpp/rnwgpu/async/AsyncTaskHandle.h +8 -5
- package/cpp/rnwgpu/async/RuntimeContext.cpp +193 -0
- package/cpp/rnwgpu/async/RuntimeContext.h +122 -0
- package/lib/commonjs/Canvas.js.map +1 -1
- package/lib/commonjs/Offscreen.js +1 -1
- package/lib/commonjs/WebPolyfillGPUModule.js +2 -0
- package/lib/commonjs/WebPolyfillGPUModule.js.map +1 -1
- package/lib/commonjs/constants.js +40 -0
- package/lib/commonjs/constants.js.map +1 -0
- package/lib/commonjs/index.js +22 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/install.js +63 -0
- package/lib/commonjs/install.js.map +1 -0
- package/lib/module/Canvas.js.map +1 -1
- package/lib/module/Offscreen.js +1 -1
- package/lib/module/WebPolyfillGPUModule.js +2 -0
- package/lib/module/WebPolyfillGPUModule.js.map +1 -1
- package/lib/module/constants.js +34 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/install.js +57 -0
- package/lib/module/install.js.map +1 -0
- package/lib/typescript/lib/commonjs/constants.d.ts +3 -0
- package/lib/typescript/lib/commonjs/constants.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/install.d.ts +35 -0
- package/lib/typescript/lib/commonjs/install.d.ts.map +1 -0
- package/lib/typescript/lib/module/constants.d.ts +6 -0
- package/lib/typescript/lib/module/constants.d.ts.map +1 -0
- package/lib/typescript/lib/module/index.d.ts +2 -0
- package/lib/typescript/lib/module/install.d.ts +2 -0
- package/lib/typescript/lib/module/install.d.ts.map +1 -0
- package/lib/typescript/src/Canvas.d.ts +9 -0
- package/lib/typescript/src/Canvas.d.ts.map +1 -1
- package/lib/typescript/src/constants.d.ts +6 -0
- package/lib/typescript/src/constants.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +5 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/install.d.ts +34 -0
- package/lib/typescript/src/install.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +34 -2
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Canvas.tsx +9 -0
- package/src/Offscreen.ts +1 -1
- package/src/WebPolyfillGPUModule.ts +3 -3
- package/src/constants.ts +37 -0
- package/src/index.tsx +13 -2
- package/src/install.ts +61 -0
- package/src/types.ts +69 -3
- package/cpp/rnwgpu/async/AsyncDispatcher.h +0 -28
- package/cpp/rnwgpu/async/AsyncRunner.cpp +0 -215
- package/cpp/rnwgpu/async/AsyncRunner.h +0 -53
- package/cpp/rnwgpu/async/JSIMicrotaskDispatcher.cpp +0 -23
- package/cpp/rnwgpu/async/JSIMicrotaskDispatcher.h +0 -22
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ npm install react-native-webgpu
|
|
|
15
15
|
## With Expo
|
|
16
16
|
|
|
17
17
|
Expo provides a React Native WebGPU template that works with React Three Fiber.
|
|
18
|
-
|
|
18
|
+
This works on iOS, Android, and Web.
|
|
19
19
|
|
|
20
20
|
```
|
|
21
21
|
npx create-expo-app@latest -e with-webgpu
|
|
@@ -174,8 +174,7 @@ ctx.canvas.height = ctx.canvas.clientHeight * PixelRatio.get();
|
|
|
174
174
|
|
|
175
175
|
### Frame Scheduling
|
|
176
176
|
|
|
177
|
-
In React Native,
|
|
178
|
-
This means that when you are ready to present a frame, you need to call `present` on the context.
|
|
177
|
+
In React Native, frame presentation is a manual operation: when you are ready to present a frame, call `present()` on the context after submitting your commands to the queue. This works the same on every runtime: the main JS runtime, the Reanimated UI runtime, and dedicated worklet runtimes (`createWorkletRuntime` / `runOnRuntime`, or a Vision Camera frame processor). `present()` runs synchronously on the calling thread, so the frame is presented from whichever thread did the rendering.
|
|
179
178
|
|
|
180
179
|
```tsx
|
|
181
180
|
// draw
|
|
@@ -185,6 +184,13 @@ device.queue.submit([commandEncoder.finish()]);
|
|
|
185
184
|
context.present();
|
|
186
185
|
```
|
|
187
186
|
|
|
187
|
+
### Threading model
|
|
188
|
+
|
|
189
|
+
react-native-webgpu can drive WebGPU from more than one JavaScript runtime: the main JS runtime, the Reanimated UI runtime, and dedicated worklet runtimes (`createWorkletRuntime` / `runOnRuntime`, or a Vision Camera frame processor).
|
|
190
|
+
This module also works well with [Bundle Mode](https://docs.swmansion.com/react-native-worklets/docs/bundleMode/) and lets you run complex Three.js scenes on the UI thread or dedicated worklet threads.
|
|
191
|
+
|
|
192
|
+
There is a caveat with `device.lost` and `uncapturederror`: they are only delivered on the main JS runtime. This is usually fine because the GPU device is typically created on the main JS thread and then sent to the UI or a dedicated worklet thread. However, if for some reason you create the device outside the main JS thread, beware that `device.lost` and `uncapturederror` won't fire.
|
|
193
|
+
|
|
188
194
|
### Canvas Transparency
|
|
189
195
|
|
|
190
196
|
On Android, the `alphaMode` property is ignored when configuring the canvas.
|
|
@@ -293,10 +299,10 @@ const render = () => {
|
|
|
293
299
|
|
|
294
300
|
// ... encode a pass that samples `externalTexture`, then:
|
|
295
301
|
device.queue.submit([encoder.finish()]);
|
|
302
|
+
context.present();
|
|
296
303
|
|
|
297
304
|
// Release the surface's access window right after the submit that sampled it.
|
|
298
305
|
externalTexture.destroy();
|
|
299
|
-
context.present();
|
|
300
306
|
};
|
|
301
307
|
```
|
|
302
308
|
|
|
@@ -316,14 +322,21 @@ First, install the optional peer dependencies:
|
|
|
316
322
|
npm install react-native-reanimated react-native-worklets
|
|
317
323
|
```
|
|
318
324
|
|
|
319
|
-
WebGPU objects are automatically registered for Worklets serialization when the module loads. You can pass WebGPU objects like `GPUDevice` and `GPUCanvasContext` directly to worklets
|
|
325
|
+
WebGPU objects are automatically registered for Worklets serialization when the module loads. You can pass WebGPU objects like `GPUDevice` and `GPUCanvasContext` directly to worklets.
|
|
326
|
+
Call `installWebGPU()` once at the top of the worklet to install flag constants like `GPUBufferUsage`, `GPUTextureUsage`, and so on.
|
|
320
327
|
|
|
321
328
|
```tsx
|
|
322
|
-
import { Canvas } from "react-native-webgpu";
|
|
329
|
+
import { Canvas, installWebGPU } from "react-native-webgpu";
|
|
323
330
|
import { runOnUI } from "react-native-reanimated";
|
|
324
331
|
|
|
325
332
|
const renderFrame = (device: GPUDevice, context: GPUCanvasContext) => {
|
|
326
333
|
"worklet";
|
|
334
|
+
installWebGPU();
|
|
335
|
+
// WebGPU constants are now available on this worklet thread
|
|
336
|
+
const buffer = device.createBuffer({
|
|
337
|
+
size,
|
|
338
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
|
|
339
|
+
});
|
|
327
340
|
// WebGPU rendering code runs on the UI thread
|
|
328
341
|
const commandEncoder = device.createCommandEncoder();
|
|
329
342
|
// ... render ...
|
package/android/CMakeLists.txt
CHANGED
|
@@ -37,6 +37,7 @@ add_library(${PACKAGE_NAME} SHARED
|
|
|
37
37
|
../cpp/rnwgpu/api/GPUCommandEncoder.cpp
|
|
38
38
|
../cpp/rnwgpu/api/GPUQuerySet.cpp
|
|
39
39
|
../cpp/rnwgpu/api/GPUTexture.cpp
|
|
40
|
+
../cpp/rnwgpu/api/GPUSharedFence.cpp
|
|
40
41
|
../cpp/rnwgpu/api/GPUSharedTextureMemory.cpp
|
|
41
42
|
../cpp/rnwgpu/api/GPUExternalTexture.cpp
|
|
42
43
|
../cpp/rnwgpu/api/GPURenderBundleEncoder.cpp
|
|
@@ -50,9 +51,8 @@ add_library(${PACKAGE_NAME} SHARED
|
|
|
50
51
|
../cpp/jsi/Promise.cpp
|
|
51
52
|
../cpp/jsi/RuntimeLifecycleMonitor.cpp
|
|
52
53
|
../cpp/jsi/RuntimeAwareCache.cpp
|
|
53
|
-
../cpp/rnwgpu/async/
|
|
54
|
+
../cpp/rnwgpu/async/RuntimeContext.cpp
|
|
54
55
|
../cpp/rnwgpu/async/AsyncTaskHandle.cpp
|
|
55
|
-
../cpp/rnwgpu/async/JSIMicrotaskDispatcher.cpp
|
|
56
56
|
)
|
|
57
57
|
|
|
58
58
|
target_include_directories(
|
package/cpp/jsi/NativeObject.h
CHANGED
|
@@ -439,6 +439,29 @@ protected:
|
|
|
439
439
|
prototype.setProperty(runtime, name, func);
|
|
440
440
|
}
|
|
441
441
|
|
|
442
|
+
/**
|
|
443
|
+
* Install a method whose native implementation needs the calling jsi::Runtime
|
|
444
|
+
* as its first parameter. Used by entry points that must act per-runtime
|
|
445
|
+
* (e.g. GPU::requestAdapter, which creates a per-runtime RuntimeContext).
|
|
446
|
+
*/
|
|
447
|
+
template <typename ReturnType, typename... Args>
|
|
448
|
+
static void
|
|
449
|
+
installMethodWithRuntime(jsi::Runtime &runtime, jsi::Object &prototype,
|
|
450
|
+
const char *name,
|
|
451
|
+
ReturnType (Derived::*method)(jsi::Runtime &,
|
|
452
|
+
Args...)) {
|
|
453
|
+
auto func = jsi::Function::createFromHostFunction(
|
|
454
|
+
runtime, jsi::PropNameID::forUtf8(runtime, name), sizeof...(Args),
|
|
455
|
+
[method](jsi::Runtime &rt, const jsi::Value &thisVal,
|
|
456
|
+
const jsi::Value *args, size_t count) -> jsi::Value {
|
|
457
|
+
auto native = Derived::fromValue(rt, thisVal);
|
|
458
|
+
return callMethodWithRuntime(native.get(), method, rt, args,
|
|
459
|
+
std::index_sequence_for<Args...>{},
|
|
460
|
+
count);
|
|
461
|
+
});
|
|
462
|
+
prototype.setProperty(runtime, name, func);
|
|
463
|
+
}
|
|
464
|
+
|
|
442
465
|
/**
|
|
443
466
|
* Install a getter on the prototype.
|
|
444
467
|
*/
|
|
@@ -574,6 +597,22 @@ protected:
|
|
|
574
597
|
}
|
|
575
598
|
|
|
576
599
|
private:
|
|
600
|
+
// Helper to call a method that takes the calling jsi::Runtime as its first
|
|
601
|
+
// parameter, with JSI argument conversion for the rest and JSI conversion of
|
|
602
|
+
// the result.
|
|
603
|
+
template <typename ReturnType, typename... Args, size_t... Is>
|
|
604
|
+
static jsi::Value
|
|
605
|
+
callMethodWithRuntime(Derived *obj,
|
|
606
|
+
ReturnType (Derived::*method)(jsi::Runtime &, Args...),
|
|
607
|
+
jsi::Runtime &runtime, const jsi::Value *args,
|
|
608
|
+
std::index_sequence<Is...>, size_t count) {
|
|
609
|
+
ReturnType result = (obj->*method)(
|
|
610
|
+
runtime, rnwgpu::JSIConverter<std::decay_t<Args>>::fromJSI(
|
|
611
|
+
runtime, args[Is], Is >= count)...);
|
|
612
|
+
return rnwgpu::JSIConverter<std::decay_t<ReturnType>>::toJSI(
|
|
613
|
+
runtime, std::move(result));
|
|
614
|
+
}
|
|
615
|
+
|
|
577
616
|
// Helper to call a method with JSI argument conversion
|
|
578
617
|
template <typename ReturnType, typename... Args, size_t... Is>
|
|
579
618
|
static jsi::Value callMethod(Derived *obj,
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
#include "GPURenderPassEncoder.h"
|
|
32
32
|
#include "GPURenderPipeline.h"
|
|
33
33
|
#include "GPUSampler.h"
|
|
34
|
+
#include "GPUSharedFence.h"
|
|
34
35
|
#include "GPUSharedTextureMemory.h"
|
|
35
36
|
#include "GPUShaderModule.h"
|
|
36
37
|
#include "GPUSupportedLimits.h"
|
|
@@ -63,6 +64,12 @@ RNWebGPUManager::RNWebGPUManager(
|
|
|
63
64
|
// Register main runtime for RuntimeAwareCache
|
|
64
65
|
BaseRuntimeAwareCache::setMainJsRuntime(_jsRuntime);
|
|
65
66
|
|
|
67
|
+
// Register the main runtime + its CallInvoker so spontaneous events
|
|
68
|
+
// (device.lost / uncapturederror) on main-runtime devices can be delivered to
|
|
69
|
+
// the JS thread without the ProcessEvents pump. Worklet-runtime devices have
|
|
70
|
+
// no invoker (best-effort; see README "Threading model").
|
|
71
|
+
async::RuntimeContext::registerMainRuntime(_jsRuntime, _jsCallInvoker);
|
|
72
|
+
|
|
66
73
|
auto gpu = std::make_shared<GPU>(*_jsRuntime);
|
|
67
74
|
auto rnWebGPU =
|
|
68
75
|
std::make_shared<RNWebGPU>(gpu, _platformContext, _jsCallInvoker);
|
|
@@ -106,6 +113,7 @@ RNWebGPUManager::RNWebGPUManager(
|
|
|
106
113
|
GPURenderPassEncoder::installConstructor(*_jsRuntime);
|
|
107
114
|
GPURenderPipeline::installConstructor(*_jsRuntime);
|
|
108
115
|
GPUSampler::installConstructor(*_jsRuntime);
|
|
116
|
+
GPUSharedFence::installConstructor(*_jsRuntime);
|
|
109
117
|
GPUSharedTextureMemory::installConstructor(*_jsRuntime);
|
|
110
118
|
GPUShaderModule::installConstructor(*_jsRuntime);
|
|
111
119
|
GPUSupportedLimits::installConstructor(*_jsRuntime);
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
#include "webgpu/webgpu_cpp.h"
|
|
9
9
|
|
|
10
|
+
#ifdef __APPLE__
|
|
11
|
+
namespace dawn::native::metal {
|
|
12
|
+
void WaitForCommandsToBeScheduled(WGPUDevice device);
|
|
13
|
+
} // namespace dawn::native::metal
|
|
14
|
+
#endif
|
|
15
|
+
|
|
10
16
|
namespace rnwgpu {
|
|
11
17
|
|
|
12
18
|
struct NativeInfo {
|
|
@@ -113,7 +119,27 @@ public:
|
|
|
113
119
|
height = newHeight;
|
|
114
120
|
}
|
|
115
121
|
|
|
116
|
-
|
|
122
|
+
// Present the current surface texture. Called synchronously from the thread
|
|
123
|
+
// that did getCurrentTexture / submit (via GPUCanvasContext::present), so it
|
|
124
|
+
// preserves Dawn surface thread-affinity. No-op when offscreen / unconfigured
|
|
125
|
+
// (no surface).
|
|
126
|
+
void presentFrame() {
|
|
127
|
+
#ifdef __APPLE__
|
|
128
|
+
// Ensure command buffers are scheduled before presenting. Read the device
|
|
129
|
+
// under a shared lock, then wait without holding it (the wait can block).
|
|
130
|
+
// The device may be reconfigured between the two locks; that is safe because
|
|
131
|
+
// present() is called on the rendering thread right after submit(), the wait
|
|
132
|
+
// just flushes that thread's already-submitted work, and the Present() below
|
|
133
|
+
// re-checks `surface` under the unique lock before touching it.
|
|
134
|
+
wgpu::Device device;
|
|
135
|
+
{
|
|
136
|
+
std::shared_lock<std::shared_mutex> lock(_mutex);
|
|
137
|
+
device = config.device;
|
|
138
|
+
}
|
|
139
|
+
if (device) {
|
|
140
|
+
dawn::native::metal::WaitForCommandsToBeScheduled(device.Get());
|
|
141
|
+
}
|
|
142
|
+
#endif
|
|
117
143
|
std::unique_lock<std::shared_mutex> lock(_mutex);
|
|
118
144
|
if (surface) {
|
|
119
145
|
surface.Present();
|
|
@@ -131,6 +157,12 @@ public:
|
|
|
131
157
|
}
|
|
132
158
|
}
|
|
133
159
|
|
|
160
|
+
// True when an on-screen wgpu::Surface is attached (vs offscreen texture).
|
|
161
|
+
bool hasSurface() {
|
|
162
|
+
std::shared_lock<std::shared_mutex> lock(_mutex);
|
|
163
|
+
return surface != nullptr;
|
|
164
|
+
}
|
|
165
|
+
|
|
134
166
|
NativeInfo getNativeInfo() {
|
|
135
167
|
std::shared_lock<std::shared_mutex> lock(_mutex);
|
|
136
168
|
return {.nativeSurface = nativeSurface, .width = width, .height = height};
|
package/cpp/rnwgpu/api/GPU.cpp
CHANGED
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
|
|
10
10
|
#include "Convertors.h"
|
|
11
11
|
#include "JSIConverter.h"
|
|
12
|
-
#include "rnwgpu/async/
|
|
12
|
+
#include "rnwgpu/async/RuntimeContext.h"
|
|
13
13
|
|
|
14
14
|
namespace rnwgpu {
|
|
15
15
|
|
|
16
|
-
GPU::GPU(jsi::Runtime &runtime) : NativeObject(CLASS_NAME) {
|
|
16
|
+
GPU::GPU(jsi::Runtime & /*runtime*/) : NativeObject(CLASS_NAME) {
|
|
17
17
|
static const auto kTimedWaitAny = wgpu::InstanceFeatureName::TimedWaitAny;
|
|
18
18
|
wgpu::InstanceDescriptor instanceDesc{.requiredFeatureCount = 1,
|
|
19
19
|
.requiredFeatures = &kTimedWaitAny};
|
|
@@ -48,12 +48,10 @@ GPU::GPU(jsi::Runtime &runtime) : NativeObject(CLASS_NAME) {
|
|
|
48
48
|
instanceDesc.nextInChain = &toggles;
|
|
49
49
|
|
|
50
50
|
_instance = wgpu::CreateInstance(&instanceDesc);
|
|
51
|
-
|
|
52
|
-
auto dispatcher = std::make_shared<async::JSIMicrotaskDispatcher>(runtime);
|
|
53
|
-
_async = async::AsyncRunner::getOrCreate(runtime, _instance, dispatcher);
|
|
54
51
|
}
|
|
55
52
|
|
|
56
53
|
async::AsyncTaskHandle GPU::requestAdapter(
|
|
54
|
+
jsi::Runtime &runtime,
|
|
57
55
|
std::optional<std::shared_ptr<GPURequestAdapterOptions>> options) {
|
|
58
56
|
wgpu::RequestAdapterOptions aOptions;
|
|
59
57
|
Convertor conv;
|
|
@@ -66,12 +64,17 @@ async::AsyncTaskHandle GPU::requestAdapter(
|
|
|
66
64
|
constexpr auto kDefaultBackendType = wgpu::BackendType::Vulkan;
|
|
67
65
|
#endif
|
|
68
66
|
aOptions.backendType = kDefaultBackendType;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
|
|
68
|
+
// Per-runtime context: async ops requested on this runtime resolve on this
|
|
69
|
+
// runtime's own thread (via its ProcessEvents pump).
|
|
70
|
+
auto context = async::RuntimeContext::getOrCreate(runtime, _instance);
|
|
71
|
+
return context->postTask(
|
|
72
|
+
[this, aOptions,
|
|
73
|
+
context](const async::AsyncTaskHandle::ResolveFunction &resolve,
|
|
74
|
+
const async::AsyncTaskHandle::RejectFunction &reject) {
|
|
72
75
|
_instance.RequestAdapter(
|
|
73
76
|
&aOptions, wgpu::CallbackMode::AllowProcessEvents,
|
|
74
|
-
[
|
|
77
|
+
[context, resolve,
|
|
75
78
|
reject](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter,
|
|
76
79
|
wgpu::StringView message) {
|
|
77
80
|
if (message.length) {
|
|
@@ -79,8 +82,8 @@ async::AsyncTaskHandle GPU::requestAdapter(
|
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
if (status == wgpu::RequestAdapterStatus::Success && adapter) {
|
|
82
|
-
auto adapterHost =
|
|
83
|
-
std::move(adapter),
|
|
85
|
+
auto adapterHost =
|
|
86
|
+
std::make_shared<GPUAdapter>(std::move(adapter), context);
|
|
84
87
|
auto result =
|
|
85
88
|
std::variant<std::nullptr_t, std::shared_ptr<GPUAdapter>>(
|
|
86
89
|
adapterHost);
|
package/cpp/rnwgpu/api/GPU.h
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
#include "NativeObject.h"
|
|
11
11
|
|
|
12
|
-
#include "rnwgpu/async/AsyncRunner.h"
|
|
13
12
|
#include "rnwgpu/async/AsyncTaskHandle.h"
|
|
13
|
+
#include "rnwgpu/async/RuntimeContext.h"
|
|
14
14
|
|
|
15
15
|
#include "webgpu/webgpu_cpp.h"
|
|
16
16
|
|
|
@@ -32,7 +32,10 @@ public:
|
|
|
32
32
|
public:
|
|
33
33
|
std::string getBrand() { return CLASS_NAME; }
|
|
34
34
|
|
|
35
|
+
// requestAdapter needs the calling runtime so each runtime gets its own
|
|
36
|
+
// RuntimeContext (and ProcessEvents pump on its own thread).
|
|
35
37
|
async::AsyncTaskHandle requestAdapter(
|
|
38
|
+
jsi::Runtime &runtime,
|
|
36
39
|
std::optional<std::shared_ptr<GPURequestAdapterOptions>> options);
|
|
37
40
|
wgpu::TextureFormat getPreferredCanvasFormat();
|
|
38
41
|
|
|
@@ -40,7 +43,8 @@ public:
|
|
|
40
43
|
|
|
41
44
|
static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
|
|
42
45
|
installGetter(runtime, prototype, "__brand", &GPU::getBrand);
|
|
43
|
-
|
|
46
|
+
installMethodWithRuntime(runtime, prototype, "requestAdapter",
|
|
47
|
+
&GPU::requestAdapter);
|
|
44
48
|
installMethod(runtime, prototype, "getPreferredCanvasFormat",
|
|
45
49
|
&GPU::getPreferredCanvasFormat);
|
|
46
50
|
installGetter(runtime, prototype, "wgslLanguageFeatures",
|
|
@@ -48,11 +52,9 @@ public:
|
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
inline const wgpu::Instance get() { return _instance; }
|
|
51
|
-
inline std::shared_ptr<async::AsyncRunner> getAsyncRunner() { return _async; }
|
|
52
55
|
|
|
53
56
|
private:
|
|
54
57
|
wgpu::Instance _instance;
|
|
55
|
-
std::shared_ptr<async::AsyncRunner> _async;
|
|
56
58
|
};
|
|
57
59
|
|
|
58
60
|
} // namespace rnwgpu
|
|
@@ -164,10 +164,9 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
164
164
|
}
|
|
165
165
|
_instance.RequestDevice(
|
|
166
166
|
&deviceDesc, wgpu::CallbackMode::AllowProcessEvents,
|
|
167
|
-
[
|
|
167
|
+
[context = _async, resolve, reject, label, creationRuntime,
|
|
168
168
|
deviceLostBinding](wgpu::RequestDeviceStatus status,
|
|
169
|
-
wgpu::Device device,
|
|
170
|
-
wgpu::StringView message) {
|
|
169
|
+
wgpu::Device device, wgpu::StringView message) {
|
|
171
170
|
if (message.length) {
|
|
172
171
|
fprintf(stderr, "%s", message.data);
|
|
173
172
|
}
|
|
@@ -191,14 +190,12 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
191
190
|
case wgpu::LoggingType::Warning:
|
|
192
191
|
logLevel = "Warning";
|
|
193
192
|
Logger::warnToJavascriptConsole(
|
|
194
|
-
*creationRuntime,
|
|
195
|
-
std::string(msg.data, msg.length));
|
|
193
|
+
*creationRuntime, std::string(msg.data, msg.length));
|
|
196
194
|
break;
|
|
197
195
|
case wgpu::LoggingType::Error:
|
|
198
196
|
logLevel = "Error";
|
|
199
197
|
Logger::errorToJavascriptConsole(
|
|
200
|
-
*creationRuntime,
|
|
201
|
-
std::string(msg.data, msg.length));
|
|
198
|
+
*creationRuntime, std::string(msg.data, msg.length));
|
|
202
199
|
break;
|
|
203
200
|
case wgpu::LoggingType::Verbose:
|
|
204
201
|
logLevel = "Verbose";
|
|
@@ -216,7 +213,7 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
216
213
|
creationRuntime);
|
|
217
214
|
|
|
218
215
|
auto deviceHost = std::make_shared<GPUDevice>(std::move(device),
|
|
219
|
-
|
|
216
|
+
context, label);
|
|
220
217
|
*deviceLostBinding = deviceHost;
|
|
221
218
|
|
|
222
219
|
// Register the device in the static registry so the uncaptured
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
#include "NativeObject.h"
|
|
10
10
|
|
|
11
|
-
#include "rnwgpu/async/AsyncRunner.h"
|
|
12
11
|
#include "rnwgpu/async/AsyncTaskHandle.h"
|
|
12
|
+
#include "rnwgpu/async/RuntimeContext.h"
|
|
13
13
|
|
|
14
14
|
#include "webgpu/webgpu_cpp.h"
|
|
15
15
|
|
|
@@ -27,7 +27,7 @@ public:
|
|
|
27
27
|
static constexpr const char *CLASS_NAME = "GPUAdapter";
|
|
28
28
|
|
|
29
29
|
explicit GPUAdapter(wgpu::Adapter instance,
|
|
30
|
-
std::shared_ptr<async::
|
|
30
|
+
std::shared_ptr<async::RuntimeContext> async)
|
|
31
31
|
: NativeObject(CLASS_NAME), _instance(instance), _async(async) {}
|
|
32
32
|
|
|
33
33
|
public:
|
|
@@ -53,7 +53,7 @@ public:
|
|
|
53
53
|
|
|
54
54
|
private:
|
|
55
55
|
wgpu::Adapter _instance;
|
|
56
|
-
std::shared_ptr<async::
|
|
56
|
+
std::shared_ptr<async::RuntimeContext> _async;
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
} // namespace rnwgpu
|
|
@@ -55,30 +55,29 @@ async::AsyncTaskHandle GPUBuffer::mapAsync(uint64_t modeIn,
|
|
|
55
55
|
[bufferHandle, mode, resolvedOffset,
|
|
56
56
|
rangeSize](const async::AsyncTaskHandle::ResolveFunction &resolve,
|
|
57
57
|
const async::AsyncTaskHandle::RejectFunction &reject) {
|
|
58
|
-
bufferHandle.MapAsync(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
});
|
|
58
|
+
bufferHandle.MapAsync(
|
|
59
|
+
mode, resolvedOffset, rangeSize, wgpu::CallbackMode::AllowProcessEvents,
|
|
60
|
+
[resolve, reject](wgpu::MapAsyncStatus status,
|
|
61
|
+
wgpu::StringView message) {
|
|
62
|
+
switch (status) {
|
|
63
|
+
case wgpu::MapAsyncStatus::Success:
|
|
64
|
+
resolve(nullptr);
|
|
65
|
+
break;
|
|
66
|
+
case wgpu::MapAsyncStatus::CallbackCancelled:
|
|
67
|
+
reject("MapAsyncStatus::CallbackCancelled");
|
|
68
|
+
break;
|
|
69
|
+
case wgpu::MapAsyncStatus::Error:
|
|
70
|
+
reject("MapAsyncStatus::Error");
|
|
71
|
+
break;
|
|
72
|
+
case wgpu::MapAsyncStatus::Aborted:
|
|
73
|
+
reject("MapAsyncStatus::Aborted");
|
|
74
|
+
break;
|
|
75
|
+
default:
|
|
76
|
+
reject("MapAsyncStatus: " +
|
|
77
|
+
std::to_string(static_cast<int>(status)));
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
82
81
|
});
|
|
83
82
|
}
|
|
84
83
|
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
#include "NativeObject.h"
|
|
11
11
|
|
|
12
|
-
#include "rnwgpu/async/AsyncRunner.h"
|
|
13
12
|
#include "rnwgpu/async/AsyncTaskHandle.h"
|
|
13
|
+
#include "rnwgpu/async/RuntimeContext.h"
|
|
14
14
|
|
|
15
15
|
#include "webgpu/webgpu_cpp.h"
|
|
16
16
|
|
|
@@ -25,7 +25,7 @@ public:
|
|
|
25
25
|
static constexpr const char *CLASS_NAME = "GPUBuffer";
|
|
26
26
|
|
|
27
27
|
explicit GPUBuffer(wgpu::Buffer instance,
|
|
28
|
-
std::shared_ptr<async::
|
|
28
|
+
std::shared_ptr<async::RuntimeContext> async,
|
|
29
29
|
std::string label)
|
|
30
30
|
: NativeObject(CLASS_NAME), _instance(instance), _async(async),
|
|
31
31
|
_label(label) {}
|
|
@@ -71,7 +71,7 @@ public:
|
|
|
71
71
|
|
|
72
72
|
private:
|
|
73
73
|
wgpu::Buffer _instance;
|
|
74
|
-
std::shared_ptr<async::
|
|
74
|
+
std::shared_ptr<async::RuntimeContext> _async;
|
|
75
75
|
std::string _label;
|
|
76
76
|
struct Mapping {
|
|
77
77
|
uint64_t start;
|
|
@@ -3,14 +3,6 @@
|
|
|
3
3
|
#include "RNWebGPUManager.h"
|
|
4
4
|
#include <memory>
|
|
5
5
|
|
|
6
|
-
#ifdef __APPLE__
|
|
7
|
-
namespace dawn::native::metal {
|
|
8
|
-
|
|
9
|
-
void WaitForCommandsToBeScheduled(WGPUDevice device);
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
#endif
|
|
13
|
-
|
|
14
6
|
namespace rnwgpu {
|
|
15
7
|
|
|
16
8
|
void GPUCanvasContext::configure(
|
|
@@ -47,21 +39,26 @@ std::shared_ptr<GPUTexture> GPUCanvasContext::getCurrentTexture() {
|
|
|
47
39
|
if (sizeHasChanged) {
|
|
48
40
|
_surfaceInfo->reconfigure(width, height);
|
|
49
41
|
}
|
|
42
|
+
|
|
50
43
|
auto texture = _surfaceInfo->getCurrentTexture();
|
|
44
|
+
|
|
45
|
+
auto size = _surfaceInfo->getSize();
|
|
46
|
+
_canvas->setClientWidth(size.width);
|
|
47
|
+
_canvas->setClientHeight(size.height);
|
|
48
|
+
|
|
51
49
|
// Pass reportsMemoryPressure=false to avoid triggering spurious Hermes GC
|
|
52
50
|
// cycles every frame since the canvas texture doesn't own the buffer.
|
|
53
51
|
return std::make_shared<GPUTexture>(texture, "", false);
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
void GPUCanvasContext::present() {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
_surfaceInfo->present();
|
|
55
|
+
// Present runs synchronously on the calling thread (the one that did
|
|
56
|
+
// getCurrentTexture / submit), preserving Dawn surface thread-affinity.
|
|
57
|
+
// Required on every runtime (main JS, Reanimated UI, dedicated worklet);
|
|
58
|
+
// offscreen surfaces have no wgpu::Surface so they no-op.
|
|
59
|
+
if (_surfaceInfo->hasSurface()) {
|
|
60
|
+
_surfaceInfo->presentFrame();
|
|
61
|
+
}
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
} // namespace rnwgpu
|
|
@@ -55,6 +55,9 @@ public:
|
|
|
55
55
|
void configure(std::shared_ptr<GPUCanvasConfiguration> configuration);
|
|
56
56
|
void unconfigure();
|
|
57
57
|
std::shared_ptr<GPUTexture> getCurrentTexture();
|
|
58
|
+
// Present is explicit on every runtime (main JS, Reanimated UI, and dedicated
|
|
59
|
+
// worklet runtimes). It runs synchronously on the calling thread, preserving
|
|
60
|
+
// Dawn surface thread-affinity; offscreen surfaces no-op.
|
|
58
61
|
void present();
|
|
59
62
|
|
|
60
63
|
private:
|