react-native-webgpu 0.5.18 → 0.6.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/AndroidPlatformContext.h +24 -9
- package/cpp/rnwgpu/api/GPUAdapter.cpp +33 -4
- package/cpp/rnwgpu/api/GPUExternalTexture.cpp +105 -74
- package/cpp/rnwgpu/api/GPUExternalTexture.h +21 -2
- package/cpp/rnwgpu/async/RuntimeContext.cpp +8 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +3 -1
- package/src/index.tsx +9 -0
|
@@ -241,8 +241,8 @@ public:
|
|
|
241
241
|
const uint32_t stridePixels = actualDesc.stride;
|
|
242
242
|
|
|
243
243
|
void *vaddr = nullptr;
|
|
244
|
-
int rc = AHardwareBuffer_lock(
|
|
245
|
-
|
|
244
|
+
int rc = AHardwareBuffer_lock(
|
|
245
|
+
buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY, -1, nullptr, &vaddr);
|
|
246
246
|
if (rc != 0 || !vaddr) {
|
|
247
247
|
AHardwareBuffer_release(buffer);
|
|
248
248
|
throw std::runtime_error(
|
|
@@ -302,6 +302,21 @@ public:
|
|
|
302
302
|
AHardwareBuffer_Desc desc = {};
|
|
303
303
|
AHardwareBuffer_describe(buffer, &desc);
|
|
304
304
|
|
|
305
|
+
// Dawn derives the importable WebGPU usages from the AHB's usage bits;
|
|
306
|
+
// without GPU_SAMPLED_IMAGE the imported texture never gets
|
|
307
|
+
// TextureBinding and import fails deep inside Dawn with an opaque
|
|
308
|
+
// validation error. Surface the real cause here instead. (CameraX's
|
|
309
|
+
// default ImageReaders allocate CPU-only buffers; with
|
|
310
|
+
// react-native-vision-camera, use pixelFormat: 'native' which allocates
|
|
311
|
+
// GPU-sampleable buffers.)
|
|
312
|
+
if ((desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) == 0) {
|
|
313
|
+
throw std::runtime_error(
|
|
314
|
+
"wrapNativeBuffer: this AHardwareBuffer was allocated without "
|
|
315
|
+
"AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, so the GPU cannot sample "
|
|
316
|
+
"it. Camera/CPU pipelines must allocate frames with GPU usage (for "
|
|
317
|
+
"react-native-vision-camera, use pixelFormat: 'native').");
|
|
318
|
+
}
|
|
319
|
+
|
|
305
320
|
AHardwareBuffer_acquire(buffer);
|
|
306
321
|
|
|
307
322
|
VideoFrameHandle handle;
|
|
@@ -312,13 +327,13 @@ public:
|
|
|
312
327
|
// Dawn's OpaqueYCbCrAndroidForExternalTexture path. Single-plane RGBA AHBs
|
|
313
328
|
// take the plain BGRA8 path (sampled as a regular 2D texture).
|
|
314
329
|
switch (desc.format) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
330
|
+
case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
|
|
331
|
+
case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
|
|
332
|
+
handle.pixelFormat = VideoPixelFormat::NV12;
|
|
333
|
+
break;
|
|
334
|
+
default:
|
|
335
|
+
handle.pixelFormat = VideoPixelFormat::BGRA8;
|
|
336
|
+
break;
|
|
322
337
|
}
|
|
323
338
|
handle.deleter = [buffer]() { AHardwareBuffer_release(buffer); };
|
|
324
339
|
return handle;
|
|
@@ -2,12 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
#include <algorithm>
|
|
4
4
|
#include <cstdio>
|
|
5
|
+
#include <cstring>
|
|
5
6
|
#include <memory>
|
|
6
7
|
#include <string>
|
|
7
8
|
#include <unordered_set>
|
|
8
9
|
#include <utility>
|
|
9
10
|
#include <vector>
|
|
10
11
|
|
|
12
|
+
#ifdef __APPLE__
|
|
13
|
+
#include <TargetConditionals.h>
|
|
14
|
+
#endif
|
|
15
|
+
|
|
11
16
|
#include "Convertors.h"
|
|
12
17
|
|
|
13
18
|
#include "GPUFeatures.h"
|
|
@@ -150,16 +155,40 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
150
155
|
for (const auto &t : dawnToggles->enabledToggles.value()) {
|
|
151
156
|
enabledToggles.push_back(t.c_str());
|
|
152
157
|
}
|
|
153
|
-
toggles.enabledToggleCount = enabledToggles.size();
|
|
154
|
-
toggles.enabledToggles = enabledToggles.data();
|
|
155
158
|
}
|
|
156
159
|
if (dawnToggles->disabledToggles) {
|
|
157
160
|
for (const auto &t : dawnToggles->disabledToggles.value()) {
|
|
158
161
|
disabledToggles.push_back(t.c_str());
|
|
159
162
|
}
|
|
160
|
-
toggles.disabledToggleCount = disabledToggles.size();
|
|
161
|
-
toggles.disabledToggles = disabledToggles.data();
|
|
162
163
|
}
|
|
164
|
+
}
|
|
165
|
+
// TODO: in the latest version of Dawn, this won't be needed (https://issues.chromium.org/issues/42241591)
|
|
166
|
+
#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
|
|
167
|
+
// The iOS Simulator only advertises MTLFeatureSet_iOS_GPUFamily2, so
|
|
168
|
+
// Dawn defaults disable_base_instance/disable_base_vertex on and then
|
|
169
|
+
// rejects every draw with a non-zero firstInstance or baseVertex,
|
|
170
|
+
// both core WebGPU. The simulator forwards Metal calls to the host
|
|
171
|
+
// GPU, which does support base vertex/instance drawing, so force the
|
|
172
|
+
// toggles off. Device builds are unaffected: WebGPU-capable iPhones
|
|
173
|
+
// and iPads are all GPUFamily3+. These are device-stage toggles, so
|
|
174
|
+
// they must be chained here rather than on the instance descriptor
|
|
175
|
+
// (instance-stage toggle parsing silently drops them).
|
|
176
|
+
static const char *const kSimulatorDisabledToggles[] = {
|
|
177
|
+
"disable_base_instance", "disable_base_vertex"};
|
|
178
|
+
for (const char *name : kSimulatorDisabledToggles) {
|
|
179
|
+
const bool explicitlyEnabled = std::any_of(
|
|
180
|
+
enabledToggles.begin(), enabledToggles.end(),
|
|
181
|
+
[name](const char *t) { return std::strcmp(t, name) == 0; });
|
|
182
|
+
if (!explicitlyEnabled) {
|
|
183
|
+
disabledToggles.push_back(name);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
#endif
|
|
187
|
+
if (!enabledToggles.empty() || !disabledToggles.empty()) {
|
|
188
|
+
toggles.enabledToggleCount = enabledToggles.size();
|
|
189
|
+
toggles.enabledToggles = enabledToggles.data();
|
|
190
|
+
toggles.disabledToggleCount = disabledToggles.size();
|
|
191
|
+
toggles.disabledToggles = disabledToggles.data();
|
|
163
192
|
deviceDesc.nextInChain = &toggles;
|
|
164
193
|
}
|
|
165
194
|
_instance.RequestDevice(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "GPUExternalTexture.h"
|
|
2
2
|
|
|
3
|
+
#include <array>
|
|
3
4
|
#include <cmath>
|
|
4
5
|
#include <memory>
|
|
5
6
|
#include <string>
|
|
@@ -56,44 +57,76 @@ static const float kIdentityTransferParams[7] = {
|
|
|
56
57
|
0.0f, // F
|
|
57
58
|
};
|
|
58
59
|
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// range if it matters).
|
|
68
|
-
[[maybe_unused]] static const float kBT709LimitedToRgb[12] = {
|
|
69
|
-
1.164383f, 0.000000f, 1.792741f, -0.972945f, //
|
|
70
|
-
1.164383f, -0.213249f, -0.532909f, 0.301517f, //
|
|
71
|
-
1.164383f, 2.112402f, 0.000000f, -1.133402f, //
|
|
60
|
+
// Identity passthrough for GPUExternalTexture.yuvToRgbMatrix: the sampled
|
|
61
|
+
// texel is already RGB (Apple's biplanar path where Dawn converts in the
|
|
62
|
+
// sampler transform, RGBA surfaces, or an Android AHB whose driver reports
|
|
63
|
+
// RGB_IDENTITY). A 3x4 row-major matrix mapping [c.r, c.g, c.b, 1] to itself.
|
|
64
|
+
static constexpr std::array<float, 12> kYuvPassthroughMatrix = {
|
|
65
|
+
1.0f, 0.0f, 0.0f, 0.0f, //
|
|
66
|
+
0.0f, 1.0f, 0.0f, 0.0f, //
|
|
67
|
+
0.0f, 0.0f, 1.0f, 0.0f, //
|
|
72
68
|
};
|
|
73
69
|
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
70
|
+
// Build a 3x4 row-major matrix mapping the *sampled* gamma-encoded
|
|
71
|
+
// [Y, Cb, Cr, 1] (each normalized to [0,1]) to gamma-encoded R'G'B', from the
|
|
72
|
+
// Vulkan-suggested YCbCr model + range of an Android external-format buffer.
|
|
73
|
+
// Needed because Dawn's opaque-YCbCr sampling path hard-codes an RGB_IDENTITY
|
|
74
|
+
// conversion (SamplerVk.cpp::GetYCbCrForTextureView, crbug.com/497675620), so
|
|
75
|
+
// the shader receives raw Y/Cb/Cr and must convert itself.
|
|
76
|
+
// The VkSamplerYcbcrModelConversion / VkSamplerYcbcrRange values are inlined
|
|
77
|
+
// to avoid a Vulkan header dependency in this cross-platform file.
|
|
78
|
+
[[maybe_unused]] static std::array<float, 12>
|
|
79
|
+
makeYuvToRgbMatrix(uint32_t vkModel, uint32_t vkRange) {
|
|
80
|
+
constexpr uint32_t kModelRgbIdentity = 0; // VK_..._RGB_IDENTITY
|
|
81
|
+
constexpr uint32_t kModel709 = 2; // VK_..._YCBCR_709
|
|
82
|
+
constexpr uint32_t kModel601 = 3; // VK_..._YCBCR_601
|
|
83
|
+
constexpr uint32_t kModel2020 = 4; // VK_..._YCBCR_2020
|
|
84
|
+
constexpr uint32_t kRangeItuNarrow = 1; // VK_SAMPLER_YCBCR_RANGE_ITU_NARROW
|
|
85
|
+
|
|
86
|
+
if (vkModel == kModelRgbIdentity) {
|
|
87
|
+
// The buffer content is RGB; nothing to convert.
|
|
88
|
+
return kYuvPassthroughMatrix;
|
|
89
|
+
}
|
|
90
|
+
float kr;
|
|
91
|
+
float kb;
|
|
92
|
+
switch (vkModel) {
|
|
93
|
+
case kModel709:
|
|
94
|
+
kr = 0.2126f;
|
|
95
|
+
kb = 0.0722f;
|
|
96
|
+
break;
|
|
97
|
+
case kModel2020:
|
|
98
|
+
kr = 0.2627f;
|
|
99
|
+
kb = 0.0593f;
|
|
100
|
+
break;
|
|
101
|
+
case kModel601:
|
|
87
102
|
default:
|
|
88
|
-
|
|
103
|
+
// YCBCR_IDENTITY and unknown models: Android camera streams are BT.601 in
|
|
104
|
+
// practice, so that is the sane default.
|
|
105
|
+
kr = 0.299f;
|
|
106
|
+
kb = 0.114f;
|
|
107
|
+
break;
|
|
89
108
|
}
|
|
109
|
+
const float kg = 1.0f - kr - kb;
|
|
110
|
+
const bool narrow = vkRange == kRangeItuNarrow;
|
|
111
|
+
const float yScale = narrow ? 255.0f / 219.0f : 1.0f;
|
|
112
|
+
const float cScale = narrow ? 255.0f / 224.0f : 1.0f;
|
|
113
|
+
const float yOffset = narrow ? 16.0f / 255.0f : 0.0f;
|
|
114
|
+
const float cOffset = 128.0f / 255.0f;
|
|
115
|
+
const float crR = 2.0f * (1.0f - kr) * cScale;
|
|
116
|
+
const float cbG = -2.0f * kb * (1.0f - kb) / kg * cScale;
|
|
117
|
+
const float crG = -2.0f * kr * (1.0f - kr) / kg * cScale;
|
|
118
|
+
const float cbB = 2.0f * (1.0f - kb) * cScale;
|
|
119
|
+
return {
|
|
120
|
+
yScale, 0.0f, crR, -yScale * yOffset - crR * cOffset, //
|
|
121
|
+
yScale, cbG, crG, -yScale * yOffset - (cbG + crG) * cOffset, //
|
|
122
|
+
yScale, cbB, 0.0f, -yScale * yOffset - cbB * cOffset, //
|
|
123
|
+
};
|
|
90
124
|
}
|
|
91
125
|
|
|
92
126
|
// Map a rotation in degrees (0 / 90 / 180 / 270) to Dawn's enum. Anything that
|
|
93
127
|
// isn't a clean multiple of 90 snaps to the nearest quadrant; Dawn only
|
|
94
128
|
// supports those four steps for external textures.
|
|
95
|
-
static wgpu::ExternalTextureRotation
|
|
96
|
-
toExternalTextureRotation(double degrees) {
|
|
129
|
+
static wgpu::ExternalTextureRotation toExternalTextureRotation(double degrees) {
|
|
97
130
|
int quadrant = static_cast<int>(std::lround(degrees / 90.0)) & 3;
|
|
98
131
|
switch (quadrant) {
|
|
99
132
|
case 1:
|
|
@@ -216,7 +249,11 @@ std::shared_ptr<GPUExternalTexture> GPUExternalTexture::Create(
|
|
|
216
249
|
|
|
217
250
|
return std::make_shared<GPUExternalTexture>(
|
|
218
251
|
std::move(external), std::move(memory), std::move(texture),
|
|
219
|
-
std::move(descriptor->source), std::move(label)
|
|
252
|
+
std::move(descriptor->source), std::move(label),
|
|
253
|
+
// Dawn's Metal path applies the YUV->RGB conversion (from
|
|
254
|
+
// frame.yuvToRgbMatrix above) inside the sampling transform, so the
|
|
255
|
+
// sampled texel is already RGB.
|
|
256
|
+
kYuvPassthroughMatrix);
|
|
220
257
|
#elif defined(__ANDROID__)
|
|
221
258
|
// 1. Import the AHardwareBuffer as SharedTextureMemory. For YUV AHBs this
|
|
222
259
|
// yields a Dawn texture in the implementation-defined OpaqueYCbCrAndroid
|
|
@@ -257,32 +294,39 @@ std::shared_ptr<GPUExternalTexture> GPUExternalTexture::Create(
|
|
|
257
294
|
"GPUExternalTexture::Create(): BeginAccess failed");
|
|
258
295
|
}
|
|
259
296
|
|
|
260
|
-
// 4.
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
// a
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
//
|
|
267
|
-
//
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
297
|
+
// 4. Resolve the YUV->RGB conversion the *shader* must apply. Dawn imports
|
|
298
|
+
// every YUV / implementation-defined AHB format as OpaqueYCbCrAndroid
|
|
299
|
+
// (AHBFunctions.cpp::FormatFromAHardwareBufferFormat) and samples it
|
|
300
|
+
// through a Vulkan SamplerYcbcrConversion that is hard-coded to
|
|
301
|
+
// RGB_IDENTITY (SamplerVk.cpp::GetYCbCrForTextureView,
|
|
302
|
+
// crbug.com/497675620), so the sample always comes back as raw
|
|
303
|
+
// [Y, Cb, Cr]. The driver's *suggested* model + range are captured at
|
|
304
|
+
// import time though; read them back from the shared memory's properties
|
|
305
|
+
// and derive the correct conversion matrix, exposed to JS as
|
|
306
|
+
// GPUExternalTexture.yuvToRgbMatrix. Defined color formats (e.g. an RGBA
|
|
307
|
+
// AHB -> RGBA8Unorm) sample as RGB directly and get the passthrough.
|
|
308
|
+
std::array<float, 12> yuvToRgbMatrix = kYuvPassthroughMatrix;
|
|
309
|
+
if (texture.GetFormat() == wgpu::TextureFormat::OpaqueYCbCrAndroid) {
|
|
310
|
+
wgpu::SharedTextureMemoryAHardwareBufferProperties ahbProps{};
|
|
311
|
+
wgpu::SharedTextureMemoryProperties props{};
|
|
312
|
+
props.nextInChain = &ahbProps;
|
|
313
|
+
if (memory.GetProperties(&props)) {
|
|
314
|
+
yuvToRgbMatrix = makeYuvToRgbMatrix(ahbProps.yCbCrInfo.vkYCbCrModel,
|
|
315
|
+
ahbProps.yCbCrInfo.vkYCbCrRange);
|
|
316
|
+
} else {
|
|
317
|
+
// Fall back to the Android camera norm rather than passthrough.
|
|
318
|
+
yuvToRgbMatrix = makeYuvToRgbMatrix(/* YCBCR_601 */ 3,
|
|
319
|
+
/* ITU_NARROW */ 1);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
283
322
|
|
|
284
|
-
|
|
285
|
-
|
|
323
|
+
// 5. Build the ExternalTextureDescriptor: a single (opaque or RGB) plane
|
|
324
|
+
// with identity transfer. The YUV->RGB conversion cannot run inside
|
|
325
|
+
// Dawn's external-texture transform here: the single-plane branch of the
|
|
326
|
+
// Tint transform ignores yuvToRgbConversionMatrix, which is why the
|
|
327
|
+
// matrix is surfaced to the shader instead. The gamut/transfer arrays
|
|
328
|
+
// must still be non-null: ComputeExternalTextureParams dereferences them
|
|
329
|
+
// unconditionally.
|
|
286
330
|
wgpu::ExternalTextureDescriptor extDesc{};
|
|
287
331
|
if (!label.empty()) {
|
|
288
332
|
extDesc.label = wgpu::StringView(label.c_str(), label.size());
|
|
@@ -291,24 +335,10 @@ std::shared_ptr<GPUExternalTexture> GPUExternalTexture::Create(
|
|
|
291
335
|
extDesc.cropSize = {frame.width, frame.height};
|
|
292
336
|
extDesc.apparentSize = {frame.width, frame.height};
|
|
293
337
|
extDesc.gamutConversionMatrix = kIdentityGamutMatrix;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
wgpu::TextureViewDescriptor v1{};
|
|
299
|
-
v1.aspect = wgpu::TextureAspect::Plane1Only;
|
|
300
|
-
plane1 = texture.CreateView(&v1);
|
|
301
|
-
extDesc.plane0 = plane0;
|
|
302
|
-
extDesc.plane1 = plane1;
|
|
303
|
-
extDesc.yuvToRgbConversionMatrix = kBT709LimitedToRgb;
|
|
304
|
-
extDesc.srcTransferFunctionParameters = kSrgbDecodeParams;
|
|
305
|
-
extDesc.dstTransferFunctionParameters = kSrgbEncodeParams;
|
|
306
|
-
} else {
|
|
307
|
-
plane0 = texture.CreateView();
|
|
308
|
-
extDesc.plane0 = plane0;
|
|
309
|
-
extDesc.srcTransferFunctionParameters = kIdentityTransferParams;
|
|
310
|
-
extDesc.dstTransferFunctionParameters = kIdentityTransferParams;
|
|
311
|
-
}
|
|
338
|
+
wgpu::TextureView plane0 = texture.CreateView();
|
|
339
|
+
extDesc.plane0 = plane0;
|
|
340
|
+
extDesc.srcTransferFunctionParameters = kIdentityTransferParams;
|
|
341
|
+
extDesc.dstTransferFunctionParameters = kIdentityTransferParams;
|
|
312
342
|
extDesc.mirrored = descriptor->mirrored.value_or(false);
|
|
313
343
|
extDesc.rotation =
|
|
314
344
|
toExternalTextureRotation(descriptor->rotation.value_or(0));
|
|
@@ -324,7 +354,8 @@ std::shared_ptr<GPUExternalTexture> GPUExternalTexture::Create(
|
|
|
324
354
|
|
|
325
355
|
return std::make_shared<GPUExternalTexture>(
|
|
326
356
|
std::move(external), std::move(memory), std::move(texture),
|
|
327
|
-
std::move(descriptor->source), std::move(label)
|
|
357
|
+
std::move(descriptor->source), std::move(label),
|
|
358
|
+
std::move(yuvToRgbMatrix));
|
|
328
359
|
#else
|
|
329
360
|
throw std::runtime_error(
|
|
330
361
|
"GPUExternalTexture::Create(): not yet implemented on this "
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
#include <array>
|
|
3
4
|
#include <memory>
|
|
4
5
|
#include <string>
|
|
5
6
|
#include <utility>
|
|
7
|
+
#include <vector>
|
|
6
8
|
|
|
7
9
|
#include "Unions.h"
|
|
8
10
|
|
|
@@ -36,10 +38,12 @@ public:
|
|
|
36
38
|
// the producer (e.g. AVPlayer) can reclaim the IOSurface.
|
|
37
39
|
GPUExternalTexture(wgpu::ExternalTexture instance,
|
|
38
40
|
wgpu::SharedTextureMemory memory, wgpu::Texture texture,
|
|
39
|
-
std::shared_ptr<VideoFrame> source, std::string label
|
|
41
|
+
std::shared_ptr<VideoFrame> source, std::string label,
|
|
42
|
+
std::array<float, 12> yuvToRgbMatrix)
|
|
40
43
|
: NativeObject(CLASS_NAME), _instance(std::move(instance)),
|
|
41
44
|
_memory(std::move(memory)), _texture(std::move(texture)),
|
|
42
|
-
_source(std::move(source)), _label(std::move(label))
|
|
45
|
+
_source(std::move(source)), _label(std::move(label)),
|
|
46
|
+
_yuvToRgbMatrix(yuvToRgbMatrix) {}
|
|
43
47
|
|
|
44
48
|
~GPUExternalTexture() override { destroy(); }
|
|
45
49
|
|
|
@@ -69,11 +73,25 @@ public:
|
|
|
69
73
|
_instance.SetLabel(_label.c_str());
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
// Non-spec extension. A 3x4 row-major matrix mapping the *sampled* texel
|
|
77
|
+
// [c.r, c.g, c.b, 1] to gamma-encoded R'G'B'. When Dawn's sampler already
|
|
78
|
+
// produces RGB (Apple's biplanar path, RGBA surfaces), this is the identity
|
|
79
|
+
// passthrough; on the Android opaque-YCbCr path the sample comes back as raw
|
|
80
|
+
// [Y, Cb, Cr] (Dawn hard-codes an RGB_IDENTITY Vulkan conversion, see
|
|
81
|
+
// crbug.com/497675620) and this matrix is derived from the driver's
|
|
82
|
+
// suggested YCbCr model + range for the buffer. Shaders can therefore apply
|
|
83
|
+
// it unconditionally after textureSampleBaseClampToEdge.
|
|
84
|
+
std::vector<double> getYuvToRgbMatrix() {
|
|
85
|
+
return std::vector<double>(_yuvToRgbMatrix.begin(), _yuvToRgbMatrix.end());
|
|
86
|
+
}
|
|
87
|
+
|
|
72
88
|
static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
|
|
73
89
|
installGetter(runtime, prototype, "__brand", &GPUExternalTexture::getBrand);
|
|
74
90
|
installGetterSetter(runtime, prototype, "label",
|
|
75
91
|
&GPUExternalTexture::getLabel,
|
|
76
92
|
&GPUExternalTexture::setLabel);
|
|
93
|
+
installGetter(runtime, prototype, "yuvToRgbMatrix",
|
|
94
|
+
&GPUExternalTexture::getYuvToRgbMatrix);
|
|
77
95
|
installMethod(runtime, prototype, "destroy", &GPUExternalTexture::destroy);
|
|
78
96
|
}
|
|
79
97
|
|
|
@@ -85,6 +103,7 @@ private:
|
|
|
85
103
|
wgpu::Texture _texture;
|
|
86
104
|
std::shared_ptr<VideoFrame> _source;
|
|
87
105
|
std::string _label;
|
|
106
|
+
std::array<float, 12> _yuvToRgbMatrix;
|
|
88
107
|
};
|
|
89
108
|
|
|
90
109
|
} // namespace rnwgpu
|
|
@@ -186,7 +186,14 @@ void RuntimeContext::tick() {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
jsi::UUID RuntimeContext::runtimeDataUUID() {
|
|
189
|
-
|
|
189
|
+
// Fixed random UUID identifying react-native-webgpu's runtimeData slot.
|
|
190
|
+
// Never use the default-constructed all-zero UUID here: Hermes backs
|
|
191
|
+
// runtimeData with a DenseMap that reserves the all-zero UUID as its
|
|
192
|
+
// empty-bucket marker (and the all-0xff UUID as its tombstone), so using
|
|
193
|
+
// either as a key is undefined behavior. It crashes on worklet runtimes,
|
|
194
|
+
// where react-native-worklets seeds runtimeData before we do.
|
|
195
|
+
static constexpr jsi::UUID uuid(0xC06D5D2D, 0xB19B, 0x431B, 0xA89E,
|
|
196
|
+
0x20F8A0B6E31BULL);
|
|
190
197
|
return uuid;
|
|
191
198
|
}
|
|
192
199
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,gCAAgC,EAChC,YAAY,EACZ,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,SAAS,CAAC;AAEjB,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,gCAAgC,EAChC,oCAAoC,EACpC,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,SAAS,CAAC;AAEjB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,SAAS;QACjB,GAAG,EAAE,GAAG,CAAC;KACV;IAED,IAAI,SAAS,EAAE,SAAS,CAAC;IAEzB,IAAI,QAAQ,EAAE;QACZ,GAAG,EAAE,GAAG,CAAC;QACT,MAAM,EAAE,OAAO,CAAC;QAChB,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,YAAY,CAAC;QACtD,uBAAuB,EAAE,CACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,KACX,eAAe,CAAC;QACrB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,eAAe,GAAG,WAAW,KAAK,MAAM,CAAC;QACvE,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;QAC5C,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,gBAAgB,CAAC;QACnD,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,gBAAgB,CAAC;QAI1E,gCAAgC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,gBAAgB,CAAC;QACxE,iBAAiB,EAAE,CACjB,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,sBAAsB,KACjC,WAAW,CAAC;QACjB,kBAAkB,EAAE,MAAM,MAAM,CAAC;KAClC,CAAC;IAEF,UAAU,SAAS;QACjB,yBAAyB,CACvB,UAAU,EAAE,gCAAgC,GAC3C,sBAAsB,CAAC;QAC1B,iBAAiB,CAAC,UAAU,EAAE,wBAAwB,GAAG,cAAc,CAAC;KACzE;IAID,UAAU,mBAAmB;QAC3B,WAAW,CAAC,EAAE,wBAAwB,CAAC;KACxC;IAMD,UAAU,4BAA4B;QACpC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;QAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB;IASD,UAAU,kBAAkB;QAC1B,OAAO,IAAI,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,gCAAgC,EAChC,YAAY,EACZ,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,SAAS,CAAC;AAEjB,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,gCAAgC,EAChC,oCAAoC,EACpC,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,SAAS,CAAC;AAEjB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,SAAS;QACjB,GAAG,EAAE,GAAG,CAAC;KACV;IAED,IAAI,SAAS,EAAE,SAAS,CAAC;IAEzB,IAAI,QAAQ,EAAE;QACZ,GAAG,EAAE,GAAG,CAAC;QACT,MAAM,EAAE,OAAO,CAAC;QAChB,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,YAAY,CAAC;QACtD,uBAAuB,EAAE,CACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,KACX,eAAe,CAAC;QACrB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,eAAe,GAAG,WAAW,KAAK,MAAM,CAAC;QACvE,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;QAC5C,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,gBAAgB,CAAC;QACnD,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,gBAAgB,CAAC;QAI1E,gCAAgC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,gBAAgB,CAAC;QACxE,iBAAiB,EAAE,CACjB,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,sBAAsB,KACjC,WAAW,CAAC;QACjB,kBAAkB,EAAE,MAAM,MAAM,CAAC;KAClC,CAAC;IAEF,UAAU,SAAS;QACjB,yBAAyB,CACvB,UAAU,EAAE,gCAAgC,GAC3C,sBAAsB,CAAC;QAC1B,iBAAiB,CAAC,UAAU,EAAE,wBAAwB,GAAG,cAAc,CAAC;KACzE;IAID,UAAU,mBAAmB;QAC3B,WAAW,CAAC,EAAE,wBAAwB,CAAC;KACxC;IAMD,UAAU,4BAA4B;QACpC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;QAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB;IASD,UAAU,kBAAkB;QAC1B,OAAO,IAAI,IAAI,CAAC;QAShB,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;KACnC;IAGD,SAAS,iBAAiB,CACxB,KAAK,EAAE,WAAW,GAAG,eAAe,GACnC,OAAO,CAAC,WAAW,CAAC,CAAC;CACzB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-webgpu",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "React Native WebGPU",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"scripts": {
|
|
27
27
|
"test": "NODE_OPTIONS='--experimental-require-module' jest -i",
|
|
28
28
|
"test:ref": "REFERENCE=true NODE_OPTIONS='--experimental-require-module' jest -i",
|
|
29
|
+
"test:node": "NODE_WEBGPU=true NODE_OPTIONS='--experimental-require-module' jest -i",
|
|
29
30
|
"test:plugin": "jest -c plugin/jest.config.js",
|
|
30
31
|
"lint": "eslint . --ext .ts,.tsx --max-warnings 0 --cache --fix",
|
|
31
32
|
"tsc": "tsc --noEmit",
|
|
@@ -107,6 +108,7 @@
|
|
|
107
108
|
"ts-morph": "^22.0.0",
|
|
108
109
|
"tsx": "^4.20.5",
|
|
109
110
|
"typescript": "^5.2.2",
|
|
111
|
+
"webgpu": "0.4.0",
|
|
110
112
|
"wgpu-matrix": "^3.0.2",
|
|
111
113
|
"ws": "^8.18.0",
|
|
112
114
|
"yargs": "^17.7.2"
|
package/src/index.tsx
CHANGED
|
@@ -93,6 +93,15 @@ declare global {
|
|
|
93
93
|
// pool (e.g. a camera/video player) and pile up GPU resources.
|
|
94
94
|
interface GPUExternalTexture {
|
|
95
95
|
destroy(): void;
|
|
96
|
+
// Non-spec extension: a 3x4 row-major matrix (12 numbers) mapping the
|
|
97
|
+
// sampled texel [r, g, b, 1] to gamma-encoded R'G'B'. On the Android
|
|
98
|
+
// opaque-YCbCr camera path, textureSampleBaseClampToEdge returns raw
|
|
99
|
+
// [Y, Cb, Cr] (Dawn hard-codes an RGB_IDENTITY Vulkan conversion); this
|
|
100
|
+
// matrix is derived per-buffer from the driver's suggested YCbCr model and
|
|
101
|
+
// range (BT.601/709/2020, full/narrow). Everywhere else (iOS, RGBA
|
|
102
|
+
// surfaces) it is the identity passthrough, so shaders can apply it
|
|
103
|
+
// unconditionally. Upload it as a uniform and multiply after sampling.
|
|
104
|
+
readonly yuvToRgbMatrix: number[];
|
|
96
105
|
}
|
|
97
106
|
|
|
98
107
|
// Extend createImageBitmap to accept ArrayBuffer/TypedArray (encoded image bytes)
|