@shopify/react-native-skia 2.6.6 → 2.6.8
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/android/CMakeLists.txt +1 -2
- package/apple/RNSkiaModule.mm +8 -2
- package/apple/SkiaManager.mm +10 -5
- package/cpp/api/JsiSkApi.h +6 -6
- package/cpp/api/JsiSkMaskFilter.h +1 -0
- package/cpp/jsi2/NativeObject.h +39 -0
- package/cpp/rnskia/RNSkManager.cpp +27 -11
- package/cpp/rnwgpu/SurfaceRegistry.h +33 -1
- package/cpp/rnwgpu/api/GPU.cpp +15 -12
- package/cpp/rnwgpu/api/GPU.h +6 -3
- package/cpp/rnwgpu/api/GPUAdapter.cpp +2 -2
- package/cpp/rnwgpu/api/GPUAdapter.h +3 -3
- 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 +48 -13
- package/cpp/rnwgpu/api/GPUDevice.h +12 -3
- package/cpp/rnwgpu/api/GPUQueue.h +3 -3
- package/cpp/rnwgpu/api/GPUShaderModule.h +3 -3
- package/cpp/rnwgpu/api/WebGPUConstants.h +36 -0
- package/cpp/rnwgpu/async/AsyncTaskHandle.cpp +55 -22
- package/cpp/rnwgpu/async/AsyncTaskHandle.h +8 -5
- package/cpp/rnwgpu/async/RuntimeContext.cpp +194 -0
- package/cpp/rnwgpu/async/RuntimeContext.h +121 -0
- package/lib/commonjs/skia/types/WebGPU.d.ts +31 -0
- package/lib/commonjs/skia/types/WebGPU.js +99 -0
- package/lib/commonjs/skia/types/WebGPU.js.map +1 -1
- package/lib/module/skia/types/WebGPU.d.ts +31 -0
- package/lib/module/skia/types/WebGPU.js +98 -1
- package/lib/module/skia/types/WebGPU.js.map +1 -1
- package/lib/typescript/lib/commonjs/skia/types/WebGPU.d.ts +1 -0
- package/lib/typescript/lib/module/mock/index.d.ts +1 -0
- package/lib/typescript/lib/module/skia/types/WebGPU.d.ts +31 -1
- package/lib/typescript/src/skia/types/WebGPU.d.ts +31 -0
- package/package.json +1 -1
- package/src/skia/types/WebGPU.ts +40 -0
- package/cpp/rnwgpu/async/AsyncDispatcher.h +0 -28
- package/cpp/rnwgpu/async/AsyncRunner.cpp +0 -182
- package/cpp/rnwgpu/async/AsyncRunner.h +0 -57
- package/cpp/rnwgpu/async/JSIMicrotaskDispatcher.cpp +0 -23
- package/cpp/rnwgpu/async/JSIMicrotaskDispatcher.h +0 -22
package/android/CMakeLists.txt
CHANGED
|
@@ -120,9 +120,8 @@ if(SK_GRAPHITE)
|
|
|
120
120
|
"${PROJECT_SOURCE_DIR}/../cpp/jsi2/Promise.cpp"
|
|
121
121
|
|
|
122
122
|
# WebGPU async system
|
|
123
|
-
"${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/async/AsyncRunner.cpp"
|
|
124
123
|
"${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/async/AsyncTaskHandle.cpp"
|
|
125
|
-
"${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/async/
|
|
124
|
+
"${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/async/RuntimeContext.cpp"
|
|
126
125
|
|
|
127
126
|
# WebGPU API
|
|
128
127
|
"${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPU.cpp"
|
package/apple/RNSkiaModule.mm
CHANGED
|
@@ -35,11 +35,17 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) {
|
|
|
35
35
|
// Already initialized, ignore call.
|
|
36
36
|
return @true;
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
#ifndef RCT_REMOVE_LEGACY_ARCH
|
|
39
39
|
if (!jsInvoker) {
|
|
40
|
+
RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
|
|
40
41
|
jsInvoker = cxxBridge.jsCallInvoker;
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
+
#endif
|
|
44
|
+
if (!jsInvoker) {
|
|
45
|
+
NSLog(@"[RNSkiaModule] Failed to install SkiaManager: jsInvoker is not initialized.");
|
|
46
|
+
return @false;
|
|
47
|
+
}
|
|
48
|
+
skiaManager = [[SkiaManager alloc] initWithBridge:self.bridge
|
|
43
49
|
jsInvoker:jsInvoker];
|
|
44
50
|
return @true;
|
|
45
51
|
}
|
package/apple/SkiaManager.mm
CHANGED
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
#import <Foundation/Foundation.h>
|
|
4
4
|
|
|
5
|
-
#import <React/RCTBridge+Private.h>
|
|
6
5
|
#import <React/RCTBridge.h>
|
|
7
6
|
#import <React/RCTUIManager.h>
|
|
8
7
|
|
|
9
8
|
#import "RNSkApplePlatformContext.h"
|
|
10
9
|
|
|
10
|
+
// Forward-declared runtime accessor that is satisfied by RCTCxxBridge
|
|
11
|
+
// (legacy/transitional) and RCTBridgeProxy (bridgeless). Avoids referencing
|
|
12
|
+
// RCTCxxBridge directly, which is compiled out when RCT_REMOVE_LEGACY_ARCH
|
|
13
|
+
// is set (React Native 0.82+).
|
|
14
|
+
@interface RCTBridge (RNSkiaRuntime)
|
|
15
|
+
- (void *)runtime;
|
|
16
|
+
@end
|
|
17
|
+
|
|
11
18
|
static __weak SkiaManager *sharedInstance = nil;
|
|
12
19
|
|
|
13
20
|
@implementation SkiaManager {
|
|
@@ -29,11 +36,9 @@ static __weak SkiaManager *sharedInstance = nil;
|
|
|
29
36
|
self = [super init];
|
|
30
37
|
if (self) {
|
|
31
38
|
sharedInstance = self;
|
|
32
|
-
|
|
33
|
-
if (cxxBridge.runtime) {
|
|
34
|
-
|
|
39
|
+
if (bridge.runtime) {
|
|
35
40
|
facebook::jsi::Runtime *jsRuntime =
|
|
36
|
-
(facebook::jsi::Runtime *)
|
|
41
|
+
(facebook::jsi::Runtime *)bridge.runtime;
|
|
37
42
|
|
|
38
43
|
// Create the RNSkiaManager (cross platform)
|
|
39
44
|
_skManager = std::make_shared<RNSkia::RNSkManager>(
|
package/cpp/api/JsiSkApi.h
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
#ifdef SK_GRAPHITE
|
|
10
10
|
#include "rnskia/RNDawnContext.h"
|
|
11
11
|
#include "rnwgpu/api/GPUDevice.h"
|
|
12
|
-
#include "rnwgpu/async/
|
|
12
|
+
#include "rnwgpu/async/RuntimeContext.h"
|
|
13
13
|
#endif
|
|
14
14
|
|
|
15
15
|
#include "JsiNativeBuffer.h"
|
|
@@ -164,12 +164,12 @@ public:
|
|
|
164
164
|
"getDevice", JSI_HOST_FUNCTION_LAMBDA {
|
|
165
165
|
#ifdef SK_GRAPHITE
|
|
166
166
|
auto &dawnContext = DawnContext::getInstance();
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
// Per-runtime context: async ops on this device resolve on the calling
|
|
168
|
+
// runtime's own thread (via its ProcessEvents pump).
|
|
169
|
+
auto context = rnwgpu::async::RuntimeContext::getOrCreate(
|
|
170
|
+
runtime, dawnContext.getWGPUInstance());
|
|
171
171
|
auto device = std::make_shared<rnwgpu::GPUDevice>(
|
|
172
|
-
dawnContext.getWGPUDevice(),
|
|
172
|
+
dawnContext.getWGPUDevice(), context, "Skia Device");
|
|
173
173
|
return rnwgpu::GPUDevice::create(runtime, device);
|
|
174
174
|
#else
|
|
175
175
|
throw jsi::JSError(runtime,
|
package/cpp/jsi2/NativeObject.h
CHANGED
|
@@ -432,6 +432,29 @@ protected:
|
|
|
432
432
|
prototype.setProperty(runtime, name, func);
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
+
/**
|
|
436
|
+
* Install a method whose native implementation needs the calling jsi::Runtime
|
|
437
|
+
* as its first parameter. Used by entry points that must act per-runtime
|
|
438
|
+
* (e.g. GPU::requestAdapter, which creates a per-runtime RuntimeContext).
|
|
439
|
+
*/
|
|
440
|
+
template <typename ReturnType, typename... Args>
|
|
441
|
+
static void
|
|
442
|
+
installMethodWithRuntime(jsi::Runtime &runtime, jsi::Object &prototype,
|
|
443
|
+
const char *name,
|
|
444
|
+
ReturnType (Derived::*method)(jsi::Runtime &,
|
|
445
|
+
Args...)) {
|
|
446
|
+
auto func = jsi::Function::createFromHostFunction(
|
|
447
|
+
runtime, jsi::PropNameID::forUtf8(runtime, name), sizeof...(Args),
|
|
448
|
+
[method](jsi::Runtime &rt, const jsi::Value &thisVal,
|
|
449
|
+
const jsi::Value *args, size_t count) -> jsi::Value {
|
|
450
|
+
auto native = Derived::fromValue(rt, thisVal);
|
|
451
|
+
return callMethodWithRuntime(native.get(), method, rt, args,
|
|
452
|
+
std::index_sequence_for<Args...>{},
|
|
453
|
+
count);
|
|
454
|
+
});
|
|
455
|
+
prototype.setProperty(runtime, name, func);
|
|
456
|
+
}
|
|
457
|
+
|
|
435
458
|
/**
|
|
436
459
|
* Install a getter on the prototype.
|
|
437
460
|
*/
|
|
@@ -567,6 +590,22 @@ protected:
|
|
|
567
590
|
}
|
|
568
591
|
|
|
569
592
|
private:
|
|
593
|
+
// Helper to call a method that takes the calling jsi::Runtime as its first
|
|
594
|
+
// parameter, with JSI argument conversion for the rest and JSI conversion of
|
|
595
|
+
// the result.
|
|
596
|
+
template <typename ReturnType, typename... Args, size_t... Is>
|
|
597
|
+
static jsi::Value
|
|
598
|
+
callMethodWithRuntime(Derived *obj,
|
|
599
|
+
ReturnType (Derived::*method)(jsi::Runtime &, Args...),
|
|
600
|
+
jsi::Runtime &runtime, const jsi::Value *args,
|
|
601
|
+
std::index_sequence<Is...>, size_t count) {
|
|
602
|
+
ReturnType result = (obj->*method)(
|
|
603
|
+
runtime, rnwgpu::JSIConverter<std::decay_t<Args>>::fromJSI(
|
|
604
|
+
runtime, args[Is], Is >= count)...);
|
|
605
|
+
return rnwgpu::JSIConverter<std::decay_t<ReturnType>>::toJSI(
|
|
606
|
+
runtime, std::move(result));
|
|
607
|
+
}
|
|
608
|
+
|
|
570
609
|
// Helper to call a method with JSI argument conversion
|
|
571
610
|
template <typename ReturnType, typename... Args, size_t... Is>
|
|
572
611
|
static jsi::Value callMethod(Derived *obj,
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
#include "rnwgpu/api/descriptors/GPUMapMode.h"
|
|
24
24
|
#include "rnwgpu/api/descriptors/GPUShaderStage.h"
|
|
25
25
|
#include "rnwgpu/api/descriptors/GPUTextureUsage.h"
|
|
26
|
+
#include "rnwgpu/api/WebGPUConstants.h"
|
|
27
|
+
#include "rnwgpu/async/RuntimeContext.h"
|
|
26
28
|
#include "jsi2/Promise.h"
|
|
27
29
|
|
|
28
30
|
#include "include/core/SkData.h"
|
|
@@ -82,6 +84,12 @@ void RNSkManager::installBindings() {
|
|
|
82
84
|
jsi::Object::createFromHostObject(*_jsRuntime, _viewApi));
|
|
83
85
|
|
|
84
86
|
#ifdef SK_GRAPHITE
|
|
87
|
+
// Register the main runtime + its CallInvoker so spontaneous events
|
|
88
|
+
// (device.lost / uncapturederror) on main-runtime devices can be delivered to
|
|
89
|
+
// the JS thread without the ProcessEvents pump. Worklet-runtime devices have
|
|
90
|
+
// no invoker (best-effort; see the RuntimeContext "Threading model" doc).
|
|
91
|
+
rnwgpu::async::RuntimeContext::registerMainRuntime(_jsRuntime, _jsCallInvoker);
|
|
92
|
+
|
|
85
93
|
// Install WebGPU constructors
|
|
86
94
|
rnwgpu::GPU::installConstructor(*_jsRuntime);
|
|
87
95
|
rnwgpu::GPUUncapturedErrorEvent::installConstructor(*_jsRuntime);
|
|
@@ -104,18 +112,26 @@ void RNSkManager::installBindings() {
|
|
|
104
112
|
std::move(navigator));
|
|
105
113
|
}
|
|
106
114
|
|
|
107
|
-
// Install WebGPU constant objects as plain JS objects
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
// Install WebGPU constant objects as plain JS objects on the main runtime.
|
|
116
|
+
rnwgpu::installWebGPUConstants(*_jsRuntime);
|
|
117
|
+
|
|
118
|
+
// Install a global `installWebGPU()` host function so worklet runtimes can get
|
|
119
|
+
// the same constants. A host function captured into a worklet is serialized as
|
|
120
|
+
// a SerializableHostFunction and re-created on the worklet runtime, so the body
|
|
121
|
+
// runs there (its `rt` is the worklet runtime) and installs the constants on
|
|
122
|
+
// that runtime. The constants come from the native wgpu::*Usage enums, so the
|
|
123
|
+
// values stay a single source of truth across every runtime. Calling it on a
|
|
124
|
+
// runtime that already has the globals is a safe, idempotent no-op.
|
|
116
125
|
_jsRuntime->global().setProperty(
|
|
117
|
-
*_jsRuntime, "
|
|
118
|
-
|
|
126
|
+
*_jsRuntime, "installWebGPU",
|
|
127
|
+
jsi::Function::createFromHostFunction(
|
|
128
|
+
*_jsRuntime, jsi::PropNameID::forAscii(*_jsRuntime, "installWebGPU"),
|
|
129
|
+
0,
|
|
130
|
+
[](jsi::Runtime &rt, const jsi::Value & /*thisVal*/,
|
|
131
|
+
const jsi::Value * /*args*/, size_t /*count*/) -> jsi::Value {
|
|
132
|
+
rnwgpu::installWebGPUConstants(rt);
|
|
133
|
+
return jsi::Value::undefined();
|
|
134
|
+
}));
|
|
119
135
|
|
|
120
136
|
// Install RNWebGPU global object for WebGPU Canvas support
|
|
121
137
|
auto rnWebGPU = std::make_shared<rnwgpu::RNWebGPU>(gpu, nullptr);
|
|
@@ -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 {
|
|
@@ -112,13 +118,39 @@ public:
|
|
|
112
118
|
height = newHeight;
|
|
113
119
|
}
|
|
114
120
|
|
|
115
|
-
|
|
121
|
+
// Present the current surface texture. Called synchronously from the thread
|
|
122
|
+
// that did getCurrentTexture / submit (via GPUCanvasContext::present), so it
|
|
123
|
+
// preserves Dawn surface thread-affinity. No-op when offscreen / unconfigured
|
|
124
|
+
// (no surface).
|
|
125
|
+
void presentFrame() {
|
|
126
|
+
#ifdef __APPLE__
|
|
127
|
+
// Ensure command buffers are scheduled before presenting. Read the device
|
|
128
|
+
// under a shared lock, then wait without holding it (the wait can block).
|
|
129
|
+
// The device may be reconfigured between the two locks; that is safe because
|
|
130
|
+
// present() is called on the rendering thread right after submit(), the wait
|
|
131
|
+
// just flushes that thread's already-submitted work, and the Present() below
|
|
132
|
+
// re-checks `surface` under the unique lock before touching it.
|
|
133
|
+
wgpu::Device device;
|
|
134
|
+
{
|
|
135
|
+
std::shared_lock<std::shared_mutex> lock(_mutex);
|
|
136
|
+
device = config.device;
|
|
137
|
+
}
|
|
138
|
+
if (device) {
|
|
139
|
+
dawn::native::metal::WaitForCommandsToBeScheduled(device.Get());
|
|
140
|
+
}
|
|
141
|
+
#endif
|
|
116
142
|
std::unique_lock<std::shared_mutex> lock(_mutex);
|
|
117
143
|
if (surface) {
|
|
118
144
|
surface.Present();
|
|
119
145
|
}
|
|
120
146
|
}
|
|
121
147
|
|
|
148
|
+
// True when an on-screen wgpu::Surface is attached (vs offscreen texture).
|
|
149
|
+
bool hasSurface() {
|
|
150
|
+
std::shared_lock<std::shared_mutex> lock(_mutex);
|
|
151
|
+
return surface != nullptr;
|
|
152
|
+
}
|
|
153
|
+
|
|
122
154
|
wgpu::Texture getCurrentTexture() {
|
|
123
155
|
std::shared_lock<std::shared_mutex> lock(_mutex);
|
|
124
156
|
if (surface) {
|
package/cpp/rnwgpu/api/GPU.cpp
CHANGED
|
@@ -9,17 +9,15 @@
|
|
|
9
9
|
|
|
10
10
|
#include "Convertors.h"
|
|
11
11
|
#include "jsi2/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
|
|
17
|
-
: NativeObject(CLASS_NAME), _instance(instance) {
|
|
18
|
-
auto dispatcher = std::make_shared<async::JSIMicrotaskDispatcher>(runtime);
|
|
19
|
-
_async = async::AsyncRunner::getOrCreate(runtime, _instance, dispatcher);
|
|
20
|
-
}
|
|
16
|
+
GPU::GPU(jsi::Runtime & /*runtime*/, wgpu::Instance instance)
|
|
17
|
+
: NativeObject(CLASS_NAME), _instance(instance) {}
|
|
21
18
|
|
|
22
19
|
async::AsyncTaskHandle GPU::requestAdapter(
|
|
20
|
+
jsi::Runtime &runtime,
|
|
23
21
|
std::optional<std::shared_ptr<GPURequestAdapterOptions>> options) {
|
|
24
22
|
wgpu::RequestAdapterOptions aOptions;
|
|
25
23
|
Convertor conv;
|
|
@@ -32,12 +30,17 @@ async::AsyncTaskHandle GPU::requestAdapter(
|
|
|
32
30
|
constexpr auto kDefaultBackendType = wgpu::BackendType::Vulkan;
|
|
33
31
|
#endif
|
|
34
32
|
aOptions.backendType = kDefaultBackendType;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
|
|
34
|
+
// Per-runtime context: async ops requested on this runtime resolve on this
|
|
35
|
+
// runtime's own thread (via its ProcessEvents pump).
|
|
36
|
+
auto context = async::RuntimeContext::getOrCreate(runtime, _instance);
|
|
37
|
+
return context->postTask(
|
|
38
|
+
[this, aOptions,
|
|
39
|
+
context](const async::AsyncTaskHandle::ResolveFunction &resolve,
|
|
40
|
+
const async::AsyncTaskHandle::RejectFunction &reject) {
|
|
38
41
|
_instance.RequestAdapter(
|
|
39
42
|
&aOptions, wgpu::CallbackMode::AllowProcessEvents,
|
|
40
|
-
[
|
|
43
|
+
[context, resolve,
|
|
41
44
|
reject](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter,
|
|
42
45
|
wgpu::StringView message) {
|
|
43
46
|
if (message.length) {
|
|
@@ -45,8 +48,8 @@ async::AsyncTaskHandle GPU::requestAdapter(
|
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
if (status == wgpu::RequestAdapterStatus::Success && adapter) {
|
|
48
|
-
auto adapterHost =
|
|
49
|
-
std::move(adapter),
|
|
51
|
+
auto adapterHost =
|
|
52
|
+
std::make_shared<GPUAdapter>(std::move(adapter), context);
|
|
50
53
|
auto result =
|
|
51
54
|
std::variant<std::nullptr_t, std::shared_ptr<GPUAdapter>>(
|
|
52
55
|
adapterHost);
|
package/cpp/rnwgpu/api/GPU.h
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
#include "jsi2/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",
|
|
@@ -51,7 +55,6 @@ public:
|
|
|
51
55
|
|
|
52
56
|
private:
|
|
53
57
|
wgpu::Instance _instance;
|
|
54
|
-
std::shared_ptr<async::AsyncRunner> _async;
|
|
55
58
|
};
|
|
56
59
|
|
|
57
60
|
} // namespace rnwgpu
|
|
@@ -138,7 +138,7 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
138
138
|
}
|
|
139
139
|
_instance.RequestDevice(
|
|
140
140
|
&deviceDesc, wgpu::CallbackMode::AllowProcessEvents,
|
|
141
|
-
[
|
|
141
|
+
[context = _async, resolve, reject, label, creationRuntime,
|
|
142
142
|
deviceLostBinding](wgpu::RequestDeviceStatus status,
|
|
143
143
|
wgpu::Device device,
|
|
144
144
|
wgpu::StringView message) {
|
|
@@ -190,7 +190,7 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
190
190
|
creationRuntime);
|
|
191
191
|
|
|
192
192
|
auto deviceHost = std::make_shared<GPUDevice>(std::move(device),
|
|
193
|
-
|
|
193
|
+
context, label);
|
|
194
194
|
*deviceLostBinding = deviceHost;
|
|
195
195
|
resolve([deviceHost = std::move(deviceHost)](
|
|
196
196
|
jsi::Runtime &runtime) mutable {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
#include "jsi2/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
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
#include "jsi2/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;
|
|
@@ -2,14 +2,6 @@
|
|
|
2
2
|
#include "Convertors.h"
|
|
3
3
|
#include <memory>
|
|
4
4
|
|
|
5
|
-
#ifdef __APPLE__
|
|
6
|
-
namespace dawn::native::metal {
|
|
7
|
-
|
|
8
|
-
void WaitForCommandsToBeScheduled(WGPUDevice device);
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
#endif
|
|
12
|
-
|
|
13
5
|
namespace rnwgpu {
|
|
14
6
|
|
|
15
7
|
void GPUCanvasContext::configure(
|
|
@@ -46,19 +38,24 @@ std::shared_ptr<GPUTexture> GPUCanvasContext::getCurrentTexture() {
|
|
|
46
38
|
if (sizeHasChanged) {
|
|
47
39
|
_surfaceInfo->reconfigure(width, height);
|
|
48
40
|
}
|
|
41
|
+
|
|
49
42
|
auto texture = _surfaceInfo->getCurrentTexture();
|
|
50
|
-
return std::make_shared<GPUTexture>(texture, "", false);
|
|
51
|
-
}
|
|
52
43
|
|
|
53
|
-
void GPUCanvasContext::present() {
|
|
54
|
-
#ifdef __APPLE__
|
|
55
|
-
dawn::native::metal::WaitForCommandsToBeScheduled(
|
|
56
|
-
_surfaceInfo->getDevice().Get());
|
|
57
|
-
#endif
|
|
58
44
|
auto size = _surfaceInfo->getSize();
|
|
59
45
|
_canvas->setClientWidth(size.width);
|
|
60
46
|
_canvas->setClientHeight(size.height);
|
|
61
|
-
|
|
47
|
+
|
|
48
|
+
return std::make_shared<GPUTexture>(texture, "", false);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
void GPUCanvasContext::present() {
|
|
52
|
+
// Present runs synchronously on the calling thread (the one that did
|
|
53
|
+
// getCurrentTexture / submit), preserving Dawn surface thread-affinity.
|
|
54
|
+
// Required on every runtime (main JS, Reanimated UI, dedicated worklet);
|
|
55
|
+
// offscreen surfaces have no wgpu::Surface so they no-op.
|
|
56
|
+
if (_surfaceInfo->hasSurface()) {
|
|
57
|
+
_surfaceInfo->presentFrame();
|
|
58
|
+
}
|
|
62
59
|
}
|
|
63
60
|
|
|
64
61
|
} // namespace rnwgpu
|
|
@@ -54,6 +54,9 @@ public:
|
|
|
54
54
|
void configure(std::shared_ptr<GPUCanvasConfiguration> configuration);
|
|
55
55
|
void unconfigure();
|
|
56
56
|
std::shared_ptr<GPUTexture> getCurrentTexture();
|
|
57
|
+
// Present is explicit on every runtime (main JS, Reanimated UI, and dedicated
|
|
58
|
+
// worklet runtimes). It runs synchronously on the calling thread, preserving
|
|
59
|
+
// Dawn surface thread-affinity; offscreen surfaces no-op.
|
|
57
60
|
void present();
|
|
58
61
|
|
|
59
62
|
private:
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
#include <utility>
|
|
7
7
|
#include <vector>
|
|
8
8
|
|
|
9
|
+
#include <ReactCommon/CallInvoker.h>
|
|
10
|
+
|
|
9
11
|
#include "Convertors.h"
|
|
10
12
|
#include "NativeBufferUtils.h"
|
|
11
13
|
#include "jsi2/JSIConverter.h"
|
|
@@ -19,23 +21,33 @@ namespace rnwgpu {
|
|
|
19
21
|
|
|
20
22
|
void GPUDevice::notifyDeviceLost(wgpu::DeviceLostReason reason,
|
|
21
23
|
std::string message) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
std::optional<async::AsyncTaskHandle::ResolveFunction> resolveToCall;
|
|
25
|
+
std::shared_ptr<GPUDeviceLostInfo> info;
|
|
26
|
+
{
|
|
27
|
+
std::lock_guard<std::mutex> lock(_lostMutex);
|
|
28
|
+
if (_lostSettled) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
_lostSettled = true;
|
|
33
|
+
_lostInfo = std::make_shared<GPUDeviceLostInfo>(reason, std::move(message));
|
|
34
|
+
info = _lostInfo;
|
|
25
35
|
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
if (_lostResolve.has_value()) {
|
|
37
|
+
resolveToCall = std::move(*_lostResolve);
|
|
38
|
+
_lostResolve.reset();
|
|
39
|
+
}
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
_lostHandle.reset();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Settle outside the lock: resolve() only enqueues onto the JS thread.
|
|
45
|
+
if (resolveToCall.has_value()) {
|
|
46
|
+
(*resolveToCall)([info](jsi::Runtime &runtime) mutable {
|
|
33
47
|
return JSIConverter<std::shared_ptr<GPUDeviceLostInfo>>::toJSI(runtime,
|
|
34
48
|
info);
|
|
35
49
|
});
|
|
36
50
|
}
|
|
37
|
-
|
|
38
|
-
_lostHandle.reset();
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
void GPUDevice::forceLossForTesting() {
|
|
@@ -474,6 +486,11 @@ std::unordered_set<std::string> GPUDevice::getFeatures() {
|
|
|
474
486
|
}
|
|
475
487
|
|
|
476
488
|
async::AsyncTaskHandle GPUDevice::getLost() {
|
|
489
|
+
// Held across the whole body: the postTask callback below runs synchronously
|
|
490
|
+
// on this (JS) thread and touches the same _lost* fields, so it must not
|
|
491
|
+
// re-lock. notifyDeviceLost() takes the same lock from its (possibly worker)
|
|
492
|
+
// thread.
|
|
493
|
+
std::lock_guard<std::mutex> lock(_lostMutex);
|
|
477
494
|
if (_lostHandle.has_value()) {
|
|
478
495
|
return *_lostHandle;
|
|
479
496
|
}
|
|
@@ -488,7 +505,7 @@ async::AsyncTaskHandle GPUDevice::getLost() {
|
|
|
488
505
|
runtime, info);
|
|
489
506
|
});
|
|
490
507
|
},
|
|
491
|
-
false);
|
|
508
|
+
/*keepPumping=*/false);
|
|
492
509
|
}
|
|
493
510
|
|
|
494
511
|
auto handle = _async->postTask(
|
|
@@ -502,9 +519,10 @@ async::AsyncTaskHandle GPUDevice::getLost() {
|
|
|
502
519
|
return;
|
|
503
520
|
}
|
|
504
521
|
|
|
522
|
+
// Resolved later from notifyDeviceLost().
|
|
505
523
|
_lostResolve = resolve;
|
|
506
524
|
},
|
|
507
|
-
false);
|
|
525
|
+
/*keepPumping=*/false);
|
|
508
526
|
|
|
509
527
|
_lostHandle = handle;
|
|
510
528
|
return handle;
|
|
@@ -529,6 +547,23 @@ void GPUDevice::removeEventListener(std::string type, jsi::Function callback) {
|
|
|
529
547
|
}
|
|
530
548
|
|
|
531
549
|
void GPUDevice::notifyUncapturedError(GPUErrorVariant error) {
|
|
550
|
+
// Dawn can surface an uncaptured error from any ProcessEvents pump (a worklet
|
|
551
|
+
// runtime sharing this instance may pump it on the wrong thread). Marshal to
|
|
552
|
+
// the owning runtime's JS thread via its CallInvoker before touching JSI. The
|
|
553
|
+
// invoker is wired only for the main JS runtime, so a device created on a
|
|
554
|
+
// worklet runtime does not deliver uncaptured errors to JS (best-effort; see
|
|
555
|
+
// the Threading model).
|
|
556
|
+
auto invoker = _async ? _async->callInvoker() : nullptr;
|
|
557
|
+
if (!invoker) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
auto self = shared_from_this();
|
|
561
|
+
invoker->invokeAsync([self, error = std::move(error)]() mutable {
|
|
562
|
+
self->deliverUncapturedError(std::move(error));
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
void GPUDevice::deliverUncapturedError(GPUErrorVariant error) {
|
|
532
567
|
auto runtime = getCreationRuntime();
|
|
533
568
|
if (runtime == nullptr) {
|
|
534
569
|
return;
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
#include "jsi2/NativeObject.h"
|
|
17
17
|
|
|
18
|
-
#include "rnwgpu/async/AsyncRunner.h"
|
|
19
18
|
#include "rnwgpu/async/AsyncTaskHandle.h"
|
|
19
|
+
#include "rnwgpu/async/RuntimeContext.h"
|
|
20
20
|
|
|
21
21
|
#include "webgpu/webgpu_cpp.h"
|
|
22
22
|
|
|
@@ -99,7 +99,7 @@ public:
|
|
|
99
99
|
static constexpr const char *CLASS_NAME = "GPUDevice";
|
|
100
100
|
|
|
101
101
|
explicit GPUDevice(wgpu::Device instance,
|
|
102
|
-
std::shared_ptr<async::
|
|
102
|
+
std::shared_ptr<async::RuntimeContext> async,
|
|
103
103
|
std::string label)
|
|
104
104
|
: NativeObject(CLASS_NAME), _instance(instance), _async(async),
|
|
105
105
|
_label(label) {
|
|
@@ -230,9 +230,18 @@ public:
|
|
|
230
230
|
private:
|
|
231
231
|
friend class GPUAdapter;
|
|
232
232
|
|
|
233
|
+
// Runs the uncapturederror listeners on the creation runtime's JS thread.
|
|
234
|
+
// Invoked from notifyUncapturedError via the main CallInvoker.
|
|
235
|
+
void deliverUncapturedError(GPUErrorVariant error);
|
|
236
|
+
|
|
233
237
|
wgpu::Device _instance;
|
|
234
|
-
std::shared_ptr<async::
|
|
238
|
+
std::shared_ptr<async::RuntimeContext> _async;
|
|
235
239
|
std::string _label;
|
|
240
|
+
// Guards the device-lost state below. In the ProcessEvents model both
|
|
241
|
+
// notifyDeviceLost() (fired by Dawn during ProcessEvents) and getLost() run on
|
|
242
|
+
// the owning runtime's own thread, but device destruction can also trigger
|
|
243
|
+
// notifyDeviceLost() synchronously, so the mutex keeps these fields safe.
|
|
244
|
+
std::mutex _lostMutex;
|
|
236
245
|
std::optional<async::AsyncTaskHandle> _lostHandle;
|
|
237
246
|
std::shared_ptr<GPUDeviceLostInfo> _lostInfo;
|
|
238
247
|
bool _lostSettled = false;
|