react-native-webgpu 0.14.1 → 0.15.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.
- package/android/cpp/AndroidColorSpace.h +107 -0
- package/android/cpp/AndroidPlatformContext.h +100 -9
- package/android/cpp/AndroidVideoPlayer.h +46 -1
- package/android/cpp/cpp-adapter.cpp +53 -1
- package/android/src/main/java/com/webgpu/SyncFences.java +88 -0
- package/android/src/main/java/com/webgpu/ViewSnapshot.java +66 -23
- package/android/src/main/java/com/webgpu/WebGPUModule.java +69 -5
- package/android/src/main/java/com/webgpu/WebGPUVideoPlayer.java +109 -0
- package/apple/ApplePlatformContext.h +5 -5
- package/apple/ApplePlatformContext.mm +75 -3
- package/apple/AppleVideoPlayer.mm +68 -35
- package/cpp/dawn/common/ExternalTextureParams.h +67 -0
- package/cpp/rnwgpu/PlatformContext.h +65 -16
- package/cpp/rnwgpu/SurfaceRegistry.h +39 -5
- package/cpp/rnwgpu/api/GPUAdapter.cpp +35 -0
- package/cpp/rnwgpu/api/GPUExternalTexture.cpp +172 -156
- package/cpp/rnwgpu/api/GPUExternalTexture.h +2 -19
- package/cpp/rnwgpu/api/GPUQueue.cpp +98 -3
- package/cpp/rnwgpu/api/RNWebGPU.h +12 -3
- package/cpp/rnwgpu/api/VideoFrameBlit.h +39 -24
- package/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +10 -3
- package/lib/commonjs/Canvas.js +36 -6
- package/lib/commonjs/Canvas.js.map +1 -1
- package/lib/commonjs/WebPolyfillGPUModule.js +6 -3
- package/lib/commonjs/WebPolyfillGPUModule.js.map +1 -1
- package/lib/commonjs/constants.js +6 -3
- package/lib/commonjs/constants.js.map +1 -1
- package/lib/commonjs/index.js +1 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/install.js +9 -22
- package/lib/commonjs/install.js.map +1 -1
- package/lib/commonjs/main/index.js +8 -7
- package/lib/commonjs/main/index.js.map +1 -1
- package/lib/commonjs/main/index.web.js +1 -1
- package/lib/commonjs/main/installNative.js +20 -0
- package/lib/commonjs/main/installNative.js.map +1 -0
- package/lib/commonjs/main/installNative.web.js +4 -0
- package/lib/commonjs/main/installNative.web.js.map +1 -0
- package/lib/commonjs/mock.js +60 -13
- package/lib/commonjs/mock.js.map +1 -1
- package/lib/module/Canvas.js +37 -7
- package/lib/module/Canvas.js.map +1 -1
- package/lib/module/WebPolyfillGPUModule.js +6 -3
- package/lib/module/WebPolyfillGPUModule.js.map +1 -1
- package/lib/module/constants.js +6 -3
- package/lib/module/constants.js.map +1 -1
- package/lib/module/index.js +8 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/install.js +8 -20
- package/lib/module/install.js.map +1 -1
- package/lib/module/main/index.js +6 -7
- package/lib/module/main/index.js.map +1 -1
- package/lib/module/main/index.web.js +1 -1
- package/lib/module/main/index.web.js.map +1 -1
- package/lib/module/main/installNative.js +18 -0
- package/lib/module/main/installNative.js.map +1 -0
- package/lib/module/main/installNative.web.js +6 -0
- package/lib/module/main/installNative.web.js.map +1 -0
- package/lib/module/mock.js +55 -1
- package/lib/module/mock.js.map +1 -1
- package/lib/typescript/lib/commonjs/Canvas.d.ts.map +1 -1
- package/lib/typescript/lib/commonjs/install.d.ts +41 -3
- package/lib/typescript/lib/commonjs/install.d.ts.map +1 -1
- package/lib/typescript/lib/commonjs/main/installNative.d.ts +2 -0
- package/lib/typescript/lib/commonjs/main/installNative.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/main/installNative.web.d.ts +2 -0
- package/lib/typescript/lib/commonjs/main/installNative.web.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/mock.d.ts +39 -0
- package/lib/typescript/lib/commonjs/mock.d.ts.map +1 -1
- package/lib/typescript/lib/module/Canvas.d.ts.map +1 -1
- package/lib/typescript/lib/module/install.d.ts +0 -1
- package/lib/typescript/lib/module/install.d.ts.map +1 -1
- package/lib/typescript/lib/module/main/installNative.d.ts +2 -0
- package/lib/typescript/lib/module/main/installNative.d.ts.map +1 -0
- package/lib/typescript/lib/module/main/installNative.web.d.ts +2 -0
- package/lib/typescript/lib/module/main/installNative.web.d.ts.map +1 -0
- package/lib/typescript/lib/module/mock.d.ts +39 -1
- package/lib/typescript/lib/module/mock.d.ts.map +1 -1
- package/lib/typescript/src/Canvas.d.ts.map +1 -1
- package/lib/typescript/src/constants.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/install.d.ts +0 -5
- package/lib/typescript/src/install.d.ts.map +1 -1
- package/lib/typescript/src/main/index.d.ts +1 -0
- package/lib/typescript/src/main/index.d.ts.map +1 -1
- package/lib/typescript/src/main/index.web.d.ts +1 -1
- package/lib/typescript/src/main/index.web.d.ts.map +1 -1
- package/lib/typescript/src/main/installNative.d.ts +2 -0
- package/lib/typescript/src/main/installNative.d.ts.map +1 -0
- package/lib/typescript/src/main/installNative.web.d.ts +2 -0
- package/lib/typescript/src/main/installNative.web.d.ts.map +1 -0
- package/lib/typescript/src/mock.d.ts +5 -1
- package/lib/typescript/src/mock.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Canvas.tsx +48 -29
- package/src/WebPolyfillGPUModule.ts +3 -1
- package/src/constants.ts +6 -3
- package/src/index.tsx +18 -10
- package/src/install.ts +9 -18
- package/src/main/index.tsx +7 -10
- package/src/main/index.web.tsx +1 -1
- package/src/main/installNative.ts +20 -0
- package/src/main/installNative.web.ts +5 -0
- package/src/mock.ts +60 -1
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include <functional>
|
|
4
4
|
#include <memory>
|
|
5
5
|
#include <mutex>
|
|
6
|
+
#include <optional>
|
|
6
7
|
#include <span>
|
|
7
8
|
#include <string>
|
|
8
9
|
#include <utility>
|
|
@@ -36,6 +37,20 @@ enum class VideoPixelFormat {
|
|
|
36
37
|
NV12,
|
|
37
38
|
};
|
|
38
39
|
|
|
40
|
+
// The color space of a YUV frame, as its producer reports it: the YCbCr matrix
|
|
41
|
+
// and range that encode the samples, and the primaries and transfer function of
|
|
42
|
+
// the RGB they encode. Each member is optional: what the producer does not know
|
|
43
|
+
// (a camera buffer carries no color metadata, a container may record only some
|
|
44
|
+
// of it) is resolved at import time (GPUExternalTexture::Create) from the
|
|
45
|
+
// buffer and the platform's norm. Dawn converts the samples to RGB in the
|
|
46
|
+
// destination color space while sampling the external texture.
|
|
47
|
+
struct VideoFrameColorSpace {
|
|
48
|
+
std::optional<wgpu::ColorSpacePrimariesDawn> primaries;
|
|
49
|
+
std::optional<wgpu::ColorSpaceTransferDawn> transfer;
|
|
50
|
+
std::optional<wgpu::ColorSpaceYCbCrRangeDawn> range;
|
|
51
|
+
std::optional<wgpu::ColorSpaceYCbCrMatrixDawn> matrix;
|
|
52
|
+
};
|
|
53
|
+
|
|
39
54
|
// A native handle to a video frame that can be imported into a
|
|
40
55
|
// GPUSharedTextureMemory.
|
|
41
56
|
//
|
|
@@ -50,14 +65,33 @@ struct VideoFrameHandle {
|
|
|
50
65
|
uint32_t width = 0;
|
|
51
66
|
uint32_t height = 0;
|
|
52
67
|
VideoPixelFormat pixelFormat = VideoPixelFormat::BGRA8;
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
// The color space of the samples. Only meaningful when pixelFormat == NV12:
|
|
69
|
+
// from the CVPixelBuffer attachments on Apple platforms, from the Image's
|
|
70
|
+
// data space (API 33) or the container's color info on Android.
|
|
71
|
+
VideoFrameColorSpace colorSpace;
|
|
72
|
+
// Android: the acquire fence of the frame as a sync file descriptor, or -1.
|
|
73
|
+
// The producer (video decoder, camera) may still be writing the buffer when
|
|
74
|
+
// the consumer gets it; the GPU work that reads the frame waits on this fence
|
|
75
|
+
// (imported as a shared-fence-sync-fd into BeginAccess). Owned by the handle:
|
|
76
|
+
// the deleter closes it. Importing it into Dawn duplicates it, so the frame
|
|
77
|
+
// can be imported more than once.
|
|
78
|
+
int acquireFenceFd = -1;
|
|
58
79
|
std::function<void()> deleter;
|
|
59
80
|
};
|
|
60
81
|
|
|
82
|
+
// The samples of the NV12 test frame of createTestVideoFrame: pure red and
|
|
83
|
+
// pure green in BT.709 limited range (Y 16..235, Cb/Cr 16..240), so the frame
|
|
84
|
+
// converts back to exactly those colors in sRGB. Shared by both platforms so
|
|
85
|
+
// the e2e spec sees the same frame on each.
|
|
86
|
+
namespace test_yuv_frame {
|
|
87
|
+
constexpr uint8_t kRedY = 63;
|
|
88
|
+
constexpr uint8_t kRedCb = 102;
|
|
89
|
+
constexpr uint8_t kRedCr = 240;
|
|
90
|
+
constexpr uint8_t kGreenY = 173;
|
|
91
|
+
constexpr uint8_t kGreenCb = 42;
|
|
92
|
+
constexpr uint8_t kGreenCr = 26;
|
|
93
|
+
} // namespace test_yuv_frame
|
|
94
|
+
|
|
61
95
|
// Platform-implemented video source that hands out fresh IOSurface /
|
|
62
96
|
// AHardwareBuffer-backed frames as a video plays, with the playback controls
|
|
63
97
|
// of an HTMLMediaElement (times in seconds).
|
|
@@ -110,6 +144,10 @@ struct ViewSnapshotRequest {
|
|
|
110
144
|
double sourceHeight = 0;
|
|
111
145
|
uint32_t width = 0;
|
|
112
146
|
uint32_t height = 0;
|
|
147
|
+
// Whether the caller can draw a GPU frame (a VideoFrameHandle) into the
|
|
148
|
+
// destination itself. A platform that renders the view into a GPU buffer
|
|
149
|
+
// then hands that buffer over instead of reading the pixels back.
|
|
150
|
+
bool allowFrame = false;
|
|
113
151
|
};
|
|
114
152
|
|
|
115
153
|
class PlatformContext {
|
|
@@ -129,17 +167,24 @@ public:
|
|
|
129
167
|
return currentSlot();
|
|
130
168
|
}
|
|
131
169
|
|
|
132
|
-
// Rasterize a native view
|
|
133
|
-
//
|
|
134
|
-
//
|
|
170
|
+
// Rasterize a native view (see ViewSnapshotRequest). The implementation hops
|
|
171
|
+
// to the platform UI thread, so this is asynchronous: exactly one of
|
|
172
|
+
// onPixels / onFrame / onError is invoked, from an arbitrary thread
|
|
135
173
|
// (typically the UI thread). Callers must not touch JSI in the callbacks.
|
|
136
174
|
//
|
|
137
|
-
//
|
|
138
|
-
// pixel, `format`
|
|
139
|
-
// rasterizer produces natively, and `premultiplied`
|
|
140
|
-
// representation.
|
|
175
|
+
// onPixels receives the view as CPU pixels: tightly packed (no row
|
|
176
|
+
// padding), 4 bytes per pixel, `format` rgba8unorm or bgra8unorm depending
|
|
177
|
+
// on what the platform rasterizer produces natively, and `premultiplied`
|
|
178
|
+
// reporting its alpha representation.
|
|
179
|
+
//
|
|
180
|
+
// onFrame, only when the request allows it, receives the GPU buffer the
|
|
181
|
+
// platform rendered the view into (Android 13 and above: the
|
|
182
|
+
// HardwareRenderer's AHardwareBuffer, with the fence that signals when the
|
|
183
|
+
// drawing is done), as an RGBA frame of premultiplied pixels. The receiver
|
|
184
|
+
// owns the frame and releases it through its deleter.
|
|
141
185
|
virtual void snapshotView(const ViewSnapshotRequest &request,
|
|
142
|
-
std::function<void(ImageData)>
|
|
186
|
+
std::function<void(ImageData)> onPixels,
|
|
187
|
+
std::function<void(VideoFrameHandle)> onFrame,
|
|
143
188
|
std::function<void(std::string)> onError) = 0;
|
|
144
189
|
|
|
145
190
|
virtual ImageData createImageBitmap(std::string blobId, double offset,
|
|
@@ -167,9 +212,13 @@ public:
|
|
|
167
212
|
|
|
168
213
|
// Create a synthetic, GPU-shareable IOSurface/AHardwareBuffer filled with a
|
|
169
214
|
// generated test pattern. Avoids the need to bundle a video asset for the
|
|
170
|
-
// SharedTextureMemory example.
|
|
171
|
-
|
|
172
|
-
|
|
215
|
+
// SharedTextureMemory example. BGRA8 is an RGB gradient; NV12 is a biplanar
|
|
216
|
+
// YUV frame, BT.709 limited range, red on the left half and green on the
|
|
217
|
+
// right, which exercises the color conversion of importExternalTexture.
|
|
218
|
+
// Throws a message containing "unsupported" where the platform cannot
|
|
219
|
+
// allocate or fill the YUV layout (Android before API 29).
|
|
220
|
+
virtual VideoFrameHandle createTestVideoFrame(uint32_t width, uint32_t height,
|
|
221
|
+
VideoPixelFormat format) = 0;
|
|
173
222
|
|
|
174
223
|
// Open a video file at `path` for playback. The returned player yields
|
|
175
224
|
// IOSurface / AHardwareBuffer-backed frames via copyLatestFrame().
|
|
@@ -1284,6 +1284,7 @@ public:
|
|
|
1284
1284
|
void removeSurfaceInfo(int id) {
|
|
1285
1285
|
std::unique_lock<std::shared_mutex> lock(_mutex);
|
|
1286
1286
|
_registry.erase(id);
|
|
1287
|
+
_retired.erase(id);
|
|
1287
1288
|
}
|
|
1288
1289
|
|
|
1289
1290
|
std::shared_ptr<SurfaceInfo>
|
|
@@ -1310,13 +1311,25 @@ public:
|
|
|
1310
1311
|
|
|
1311
1312
|
// Erase the entry only if no native surface is attached or pending; the
|
|
1312
1313
|
// atomic counterpart of attachSurface above (see RNWebGPU::destroyContext
|
|
1313
|
-
// for the ownership split this implements).
|
|
1314
|
+
// for the ownership split this implements). The SurfaceInfo is let go of,
|
|
1315
|
+
// not forgotten: for as long as a GPUCanvasContext holds it, the next
|
|
1316
|
+
// find-or-create for the id (the native view's attach, or another context)
|
|
1317
|
+
// takes it over. React's StrictMode runs the Canvas cleanup once right after
|
|
1318
|
+
// mount, before a lagging UI thread attached the surface, and the context
|
|
1319
|
+
// the first effect run made stays in use; it would otherwise render into a
|
|
1320
|
+
// SurfaceInfo no view ever attaches to.
|
|
1314
1321
|
void removeSurfaceInfoIfDetached(int id) {
|
|
1315
1322
|
std::unique_lock<std::shared_mutex> lock(_mutex);
|
|
1316
1323
|
auto it = _registry.find(id);
|
|
1317
1324
|
if (it == _registry.end() || it->second->hasNativeSurface()) {
|
|
1318
1325
|
return;
|
|
1319
1326
|
}
|
|
1327
|
+
pruneRetiredLocked();
|
|
1328
|
+
if (it->second.use_count() > 1) {
|
|
1329
|
+
// A GPUCanvasContext holds it: keep it reachable for the next
|
|
1330
|
+
// find-or-create (see getSurfaceInfoOrCreateLocked).
|
|
1331
|
+
_retired[id] = it->second;
|
|
1332
|
+
}
|
|
1320
1333
|
_registry.erase(it);
|
|
1321
1334
|
}
|
|
1322
1335
|
|
|
@@ -1350,6 +1363,7 @@ public:
|
|
|
1350
1363
|
void clear() {
|
|
1351
1364
|
std::unique_lock<std::shared_mutex> lock(_mutex);
|
|
1352
1365
|
_registry.clear();
|
|
1366
|
+
_retired.clear();
|
|
1353
1367
|
}
|
|
1354
1368
|
|
|
1355
1369
|
private:
|
|
@@ -1363,14 +1377,30 @@ private:
|
|
|
1363
1377
|
if (it != _registry.end()) {
|
|
1364
1378
|
return it->second;
|
|
1365
1379
|
}
|
|
1366
|
-
|
|
1380
|
+
// A retired entry whose GPUCanvasContext still holds the SurfaceInfo is
|
|
1381
|
+
// owned again (see removeSurfaceInfoIfDetached).
|
|
1382
|
+
std::shared_ptr<SurfaceInfo> info;
|
|
1383
|
+
auto retired = _retired.find(id);
|
|
1384
|
+
if (retired != _retired.end()) {
|
|
1385
|
+
info = retired->second.lock();
|
|
1386
|
+
_retired.erase(retired);
|
|
1387
|
+
}
|
|
1388
|
+
if (!info) {
|
|
1389
|
+
info = std::make_shared<SurfaceInfo>(gpu, width, height);
|
|
1390
|
+
// DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
|
|
1391
|
+
pruneAllSurfacesLocked();
|
|
1392
|
+
_allSurfaces.push_back(info);
|
|
1393
|
+
}
|
|
1367
1394
|
_registry[id] = info;
|
|
1368
|
-
// DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
|
|
1369
|
-
pruneAllSurfacesLocked();
|
|
1370
|
-
_allSurfaces.push_back(info);
|
|
1371
1395
|
return info;
|
|
1372
1396
|
}
|
|
1373
1397
|
|
|
1398
|
+
void pruneRetiredLocked() {
|
|
1399
|
+
for (auto it = _retired.begin(); it != _retired.end();) {
|
|
1400
|
+
it = it->second.expired() ? _retired.erase(it) : ++it;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1374
1404
|
// DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
|
|
1375
1405
|
void pruneAllSurfacesLocked() {
|
|
1376
1406
|
_allSurfaces.erase(
|
|
@@ -1383,6 +1413,10 @@ private:
|
|
|
1383
1413
|
|
|
1384
1414
|
mutable std::shared_mutex _mutex;
|
|
1385
1415
|
std::unordered_map<int, std::shared_ptr<SurfaceInfo>> _registry;
|
|
1416
|
+
// The entries JS retired while a GPUCanvasContext still held their
|
|
1417
|
+
// SurfaceInfo (see removeSurfaceInfoIfDetached). Non-owning; pruned on
|
|
1418
|
+
// every retire.
|
|
1419
|
+
std::unordered_map<int, std::weak_ptr<SurfaceInfo>> _retired;
|
|
1386
1420
|
// DAWN_WORKAROUND_DEVICE_DESTROY_BEFORE_SURFACE_RELEASE
|
|
1387
1421
|
// Every live SurfaceInfo, including the ones no longer in _registry.
|
|
1388
1422
|
// Non-owning; pruned on insert and on every device destroy.
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
#ifdef __APPLE__
|
|
13
13
|
#include <TargetConditionals.h>
|
|
14
14
|
#endif
|
|
15
|
+
#ifdef __ANDROID__
|
|
16
|
+
#include <android/log.h>
|
|
17
|
+
#endif
|
|
15
18
|
|
|
16
19
|
#include "Convertors.h"
|
|
17
20
|
|
|
@@ -158,7 +161,14 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
158
161
|
message.length > 0 ? std::string(message.data, message.length) : "";
|
|
159
162
|
std::string fullMessage =
|
|
160
163
|
msg.length() > 0 ? std::string(errorType) + ": " + msg : "no message";
|
|
164
|
+
#ifdef __ANDROID__
|
|
165
|
+
// stderr goes nowhere in an Android app; logcat is where the message can
|
|
166
|
+
// be read (and where CI collects it).
|
|
167
|
+
__android_log_print(ANDROID_LOG_ERROR, "WebGPU", "Uncaptured error: %s",
|
|
168
|
+
fullMessage.c_str());
|
|
169
|
+
#else
|
|
161
170
|
fprintf(stderr, "%s\n", fullMessage.c_str());
|
|
171
|
+
#endif
|
|
162
172
|
|
|
163
173
|
// Look up the GPUDevice from the registry and notify it
|
|
164
174
|
if (auto gpuDevice = GPUDevice::lookupDevice(device.Get())) {
|
|
@@ -224,6 +234,31 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
224
234
|
disabledToggles.push_back(name);
|
|
225
235
|
}
|
|
226
236
|
}
|
|
237
|
+
#endif
|
|
238
|
+
#if defined(__ANDROID__)
|
|
239
|
+
// Dawn checks the memory a VkImage needs for an imported
|
|
240
|
+
// AHardwareBuffer against the allocation size the driver reports for
|
|
241
|
+
// the buffer, and some drivers report it wrong: Dawn itself skips the
|
|
242
|
+
// check on Samsung, Qualcomm and Huawei drivers
|
|
243
|
+
// (https://crbug.com/333424893). The emulator (gfxstream) reports 0
|
|
244
|
+
// for the buffers HWUI draws into, which rejects every view snapshot
|
|
245
|
+
// and SurfaceControl import there, so skip it on all of Android unless
|
|
246
|
+
// the caller disables the toggle. Dawn drops unknown toggle names, so a
|
|
247
|
+
// build without this toggle is unaffected.
|
|
248
|
+
static const char *const kAndroidEnabledToggles[] = {
|
|
249
|
+
"ignore_imported_ahardwarebuffer_vulkan_image_size"};
|
|
250
|
+
for (const char *name : kAndroidEnabledToggles) {
|
|
251
|
+
const auto named = [name](const char *t) {
|
|
252
|
+
return std::strcmp(t, name) == 0;
|
|
253
|
+
};
|
|
254
|
+
const bool explicitlyDisabled = std::any_of(
|
|
255
|
+
disabledToggles.begin(), disabledToggles.end(), named);
|
|
256
|
+
const bool alreadyEnabled =
|
|
257
|
+
std::any_of(enabledToggles.begin(), enabledToggles.end(), named);
|
|
258
|
+
if (!explicitlyDisabled && !alreadyEnabled) {
|
|
259
|
+
enabledToggles.push_back(name);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
227
262
|
#endif
|
|
228
263
|
if (!enabledToggles.empty() || !disabledToggles.empty()) {
|
|
229
264
|
toggles.enabledToggleCount = enabledToggles.size();
|