react-native-webgpu 0.11.0 → 0.11.2
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 +42 -8
- package/android/cpp/AndroidVideoPlayer.h +307 -0
- package/android/src/main/java/com/webgpu/WebGPUModule.java +10 -0
- package/android/src/main/java/com/webgpu/WebGPUVideoPlayer.java +420 -0
- package/apple/AppleVideoPlayer.mm +157 -47
- package/cpp/rnwgpu/PlatformContext.h +25 -5
- package/cpp/rnwgpu/api/GPUAdapter.cpp +26 -12
- package/cpp/rnwgpu/api/GPUDevice.cpp +2 -1
- package/cpp/rnwgpu/api/GPUDevice.h +6 -0
- package/cpp/rnwgpu/api/GPUExternalTexture.cpp +61 -0
- package/cpp/rnwgpu/api/GPUQueue.cpp +80 -10
- package/cpp/rnwgpu/api/GPUQueue.h +15 -4
- package/cpp/rnwgpu/api/RnFeatures.h +15 -2
- package/cpp/rnwgpu/api/VideoFrameBlit.h +355 -0
- package/cpp/rnwgpu/api/VideoPlayer.h +50 -3
- package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +30 -3
- package/lib/commonjs/importDevice.js +2 -2
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/main/index.js +12 -0
- package/lib/commonjs/main/index.js.map +1 -1
- package/lib/commonjs/main/index.web.js +11 -0
- package/lib/commonjs/main/index.web.js.map +1 -1
- package/lib/commonjs/video.js +58 -0
- package/lib/commonjs/video.js.map +1 -0
- package/lib/module/importDevice.js +2 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/main/index.js +1 -0
- package/lib/module/main/index.js.map +1 -1
- package/lib/module/main/index.web.js +1 -0
- package/lib/module/main/index.web.js.map +1 -1
- package/lib/module/video.js +49 -0
- package/lib/module/video.js.map +1 -0
- package/lib/typescript/lib/commonjs/video.d.ts +30 -0
- package/lib/typescript/lib/commonjs/video.d.ts.map +1 -0
- package/lib/typescript/lib/module/main/index.d.ts +1 -0
- package/lib/typescript/lib/module/main/index.web.d.ts +1 -0
- package/lib/typescript/lib/module/video.d.ts +4 -0
- package/lib/typescript/lib/module/video.d.ts.map +1 -0
- package/lib/typescript/src/importDevice.d.ts +2 -2
- package/lib/typescript/src/index.d.ts +5 -3
- package/lib/typescript/src/index.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 -0
- package/lib/typescript/src/main/index.web.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +19 -0
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/video.d.ts +41 -0
- package/lib/typescript/src/video.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/importDevice.ts +2 -2
- package/src/index.tsx +28 -3
- package/src/main/index.tsx +1 -0
- package/src/main/index.web.tsx +1 -0
- package/src/types.ts +60 -7
- package/src/video.ts +69 -0
|
@@ -59,7 +59,8 @@ struct VideoFrameHandle {
|
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
// Platform-implemented video source that hands out fresh IOSurface /
|
|
62
|
-
// AHardwareBuffer-backed frames as a video plays
|
|
62
|
+
// AHardwareBuffer-backed frames as a video plays, with the playback controls
|
|
63
|
+
// of an HTMLMediaElement (times in seconds).
|
|
63
64
|
class IVideoPlayer {
|
|
64
65
|
public:
|
|
65
66
|
virtual ~IVideoPlayer() = default;
|
|
@@ -71,6 +72,26 @@ public:
|
|
|
71
72
|
|
|
72
73
|
virtual void play() = 0;
|
|
73
74
|
virtual void pause() = 0;
|
|
75
|
+
virtual bool paused() = 0;
|
|
76
|
+
|
|
77
|
+
// Playback position and length, in seconds. The duration is 0 until the
|
|
78
|
+
// metadata of the media has loaded.
|
|
79
|
+
virtual double currentTime() = 0;
|
|
80
|
+
virtual void seek(double seconds) = 0;
|
|
81
|
+
virtual double duration() = 0;
|
|
82
|
+
|
|
83
|
+
virtual double volume() = 0;
|
|
84
|
+
virtual void setVolume(double volume) = 0;
|
|
85
|
+
virtual bool loop() = 0;
|
|
86
|
+
virtual void setLoop(bool loop) = 0;
|
|
87
|
+
|
|
88
|
+
// The geometry of the frames, 0 until the metadata has loaded: their coded
|
|
89
|
+
// size, the clockwise rotation (0, 90, 180 or 270) to apply when displaying
|
|
90
|
+
// them, and the nominal frame rate of the video track.
|
|
91
|
+
virtual uint32_t videoWidth() = 0;
|
|
92
|
+
virtual uint32_t videoHeight() = 0;
|
|
93
|
+
virtual int rotation() = 0;
|
|
94
|
+
virtual double frameRate() = 0;
|
|
74
95
|
};
|
|
75
96
|
|
|
76
97
|
// A request to rasterize a native React Native view (looked up by its React
|
|
@@ -117,10 +138,9 @@ public:
|
|
|
117
138
|
// pixel, `format` is rgba8unorm or bgra8unorm depending on what the platform
|
|
118
139
|
// rasterizer produces natively, and `premultiplied` reports its alpha
|
|
119
140
|
// representation.
|
|
120
|
-
virtual void
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
std::function<void(std::string)> onError) = 0;
|
|
141
|
+
virtual void snapshotView(const ViewSnapshotRequest &request,
|
|
142
|
+
std::function<void(ImageData)> onSuccess,
|
|
143
|
+
std::function<void(std::string)> onError) = 0;
|
|
124
144
|
|
|
125
145
|
virtual wgpu::Surface makeSurface(wgpu::Instance instance, void *surface,
|
|
126
146
|
int width, int height) = 0;
|
|
@@ -25,18 +25,24 @@ namespace rnwgpu {
|
|
|
25
25
|
async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
26
26
|
jsi::Runtime &runtime,
|
|
27
27
|
std::optional<std::shared_ptr<GPUDeviceDescriptor>> descriptor) {
|
|
28
|
-
// Enable the react-native-wgpu "native-texture" umbrella by default,
|
|
29
|
-
// the web where importExternalTexture is core and needs no feature
|
|
30
|
-
// We append the umbrella's backing Dawn features to requiredFeatures
|
|
31
|
-
// capability is on without the caller listing it. Two rules keep this
|
|
28
|
+
// Enable the react-native-wgpu "native-texture" umbrella by default,
|
|
29
|
+
// mirroring the web where importExternalTexture is core and needs no feature
|
|
30
|
+
// request. We append the umbrella's backing Dawn features to requiredFeatures
|
|
31
|
+
// so the capability is on without the caller listing it. Two rules keep this
|
|
32
|
+
// safe:
|
|
32
33
|
// - All-or-nothing: only inject when the adapter supports *every* backing
|
|
33
34
|
// feature (same semantics as maybeSynthesizeRnNativeTextureFeature). On a
|
|
34
|
-
// web/fallback adapter the backing set is empty or unsupported, so this
|
|
35
|
-
// a no-op and device creation is unaffected.
|
|
35
|
+
// web/fallback adapter the backing set is empty or unsupported, so this
|
|
36
|
+
// is a no-op and device creation is unaffected.
|
|
36
37
|
// - Requesting a feature the adapter doesn't support makes RequestDevice
|
|
37
38
|
// fail, hence the support check below.
|
|
38
39
|
// Callers can still pass "rnwebgpu/native-texture" explicitly; the dedupe
|
|
39
40
|
// keeps that idempotent.
|
|
41
|
+
// The optional features (rnNativeTextureOptionalFeatures) ride along one by
|
|
42
|
+
// one, each only when the adapter supports it: on Android the YUV frames of
|
|
43
|
+
// the decoder and of the camera cannot be imported without
|
|
44
|
+
// OpaqueYCbCrAndroidForExternalTexture, while RGBA buffers need nothing
|
|
45
|
+
// beyond the backing set.
|
|
40
46
|
{
|
|
41
47
|
auto backing = rnNativeTextureBackingFeatures();
|
|
42
48
|
if (!backing.empty()) {
|
|
@@ -44,9 +50,10 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
44
50
|
_instance.GetFeatures(&supported);
|
|
45
51
|
std::unordered_set<wgpu::FeatureName> supportedSet(
|
|
46
52
|
supported.features, supported.features + supported.featureCount);
|
|
47
|
-
bool allSupported =
|
|
48
|
-
backing.begin(), backing.end(),
|
|
49
|
-
|
|
53
|
+
bool allSupported =
|
|
54
|
+
std::all_of(backing.begin(), backing.end(), [&](wgpu::FeatureName f) {
|
|
55
|
+
return supportedSet.count(f) > 0;
|
|
56
|
+
});
|
|
50
57
|
if (allSupported) {
|
|
51
58
|
if (!descriptor.has_value()) {
|
|
52
59
|
descriptor = std::make_shared<GPUDeviceDescriptor>();
|
|
@@ -62,6 +69,13 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
62
69
|
features.push_back(f);
|
|
63
70
|
}
|
|
64
71
|
}
|
|
72
|
+
for (auto f : rnNativeTextureOptionalFeatures()) {
|
|
73
|
+
if (supportedSet.count(f) > 0 &&
|
|
74
|
+
std::find(features.begin(), features.end(), f) ==
|
|
75
|
+
features.end()) {
|
|
76
|
+
features.push_back(f);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
65
79
|
}
|
|
66
80
|
}
|
|
67
81
|
}
|
|
@@ -101,8 +115,7 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
101
115
|
if (std::find(features.begin(), features.end(),
|
|
102
116
|
wgpu::FeatureName::ImplicitDeviceSynchronization) ==
|
|
103
117
|
features.end()) {
|
|
104
|
-
features.push_back(
|
|
105
|
-
wgpu::FeatureName::ImplicitDeviceSynchronization);
|
|
118
|
+
features.push_back(wgpu::FeatureName::ImplicitDeviceSynchronization);
|
|
106
119
|
}
|
|
107
120
|
}
|
|
108
121
|
}
|
|
@@ -211,7 +224,8 @@ async::AsyncTaskHandle GPUAdapter::requestDevice(
|
|
|
211
224
|
}
|
|
212
225
|
}
|
|
213
226
|
}
|
|
214
|
-
// TODO: in the latest version of Dawn, this won't be needed
|
|
227
|
+
// TODO: in the latest version of Dawn, this won't be needed
|
|
228
|
+
// (https://issues.chromium.org/issues/42241591)
|
|
215
229
|
#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
|
|
216
230
|
// The iOS Simulator only advertises MTLFeatureSet_iOS_GPUFamily2, so
|
|
217
231
|
// Dawn defaults disable_base_instance/disable_base_vertex on and then
|
|
@@ -133,7 +133,8 @@ std::shared_ptr<GPUSupportedLimits> GPUDevice::getLimits() {
|
|
|
133
133
|
|
|
134
134
|
std::shared_ptr<GPUQueue> GPUDevice::getQueue() {
|
|
135
135
|
auto result = _instance.GetQueue();
|
|
136
|
-
return std::make_shared<GPUQueue>(result, _async,
|
|
136
|
+
return std::make_shared<GPUQueue>(_instance, result, _async, _videoFrameBlit,
|
|
137
|
+
_label);
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
std::shared_ptr<GPUCommandEncoder> GPUDevice::createCommandEncoder(
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
#include "GPUTexture.h"
|
|
55
55
|
#include "GPUTextureDescriptor.h"
|
|
56
56
|
#include "GPUUncapturedErrorEvent.h"
|
|
57
|
+
#include "VideoFrameBlit.h"
|
|
57
58
|
|
|
58
59
|
namespace rnwgpu {
|
|
59
60
|
|
|
@@ -285,6 +286,11 @@ private:
|
|
|
285
286
|
wgpu::Device _instance;
|
|
286
287
|
std::shared_ptr<async::RuntimeContext> _async;
|
|
287
288
|
std::string _label;
|
|
289
|
+
// Renders native video frames into textures for
|
|
290
|
+
// GPUQueue.copyExternalImageToTexture; shared by every GPUQueue wrapper of
|
|
291
|
+
// this device so the pipelines are created once.
|
|
292
|
+
std::shared_ptr<VideoFrameBlit> _videoFrameBlit =
|
|
293
|
+
std::make_shared<VideoFrameBlit>();
|
|
288
294
|
// Guards the device-lost state below. getLost() runs on a JS thread, but
|
|
289
295
|
// Dawn's AllowSpontaneous device-lost callback (and device destruction) can
|
|
290
296
|
// fire notifyDeviceLost() from other threads, so the mutex keeps these
|
|
@@ -8,8 +8,47 @@
|
|
|
8
8
|
|
|
9
9
|
#include "GPUExternalTextureDescriptor.h"
|
|
10
10
|
|
|
11
|
+
#if defined(__ANDROID__)
|
|
12
|
+
#include <android/hardware_buffer.h>
|
|
13
|
+
#endif
|
|
14
|
+
|
|
11
15
|
namespace rnwgpu {
|
|
12
16
|
|
|
17
|
+
#if defined(__ANDROID__)
|
|
18
|
+
// Whether Dawn imports an AHardwareBuffer of this format as an
|
|
19
|
+
// OpaqueYCbCrAndroid texture. Mirrors FormatFromAHardwareBufferFormat
|
|
20
|
+
// (dawn/native/AHBFunctions.cpp): the color and depth formats with a WebGPU
|
|
21
|
+
// equivalent import as that format; the YUV formats and the formats outside
|
|
22
|
+
// the public enum, which drivers use for the camera and the video decoder,
|
|
23
|
+
// import as OpaqueYCbCrAndroid.
|
|
24
|
+
static bool isOpaqueYCbCrFormat(uint32_t format) {
|
|
25
|
+
switch (format) {
|
|
26
|
+
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
|
|
27
|
+
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
|
|
28
|
+
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
|
|
29
|
+
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
|
|
30
|
+
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
|
|
31
|
+
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
|
|
32
|
+
case AHARDWAREBUFFER_FORMAT_BLOB:
|
|
33
|
+
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
|
|
34
|
+
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
|
|
35
|
+
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
|
|
36
|
+
case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
|
|
37
|
+
case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
|
|
38
|
+
case AHARDWAREBUFFER_FORMAT_S8_UINT:
|
|
39
|
+
// Single-channel formats of the API 33 and 34 headers, by value so that
|
|
40
|
+
// older NDKs compile.
|
|
41
|
+
case 0x38: // AHARDWAREBUFFER_FORMAT_R8_UNORM
|
|
42
|
+
case 0x39: // AHARDWAREBUFFER_FORMAT_R16_UINT
|
|
43
|
+
case 0x3a: // AHARDWAREBUFFER_FORMAT_R16G16_UINT
|
|
44
|
+
case 0x3b: // AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM
|
|
45
|
+
return false;
|
|
46
|
+
default:
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
#endif
|
|
51
|
+
|
|
13
52
|
// Identity gamut (BT.709 -> sRGB, same primaries) as a 3x3 column-major matrix.
|
|
14
53
|
static const float kIdentityGamutMatrix[9] = {
|
|
15
54
|
1.0f, 0.0f, 0.0f, //
|
|
@@ -254,6 +293,28 @@ std::shared_ptr<GPUExternalTexture> GPUExternalTexture::Create(
|
|
|
254
293
|
// sampled texel is already RGB.
|
|
255
294
|
kYuvPassthroughMatrix);
|
|
256
295
|
#elif defined(__ANDROID__)
|
|
296
|
+
// 0. A YUV frame imports as an OpaqueYCbCrAndroid texture, which Dawn only
|
|
297
|
+
// accepts on a device with OpaqueYCbCrAndroidForExternalTexture.
|
|
298
|
+
// requestDevice() enables the feature whenever the adapter supports it;
|
|
299
|
+
// a device created by another library (importDevice) has to request it
|
|
300
|
+
// itself. Fail with the cause here: Dawn's own report is a bare
|
|
301
|
+
// "Unsupported texture format TextureFormat::OpaqueYCbCrAndroid" device
|
|
302
|
+
// error, followed by the failure of every call made with the result.
|
|
303
|
+
if (!device.HasFeature(
|
|
304
|
+
wgpu::FeatureName::OpaqueYCbCrAndroidForExternalTexture)) {
|
|
305
|
+
AHardwareBuffer_Desc ahbDesc{};
|
|
306
|
+
AHardwareBuffer_describe(static_cast<AHardwareBuffer *>(frame.handle),
|
|
307
|
+
&ahbDesc);
|
|
308
|
+
if (isOpaqueYCbCrFormat(ahbDesc.format)) {
|
|
309
|
+
throw std::runtime_error(
|
|
310
|
+
"GPUExternalTexture::Create(): a YUV frame can only be imported on "
|
|
311
|
+
"a device with the 'opaque-ycbcr-android-for-external-texture' "
|
|
312
|
+
"feature. requestDevice() enables it whenever the adapter supports "
|
|
313
|
+
"it; a device imported from another library has to request it "
|
|
314
|
+
"itself.");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
257
318
|
// 1. Import the AHardwareBuffer as SharedTextureMemory. For YUV AHBs this
|
|
258
319
|
// yields a Dawn texture in the implementation-defined OpaqueYCbCrAndroid
|
|
259
320
|
// format; for RGBA AHBs, a regular single-plane texture.
|
|
@@ -109,6 +109,68 @@ async::AsyncTaskHandle GPUQueue::onSubmittedWorkDone(jsi::Runtime &runtime) {
|
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
void GPUQueue::copyVideoFrameToTexture(
|
|
113
|
+
const GPUImageCopyExternalImage &source,
|
|
114
|
+
const GPUImageCopyTextureTagged &destination, const wgpu::Extent3D &size) {
|
|
115
|
+
if (!destination.texture) {
|
|
116
|
+
throw std::runtime_error(
|
|
117
|
+
"copyExternalImageToTexture: destination.texture is required");
|
|
118
|
+
}
|
|
119
|
+
if (destination.aspect.value_or(wgpu::TextureAspect::All) !=
|
|
120
|
+
wgpu::TextureAspect::All) {
|
|
121
|
+
throw std::runtime_error(
|
|
122
|
+
"copyExternalImageToTexture: a native frame can only be copied into "
|
|
123
|
+
"the color aspect");
|
|
124
|
+
}
|
|
125
|
+
if (size.depthOrArrayLayers > 1) {
|
|
126
|
+
throw std::runtime_error(
|
|
127
|
+
"copyExternalImageToTexture: a native frame is a single 2D image");
|
|
128
|
+
}
|
|
129
|
+
constexpr double kMaxCoordinate =
|
|
130
|
+
static_cast<double>(std::numeric_limits<uint32_t>::max());
|
|
131
|
+
auto coordinate = [&](double value, const char *name) {
|
|
132
|
+
if (!(value >= 0) || value > kMaxCoordinate) {
|
|
133
|
+
throw std::runtime_error(std::string("copyExternalImageToTexture: ") +
|
|
134
|
+
name +
|
|
135
|
+
" must be a non-negative integer coordinate");
|
|
136
|
+
}
|
|
137
|
+
return static_cast<uint32_t>(value);
|
|
138
|
+
};
|
|
139
|
+
const double rotation = source.rotation.value_or(0);
|
|
140
|
+
if (rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270) {
|
|
141
|
+
throw std::runtime_error(
|
|
142
|
+
"copyExternalImageToTexture: rotation must be 0, 90, 180 or 270");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
VideoFrameBlit::Request request;
|
|
146
|
+
request.frame = source.videoFrame;
|
|
147
|
+
if (const auto origin = source.origin.value_or(nullptr)) {
|
|
148
|
+
request.originX = coordinate(origin->x, "origin.x");
|
|
149
|
+
request.originY = coordinate(origin->y, "origin.y");
|
|
150
|
+
}
|
|
151
|
+
request.width = size.width;
|
|
152
|
+
request.height = size.height;
|
|
153
|
+
request.flipY = source.flipY.value_or(false);
|
|
154
|
+
request.rotation = rotation;
|
|
155
|
+
request.mirrored = source.mirrored.value_or(false);
|
|
156
|
+
request.texture = destination.texture->get();
|
|
157
|
+
request.mipLevel = coordinate(destination.mipLevel.value_or(0), "mipLevel");
|
|
158
|
+
wgpu::Origin3D dstOrigin{};
|
|
159
|
+
Convertor conv;
|
|
160
|
+
if (!conv(dstOrigin, destination.origin)) {
|
|
161
|
+
throw std::runtime_error(
|
|
162
|
+
"copyExternalImageToTexture: invalid destination origin");
|
|
163
|
+
}
|
|
164
|
+
if (dstOrigin.z != 0) {
|
|
165
|
+
throw std::runtime_error(
|
|
166
|
+
"copyExternalImageToTexture: a native frame can only be copied into "
|
|
167
|
+
"the first layer of the texture");
|
|
168
|
+
}
|
|
169
|
+
request.dstX = dstOrigin.x;
|
|
170
|
+
request.dstY = dstOrigin.y;
|
|
171
|
+
_videoFrameBlit->copy(_device, _instance, request);
|
|
172
|
+
}
|
|
173
|
+
|
|
112
174
|
void GPUQueue::copyExternalImageToTexture(
|
|
113
175
|
std::shared_ptr<GPUImageCopyExternalImage> source,
|
|
114
176
|
std::shared_ptr<GPUImageCopyTextureTagged> destination,
|
|
@@ -117,6 +179,17 @@ void GPUQueue::copyExternalImageToTexture(
|
|
|
117
179
|
wgpu::TexelCopyBufferLayout layout{};
|
|
118
180
|
wgpu::Extent3D sz{};
|
|
119
181
|
Convertor conv;
|
|
182
|
+
if (source->videoFrame) {
|
|
183
|
+
if (!conv(sz, size)) {
|
|
184
|
+
throw std::runtime_error("copyExternalImageToTexture: invalid copy size");
|
|
185
|
+
}
|
|
186
|
+
copyVideoFrameToTexture(*source, *destination, sz);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (!source->source) {
|
|
190
|
+
throw std::runtime_error("copyExternalImageToTexture: the source must be "
|
|
191
|
+
"an ImageBitmap or a NativeVideoFrame");
|
|
192
|
+
}
|
|
120
193
|
uint32_t bytesPerPixel =
|
|
121
194
|
source->source->getSize() /
|
|
122
195
|
(source->source->getWidth() * source->source->getHeight());
|
|
@@ -145,10 +218,8 @@ void GPUQueue::copyExternalImageToTexture(
|
|
|
145
218
|
throw std::runtime_error(
|
|
146
219
|
"The source origin must be a non-negative integer coordinate.");
|
|
147
220
|
}
|
|
148
|
-
const size_t sourceOriginX =
|
|
149
|
-
|
|
150
|
-
const size_t sourceOriginY =
|
|
151
|
-
origin ? static_cast<size_t>(origin->y) : 0;
|
|
221
|
+
const size_t sourceOriginX = origin ? static_cast<size_t>(origin->x) : 0;
|
|
222
|
+
const size_t sourceOriginY = origin ? static_cast<size_t>(origin->y) : 0;
|
|
152
223
|
if (sourceOriginX > source->source->getWidth() ||
|
|
153
224
|
sz.width > source->source->getWidth() - sourceOriginX ||
|
|
154
225
|
sourceOriginY > source->source->getHeight() ||
|
|
@@ -220,8 +291,7 @@ async::AsyncTaskHandle GPUQueue::drawElementImageToTexture(
|
|
|
220
291
|
Convertor conv;
|
|
221
292
|
if (!conv(dst.aspect, info->aspect) || !conv(dst.mipLevel, info->mipLevel) ||
|
|
222
293
|
!conv(dst.origin, info->origin) || !conv(dst.texture, info->texture)) {
|
|
223
|
-
throw std::runtime_error(
|
|
224
|
-
"drawElementImageToTexture: invalid destination");
|
|
294
|
+
throw std::runtime_error("drawElementImageToTexture: invalid destination");
|
|
225
295
|
}
|
|
226
296
|
const wgpu::Texture texture = info->texture->get();
|
|
227
297
|
bool destinationIsBgra = false;
|
|
@@ -335,10 +405,10 @@ async::AsyncTaskHandle GPUQueue::drawElementImageToTexture(
|
|
|
335
405
|
"pixels (is it mounted with a non-zero size?)");
|
|
336
406
|
return;
|
|
337
407
|
}
|
|
338
|
-
if (image.width >
|
|
339
|
-
|
|
340
|
-
image.height >
|
|
341
|
-
|
|
408
|
+
if (image.width >
|
|
409
|
+
mipWidth - std::min<uint32_t>(dst.origin.x, mipWidth) ||
|
|
410
|
+
image.height >
|
|
411
|
+
mipHeight - std::min<uint32_t>(dst.origin.y, mipHeight)) {
|
|
342
412
|
reject("drawElementImageToTexture: the view's natural pixel "
|
|
343
413
|
"size (" +
|
|
344
414
|
std::to_string(image.width) + "x" +
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
#include "GPUDrawElementImageSource.h"
|
|
21
21
|
#include "GPUImageCopyExternalImage.h"
|
|
22
22
|
#include "GPUImageCopyTextureTagged.h"
|
|
23
|
+
#include "VideoFrameBlit.h"
|
|
23
24
|
|
|
24
25
|
namespace rnwgpu {
|
|
25
26
|
|
|
@@ -29,10 +30,12 @@ class GPUQueue : public NativeObject<GPUQueue> {
|
|
|
29
30
|
public:
|
|
30
31
|
static constexpr const char *CLASS_NAME = "GPUQueue";
|
|
31
32
|
|
|
32
|
-
explicit GPUQueue(wgpu::Queue instance,
|
|
33
|
+
explicit GPUQueue(wgpu::Device device, wgpu::Queue instance,
|
|
33
34
|
std::shared_ptr<async::RuntimeContext> async,
|
|
35
|
+
std::shared_ptr<VideoFrameBlit> videoFrameBlit,
|
|
34
36
|
std::string label)
|
|
35
|
-
: NativeObject(CLASS_NAME),
|
|
37
|
+
: NativeObject(CLASS_NAME), _device(device), _instance(instance),
|
|
38
|
+
_async(async), _videoFrameBlit(std::move(videoFrameBlit)),
|
|
36
39
|
_label(label) {}
|
|
37
40
|
|
|
38
41
|
public:
|
|
@@ -48,6 +51,9 @@ public:
|
|
|
48
51
|
std::shared_ptr<ArrayBuffer> data,
|
|
49
52
|
std::shared_ptr<GPUImageDataLayout> dataLayout,
|
|
50
53
|
std::shared_ptr<GPUExtent3D> size);
|
|
54
|
+
// The source is an ImageBitmap (uploaded from the CPU) or, as a React
|
|
55
|
+
// Native extension, a NativeVideoFrame rendered into the destination through
|
|
56
|
+
// an external texture (see VideoFrameBlit).
|
|
51
57
|
void copyExternalImageToTexture(
|
|
52
58
|
std::shared_ptr<GPUImageCopyExternalImage> source,
|
|
53
59
|
std::shared_ptr<GPUImageCopyTextureTagged> destination,
|
|
@@ -61,8 +67,7 @@ public:
|
|
|
61
67
|
// runtime's thread right before the promise resolves, so work submitted
|
|
62
68
|
// after `await` observes the new contents.
|
|
63
69
|
async::AsyncTaskHandle drawElementImageToTexture(
|
|
64
|
-
jsi::Runtime &runtime,
|
|
65
|
-
std::shared_ptr<GPUDrawElementImageSource> source,
|
|
70
|
+
jsi::Runtime &runtime, std::shared_ptr<GPUDrawElementImageSource> source,
|
|
66
71
|
std::shared_ptr<GPUDrawElementImageDestination> destination);
|
|
67
72
|
|
|
68
73
|
std::string getLabel() { return _label; }
|
|
@@ -89,8 +94,14 @@ public:
|
|
|
89
94
|
inline const wgpu::Queue get() { return _instance; }
|
|
90
95
|
|
|
91
96
|
private:
|
|
97
|
+
void copyVideoFrameToTexture(const GPUImageCopyExternalImage &source,
|
|
98
|
+
const GPUImageCopyTextureTagged &destination,
|
|
99
|
+
const wgpu::Extent3D &size);
|
|
100
|
+
|
|
101
|
+
wgpu::Device _device;
|
|
92
102
|
wgpu::Queue _instance;
|
|
93
103
|
std::shared_ptr<async::RuntimeContext> _async;
|
|
104
|
+
std::shared_ptr<VideoFrameBlit> _videoFrameBlit;
|
|
94
105
|
std::string _label;
|
|
95
106
|
};
|
|
96
107
|
|
|
@@ -31,11 +31,24 @@ inline std::vector<wgpu::FeatureName> rnNativeTextureBackingFeatures() {
|
|
|
31
31
|
#endif
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Dawn features that complete the umbrella on the current platform. They are
|
|
35
|
+
// requested by default when the adapter supports them, but they are not part
|
|
36
|
+
// of the all-or-nothing backing set: on Android, Dawn imports the YUV buffers
|
|
37
|
+
// of the video decoder and of the camera as OpaqueYCbCrAndroid textures, a
|
|
38
|
+
// format it only accepts, and only samples as an external texture, with
|
|
39
|
+
// OpaqueYCbCrAndroidForExternalTexture; RGBA buffers import without it.
|
|
40
|
+
inline std::vector<wgpu::FeatureName> rnNativeTextureOptionalFeatures() {
|
|
41
|
+
#if defined(__ANDROID__)
|
|
42
|
+
return {wgpu::FeatureName::OpaqueYCbCrAndroidForExternalTexture};
|
|
43
|
+
#else
|
|
44
|
+
return {};
|
|
45
|
+
#endif
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
// If every Dawn feature backing the umbrella is in `enabled`, add the
|
|
35
49
|
// umbrella name to `out`. Used by adapter.features / device.features so JS
|
|
36
50
|
// callers can see (and call .has on) the same name they pass in.
|
|
37
|
-
inline void
|
|
38
|
-
maybeSynthesizeRnNativeTextureFeature(
|
|
51
|
+
inline void maybeSynthesizeRnNativeTextureFeature(
|
|
39
52
|
const std::unordered_set<wgpu::FeatureName> &enabled,
|
|
40
53
|
std::unordered_set<std::string> &out) {
|
|
41
54
|
auto backing = rnNativeTextureBackingFeatures();
|