react-native-wgpu 0.5.10 → 0.5.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -0
- package/android/CMakeLists.txt +2 -0
- package/android/cpp/AndroidPlatformContext.h +127 -5
- package/apple/ApplePlatformContext.h +17 -4
- package/apple/ApplePlatformContext.mm +161 -16
- package/apple/AppleVideoPlayer.h +31 -0
- package/apple/AppleVideoPlayer.mm +314 -0
- package/apple/WebGPUModule.h +2 -1
- package/apple/WebGPUModule.mm +4 -2
- package/cpp/rnwgpu/ArrayBuffer.h +51 -7
- package/cpp/rnwgpu/PlatformContext.h +91 -8
- package/cpp/rnwgpu/RNWebGPUManager.cpp +12 -0
- package/cpp/rnwgpu/api/Convertors.h +33 -11
- package/cpp/rnwgpu/api/GPU.cpp +27 -0
- package/cpp/rnwgpu/api/GPUAdapter.cpp +109 -33
- package/cpp/rnwgpu/api/GPUDevice.cpp +58 -5
- package/cpp/rnwgpu/api/GPUDevice.h +6 -0
- package/cpp/rnwgpu/api/GPUExternalTexture.cpp +335 -0
- package/cpp/rnwgpu/api/GPUExternalTexture.h +47 -2
- package/cpp/rnwgpu/api/GPUFeatures.h +7 -13
- package/cpp/rnwgpu/api/GPUShaderModule.cpp +2 -3
- package/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp +80 -0
- package/cpp/rnwgpu/api/GPUSharedTextureMemory.h +71 -0
- package/cpp/rnwgpu/api/ImageBitmap.h +8 -0
- package/cpp/rnwgpu/api/RNWebGPU.h +70 -32
- package/cpp/rnwgpu/api/RnFeatures.h +53 -0
- package/cpp/rnwgpu/api/VideoFrame.h +76 -0
- package/cpp/rnwgpu/api/VideoPlayer.h +69 -0
- package/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h +4 -1
- package/cpp/rnwgpu/api/descriptors/GPUDawnTogglesDescriptor.h +57 -0
- package/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h +18 -3
- package/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +35 -33
- package/cpp/rnwgpu/api/descriptors/GPUSharedTextureMemoryDescriptor.h +62 -0
- package/cpp/rnwgpu/api/descriptors/Unions.h +10 -15
- package/cpp/webgpu/webgpu.h +312 -188
- package/cpp/webgpu/webgpu_cpp.h +1611 -1720
- package/cpp/webgpu/webgpu_cpp_print.h +190 -61
- package/lib/commonjs/Canvas.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/Canvas.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/Canvas.d.ts +0 -10
- package/lib/typescript/src/Canvas.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +20 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +32 -1
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/libs/android/arm64-v8a/libwebgpu_dawn.so +0 -0
- package/libs/android/armeabi-v7a/libwebgpu_dawn.so +0 -0
- package/libs/android/x86/libwebgpu_dawn.so +0 -0
- package/libs/android/x86_64/libwebgpu_dawn.so +0 -0
- package/libs/apple/libwebgpu_dawn.xcframework/Info.plist +8 -8
- package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/libwebgpu_dawn.a +0 -0
- package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/libwebgpu_dawn.a +0 -0
- package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/libwebgpu_dawn.a +0 -0
- package/package.json +5 -5
- package/src/Canvas.tsx +0 -15
- package/src/index.tsx +62 -2
- package/src/types.ts +83 -1
- package/libs/dawn.json +0 -4693
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
#include <memory>
|
|
3
4
|
#include <string>
|
|
5
|
+
#include <utility>
|
|
4
6
|
|
|
5
7
|
#include "Unions.h"
|
|
6
8
|
|
|
7
9
|
#include "NativeObject.h"
|
|
10
|
+
#include "VideoFrame.h"
|
|
8
11
|
|
|
9
12
|
#include "webgpu/webgpu_cpp.h"
|
|
10
13
|
|
|
@@ -12,16 +15,54 @@ namespace rnwgpu {
|
|
|
12
15
|
|
|
13
16
|
namespace jsi = facebook::jsi;
|
|
14
17
|
|
|
18
|
+
struct GPUExternalTextureDescriptor;
|
|
19
|
+
|
|
15
20
|
class GPUExternalTexture : public NativeObject<GPUExternalTexture> {
|
|
16
21
|
public:
|
|
17
22
|
static constexpr const char *CLASS_NAME = "GPUExternalTexture";
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
// Import a VideoFrame (via descriptor.source) as a GPUExternalTexture on
|
|
25
|
+
// `device`: imports the native surface as SharedTextureMemory, begins access,
|
|
26
|
+
// and wraps the resulting wgpu::ExternalTexture together with the resources
|
|
27
|
+
// whose lifetime it owns. The matching EndAccess runs in destroy() / the
|
|
28
|
+
// destructor. Defined in GPUExternalTexture.cpp.
|
|
29
|
+
static std::shared_ptr<GPUExternalTexture>
|
|
30
|
+
Create(wgpu::Device device,
|
|
31
|
+
std::shared_ptr<GPUExternalTextureDescriptor> descriptor);
|
|
32
|
+
|
|
33
|
+
// Construct from an already-built wgpu::ExternalTexture plus the underlying
|
|
34
|
+
// shared-memory resources we need to keep alive. The wrapper takes ownership
|
|
35
|
+
// of the SharedTextureMemory + Texture and calls EndAccess on destruction so
|
|
36
|
+
// the producer (e.g. AVPlayer) can reclaim the IOSurface.
|
|
37
|
+
GPUExternalTexture(wgpu::ExternalTexture instance,
|
|
38
|
+
wgpu::SharedTextureMemory memory, wgpu::Texture texture,
|
|
39
|
+
std::shared_ptr<VideoFrame> source, std::string label)
|
|
40
|
+
: NativeObject(CLASS_NAME), _instance(std::move(instance)),
|
|
41
|
+
_memory(std::move(memory)), _texture(std::move(texture)),
|
|
42
|
+
_source(std::move(source)), _label(std::move(label)) {}
|
|
43
|
+
|
|
44
|
+
~GPUExternalTexture() override { destroy(); }
|
|
21
45
|
|
|
22
46
|
public:
|
|
23
47
|
std::string getBrand() { return CLASS_NAME; }
|
|
24
48
|
|
|
49
|
+
// End the shared-memory access window and release the underlying resources.
|
|
50
|
+
// Idempotent: safe to call more than once, and the destructor calls it as a
|
|
51
|
+
// garbage-collection fallback. Call it right after the queue.submit() that
|
|
52
|
+
// sampled this texture (never before): a GPUExternalTexture's access window
|
|
53
|
+
// is owned by this wrapper's lifetime, not by submit, so without an explicit
|
|
54
|
+
// destroy() the producer's surface (e.g. an AVPlayer IOSurface) stays claimed
|
|
55
|
+
// until GC runs. EndAccess is the designed post-submit call: Dawn keeps the
|
|
56
|
+
// texture alive for in-flight GPU work via the fences it returns.
|
|
57
|
+
void destroy() {
|
|
58
|
+
if (_memory && _texture) {
|
|
59
|
+
wgpu::SharedTextureMemoryEndAccessState state{};
|
|
60
|
+
(void)_memory.EndAccess(_texture, &state);
|
|
61
|
+
}
|
|
62
|
+
_texture = nullptr;
|
|
63
|
+
_memory = nullptr;
|
|
64
|
+
}
|
|
65
|
+
|
|
25
66
|
std::string getLabel() { return _label; }
|
|
26
67
|
void setLabel(const std::string &label) {
|
|
27
68
|
_label = label;
|
|
@@ -33,12 +74,16 @@ public:
|
|
|
33
74
|
installGetterSetter(runtime, prototype, "label",
|
|
34
75
|
&GPUExternalTexture::getLabel,
|
|
35
76
|
&GPUExternalTexture::setLabel);
|
|
77
|
+
installMethod(runtime, prototype, "destroy", &GPUExternalTexture::destroy);
|
|
36
78
|
}
|
|
37
79
|
|
|
38
80
|
inline const wgpu::ExternalTexture get() { return _instance; }
|
|
39
81
|
|
|
40
82
|
private:
|
|
41
83
|
wgpu::ExternalTexture _instance;
|
|
84
|
+
wgpu::SharedTextureMemory _memory;
|
|
85
|
+
wgpu::Texture _texture;
|
|
86
|
+
std::shared_ptr<VideoFrame> _source;
|
|
42
87
|
std::string _label;
|
|
43
88
|
};
|
|
44
89
|
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
#include <string>
|
|
4
4
|
|
|
5
|
-
#include
|
|
5
|
+
#include <cstdio>
|
|
6
6
|
|
|
7
|
-
#include "
|
|
7
|
+
#include "webgpu/webgpu_cpp.h"
|
|
8
8
|
|
|
9
9
|
namespace rnwgpu {
|
|
10
10
|
|
|
@@ -89,9 +89,6 @@ static void convertEnumToJSUnion(wgpu::FeatureName inEnum,
|
|
|
89
89
|
case wgpu::FeatureName::Unorm16TextureFormats:
|
|
90
90
|
*outUnion = "unorm16-texture-formats";
|
|
91
91
|
break;
|
|
92
|
-
case wgpu::FeatureName::Snorm16TextureFormats:
|
|
93
|
-
*outUnion = "snorm16-texture-formats";
|
|
94
|
-
break;
|
|
95
92
|
case wgpu::FeatureName::MultiPlanarFormatExtendedUsages:
|
|
96
93
|
*outUnion = "multi-planar-format-extended-usages";
|
|
97
94
|
break;
|
|
@@ -122,18 +119,12 @@ static void convertEnumToJSUnion(wgpu::FeatureName inEnum,
|
|
|
122
119
|
case wgpu::FeatureName::AdapterPropertiesVk:
|
|
123
120
|
*outUnion = "adapter-properties-vk";
|
|
124
121
|
break;
|
|
125
|
-
case wgpu::FeatureName::R8UnormStorage:
|
|
126
|
-
*outUnion = "r8unorm-storage";
|
|
127
|
-
break;
|
|
128
122
|
case wgpu::FeatureName::DawnFormatCapabilities:
|
|
129
123
|
*outUnion = "format-capabilities";
|
|
130
124
|
break;
|
|
131
125
|
case wgpu::FeatureName::DawnDrmFormatCapabilities:
|
|
132
126
|
*outUnion = "drm-format-capabilities";
|
|
133
127
|
break;
|
|
134
|
-
case wgpu::FeatureName::Norm16TextureFormats:
|
|
135
|
-
*outUnion = "norm16-texture-formats";
|
|
136
|
-
break;
|
|
137
128
|
case wgpu::FeatureName::MultiPlanarFormatNv16:
|
|
138
129
|
*outUnion = "multi-planar-format-nv16";
|
|
139
130
|
break;
|
|
@@ -177,7 +168,7 @@ static void convertEnumToJSUnion(wgpu::FeatureName inEnum,
|
|
|
177
168
|
*outUnion = "shared-fence-vk-semaphore-opaque-fd";
|
|
178
169
|
break;
|
|
179
170
|
case wgpu::FeatureName::SharedFenceSyncFD:
|
|
180
|
-
*outUnion = "shared-fence-
|
|
171
|
+
*outUnion = "shared-fence-sync-fd";
|
|
181
172
|
break;
|
|
182
173
|
case wgpu::FeatureName::SharedFenceVkSemaphoreZirconHandle:
|
|
183
174
|
*outUnion = "shared-fence-vk-semaphore-zircon-handle";
|
|
@@ -197,6 +188,9 @@ static void convertEnumToJSUnion(wgpu::FeatureName inEnum,
|
|
|
197
188
|
case wgpu::FeatureName::YCbCrVulkanSamplers:
|
|
198
189
|
*outUnion = "ycbcr-vulkan-samplers";
|
|
199
190
|
break;
|
|
191
|
+
case wgpu::FeatureName::OpaqueYCbCrAndroidForExternalTexture:
|
|
192
|
+
*outUnion = "opaque-ycbcr-android-for-external-texture";
|
|
193
|
+
break;
|
|
200
194
|
case wgpu::FeatureName::ShaderModuleCompilationOptions:
|
|
201
195
|
*outUnion = "shader-module-compilation-options";
|
|
202
196
|
break;
|
|
@@ -204,7 +198,7 @@ static void convertEnumToJSUnion(wgpu::FeatureName inEnum,
|
|
|
204
198
|
*outUnion = "dawn-load-resolve-texture";
|
|
205
199
|
break;
|
|
206
200
|
default:
|
|
207
|
-
|
|
201
|
+
fprintf(stderr, "Unknown feature name %d\n", static_cast<int>(inEnum));
|
|
208
202
|
*outUnion = "";
|
|
209
203
|
}
|
|
210
204
|
}
|
|
@@ -18,7 +18,7 @@ async::AsyncTaskHandle GPUShaderModule::getCompilationInfo() {
|
|
|
18
18
|
wgpu::CallbackMode::AllowProcessEvents,
|
|
19
19
|
[result, resolve,
|
|
20
20
|
reject](wgpu::CompilationInfoRequestStatus status,
|
|
21
|
-
const wgpu::CompilationInfo *compilationInfo)
|
|
21
|
+
const wgpu::CompilationInfo *compilationInfo) {
|
|
22
22
|
if (status != wgpu::CompilationInfoRequestStatus::Success ||
|
|
23
23
|
compilationInfo == nullptr) {
|
|
24
24
|
reject("Failed to get compilation info");
|
|
@@ -39,8 +39,7 @@ async::AsyncTaskHandle GPUShaderModule::getCompilationInfo() {
|
|
|
39
39
|
result->_messages.push_back(std::move(message));
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
resolve([result
|
|
43
|
-
std::move(result)](jsi::Runtime &runtime) mutable {
|
|
42
|
+
resolve([result](jsi::Runtime &runtime) mutable {
|
|
44
43
|
return JSIConverter<std::shared_ptr<GPUCompilationInfo>>::toJSI(
|
|
45
44
|
runtime, result);
|
|
46
45
|
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#include "GPUSharedTextureMemory.h"
|
|
2
|
+
|
|
3
|
+
#include <memory>
|
|
4
|
+
#include <stdexcept>
|
|
5
|
+
#include <string>
|
|
6
|
+
|
|
7
|
+
#include "Convertors.h"
|
|
8
|
+
|
|
9
|
+
namespace rnwgpu {
|
|
10
|
+
|
|
11
|
+
std::shared_ptr<GPUTexture> GPUSharedTextureMemory::createTexture(
|
|
12
|
+
std::optional<std::shared_ptr<GPUTextureDescriptor>> descriptor) {
|
|
13
|
+
if (!descriptor.has_value() || descriptor.value() == nullptr) {
|
|
14
|
+
auto texture = _instance.CreateTexture();
|
|
15
|
+
return std::make_shared<GPUTexture>(texture, "");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
wgpu::TextureDescriptor desc{};
|
|
19
|
+
Convertor conv;
|
|
20
|
+
if (!conv(desc, descriptor.value())) {
|
|
21
|
+
throw std::runtime_error(
|
|
22
|
+
"GPUSharedTextureMemory::createTexture(): Error with "
|
|
23
|
+
"GPUTextureDescriptor");
|
|
24
|
+
}
|
|
25
|
+
auto texture = _instance.CreateTexture(&desc);
|
|
26
|
+
return std::make_shared<GPUTexture>(texture,
|
|
27
|
+
descriptor.value()->label.value_or(""));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
bool GPUSharedTextureMemory::beginAccess(std::shared_ptr<GPUTexture> texture,
|
|
31
|
+
bool initialized) {
|
|
32
|
+
if (!texture) {
|
|
33
|
+
throw std::runtime_error(
|
|
34
|
+
"GPUSharedTextureMemory::beginAccess(): texture is null");
|
|
35
|
+
}
|
|
36
|
+
wgpu::SharedTextureMemoryBeginAccessDescriptor desc{};
|
|
37
|
+
desc.initialized = initialized;
|
|
38
|
+
desc.concurrentRead = false;
|
|
39
|
+
desc.fenceCount = 0;
|
|
40
|
+
desc.fences = nullptr;
|
|
41
|
+
desc.signaledValues = nullptr;
|
|
42
|
+
|
|
43
|
+
#if defined(__ANDROID__)
|
|
44
|
+
// Dawn's Vulkan backend (AHardwareBuffer) validates that the begin-access
|
|
45
|
+
// descriptor chains a SharedTextureMemoryVkImageLayoutBeginState specifying
|
|
46
|
+
// the VkImageLayout to acquire the image into. UNDEFINED (= 0) on both ends
|
|
47
|
+
// is the canonical "no prior GPU producer" pattern: Dawn performs an
|
|
48
|
+
// external-queue acquire from VK_QUEUE_FAMILY_EXTERNAL which preserves the
|
|
49
|
+
// AHB contents, then transitions to whatever layout the texture's actual
|
|
50
|
+
// usage requires.
|
|
51
|
+
wgpu::SharedTextureMemoryVkImageLayoutBeginState vkLayout{};
|
|
52
|
+
vkLayout.oldLayout = 0;
|
|
53
|
+
vkLayout.newLayout = 0;
|
|
54
|
+
desc.nextInChain = &vkLayout;
|
|
55
|
+
#endif
|
|
56
|
+
|
|
57
|
+
auto status = _instance.BeginAccess(texture->get(), &desc);
|
|
58
|
+
return static_cast<bool>(status);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
bool GPUSharedTextureMemory::endAccess(std::shared_ptr<GPUTexture> texture) {
|
|
62
|
+
if (!texture) {
|
|
63
|
+
throw std::runtime_error(
|
|
64
|
+
"GPUSharedTextureMemory::endAccess(): texture is null");
|
|
65
|
+
}
|
|
66
|
+
wgpu::SharedTextureMemoryEndAccessState state{};
|
|
67
|
+
|
|
68
|
+
#if defined(__ANDROID__)
|
|
69
|
+
// Dawn's Vulkan backend writes the released old/new VkImageLayouts back into
|
|
70
|
+
// a chained SharedTextureMemoryVkImageLayoutEndState; validation requires
|
|
71
|
+
// the chain even when the caller doesn't read the values.
|
|
72
|
+
wgpu::SharedTextureMemoryVkImageLayoutEndState vkLayout{};
|
|
73
|
+
state.nextInChain = &vkLayout;
|
|
74
|
+
#endif
|
|
75
|
+
|
|
76
|
+
auto status = _instance.EndAccess(texture->get(), &state);
|
|
77
|
+
return static_cast<bool>(status);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
} // namespace rnwgpu
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <memory>
|
|
4
|
+
#include <optional>
|
|
5
|
+
#include <string>
|
|
6
|
+
|
|
7
|
+
#include "NativeObject.h"
|
|
8
|
+
|
|
9
|
+
#include "webgpu/webgpu_cpp.h"
|
|
10
|
+
|
|
11
|
+
#include "GPUTexture.h"
|
|
12
|
+
#include "GPUTextureDescriptor.h"
|
|
13
|
+
|
|
14
|
+
namespace rnwgpu {
|
|
15
|
+
|
|
16
|
+
namespace jsi = facebook::jsi;
|
|
17
|
+
|
|
18
|
+
class GPUSharedTextureMemory : public NativeObject<GPUSharedTextureMemory> {
|
|
19
|
+
public:
|
|
20
|
+
static constexpr const char *CLASS_NAME = "GPUSharedTextureMemory";
|
|
21
|
+
|
|
22
|
+
explicit GPUSharedTextureMemory(wgpu::SharedTextureMemory instance,
|
|
23
|
+
std::string label)
|
|
24
|
+
: NativeObject(CLASS_NAME), _instance(std::move(instance)),
|
|
25
|
+
_label(std::move(label)) {}
|
|
26
|
+
|
|
27
|
+
public:
|
|
28
|
+
std::string getBrand() { return CLASS_NAME; }
|
|
29
|
+
|
|
30
|
+
std::shared_ptr<GPUTexture>
|
|
31
|
+
createTexture(std::optional<std::shared_ptr<GPUTextureDescriptor>> descriptor);
|
|
32
|
+
|
|
33
|
+
// Returns true on success. Marks the shared memory as initialized so the
|
|
34
|
+
// texture's content is preserved (or not). Callers that want fence-based
|
|
35
|
+
// synchronization should pass fences via beginAccess descriptor (not yet
|
|
36
|
+
// exposed - we currently take the implicit/no-fence path that matches the
|
|
37
|
+
// most common RN use cases: still images, single-producer video frames).
|
|
38
|
+
bool beginAccess(std::shared_ptr<GPUTexture> texture, bool initialized);
|
|
39
|
+
|
|
40
|
+
// Returns true on success. Drops any fences produced by end-access (we do
|
|
41
|
+
// not yet surface them to JS).
|
|
42
|
+
bool endAccess(std::shared_ptr<GPUTexture> texture);
|
|
43
|
+
|
|
44
|
+
std::string getLabel() { return _label; }
|
|
45
|
+
void setLabel(const std::string &label) {
|
|
46
|
+
_label = label;
|
|
47
|
+
_instance.SetLabel(_label.c_str());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
|
|
51
|
+
installGetter(runtime, prototype, "__brand",
|
|
52
|
+
&GPUSharedTextureMemory::getBrand);
|
|
53
|
+
installMethod(runtime, prototype, "createTexture",
|
|
54
|
+
&GPUSharedTextureMemory::createTexture);
|
|
55
|
+
installMethod(runtime, prototype, "beginAccess",
|
|
56
|
+
&GPUSharedTextureMemory::beginAccess);
|
|
57
|
+
installMethod(runtime, prototype, "endAccess",
|
|
58
|
+
&GPUSharedTextureMemory::endAccess);
|
|
59
|
+
installGetterSetter(runtime, prototype, "label",
|
|
60
|
+
&GPUSharedTextureMemory::getLabel,
|
|
61
|
+
&GPUSharedTextureMemory::setLabel);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
inline const wgpu::SharedTextureMemory get() { return _instance; }
|
|
65
|
+
|
|
66
|
+
private:
|
|
67
|
+
wgpu::SharedTextureMemory _instance;
|
|
68
|
+
std::string _label;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
} // namespace rnwgpu
|
|
@@ -26,9 +26,17 @@ public:
|
|
|
26
26
|
|
|
27
27
|
size_t getSize() { return _imageData.data.size(); }
|
|
28
28
|
|
|
29
|
+
void close() {
|
|
30
|
+
_imageData.data.clear();
|
|
31
|
+
_imageData.data.shrink_to_fit();
|
|
32
|
+
_imageData.width = 0;
|
|
33
|
+
_imageData.height = 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
29
36
|
static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
|
|
30
37
|
installGetter(runtime, prototype, "width", &ImageBitmap::getWidth);
|
|
31
38
|
installGetter(runtime, prototype, "height", &ImageBitmap::getHeight);
|
|
39
|
+
installMethod(runtime, prototype, "close", &ImageBitmap::close);
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
size_t getMemoryPressure() override { return getSize(); }
|
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
#include "NativeObject.h"
|
|
7
7
|
|
|
8
|
+
#include "ArrayBuffer.h"
|
|
8
9
|
#include "Canvas.h"
|
|
9
10
|
#include "GPU.h"
|
|
10
11
|
#include "GPUCanvasContext.h"
|
|
11
12
|
#include "ImageBitmap.h"
|
|
12
13
|
#include "PlatformContext.h"
|
|
14
|
+
#include "VideoFrame.h"
|
|
15
|
+
#include "VideoPlayer.h"
|
|
13
16
|
|
|
14
17
|
#include <ReactCommon/CallInvoker.h>
|
|
15
18
|
|
|
@@ -88,47 +91,41 @@ public:
|
|
|
88
91
|
auto callInvoker = _callInvoker;
|
|
89
92
|
|
|
90
93
|
// Check if the argument is an ArrayBuffer or ArrayBufferView
|
|
91
|
-
// (TypedArray / DataView)
|
|
94
|
+
// (TypedArray / DataView). Only a real buffer source is run through the
|
|
95
|
+
// ArrayBuffer converter, which validates byteOffset/byteLength against the
|
|
96
|
+
// backing buffer and throws on an out-of-bounds (or spoofed) view. Anything
|
|
97
|
+
// else (e.g. a Blob) is left to the fall-through path below, so its errors
|
|
98
|
+
// are not misreported as bounds errors here.
|
|
92
99
|
if (args[0].isObject()) {
|
|
93
100
|
auto obj = args[0].getObject(runtime);
|
|
94
101
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
data = {ab.data(runtime), ab.size(runtime)};
|
|
101
|
-
} else if (obj.hasProperty(runtime, "buffer")) {
|
|
102
|
-
// TypedArray or DataView — respect byteOffset/byteLength
|
|
103
|
-
auto bufferVal = obj.getProperty(runtime, "buffer");
|
|
104
|
-
if (bufferVal.isObject() &&
|
|
105
|
-
bufferVal.getObject(runtime).isArrayBuffer(runtime)) {
|
|
106
|
-
const auto &ab =
|
|
107
|
-
bufferVal.getObject(runtime).getArrayBuffer(runtime);
|
|
108
|
-
auto byteOffset = static_cast<size_t>(
|
|
109
|
-
obj.getProperty(runtime, "byteOffset").asNumber());
|
|
110
|
-
auto byteLength = static_cast<size_t>(
|
|
111
|
-
obj.getProperty(runtime, "byteLength").asNumber());
|
|
112
|
-
data = {ab.data(runtime) + byteOffset, byteLength};
|
|
113
|
-
}
|
|
102
|
+
bool isBufferSource = obj.isArrayBuffer(runtime);
|
|
103
|
+
if (!isBufferSource && obj.hasProperty(runtime, "buffer")) {
|
|
104
|
+
auto bufferProp = obj.getProperty(runtime, "buffer");
|
|
105
|
+
isBufferSource = bufferProp.isObject() &&
|
|
106
|
+
bufferProp.getObject(runtime).isArrayBuffer(runtime);
|
|
114
107
|
}
|
|
115
108
|
|
|
116
|
-
if (
|
|
117
|
-
//
|
|
109
|
+
if (isBufferSource) {
|
|
110
|
+
// Bounds violations propagate out of fromJSI so the call rejects
|
|
111
|
+
// rather than reading out of bounds below.
|
|
112
|
+
auto buffer = JSIConverter<std::shared_ptr<ArrayBuffer>>::fromJSI(
|
|
113
|
+
runtime, args[0], false);
|
|
114
|
+
std::span<const uint8_t> data{buffer->data(), buffer->size()};
|
|
115
|
+
|
|
116
|
+
// Copy bytes on the JS thread: the ArrayBuffer pointer is into
|
|
118
117
|
// JS-owned memory that can be GC'd
|
|
119
118
|
std::vector<uint8_t> dataCopy(data.begin(), data.end());
|
|
120
119
|
|
|
121
120
|
return Promise::createPromise(
|
|
122
121
|
runtime,
|
|
123
|
-
[platformContext, callInvoker,
|
|
124
|
-
dataCopy = std::move(dataCopy)](
|
|
122
|
+
[platformContext, callInvoker, dataCopy = std::move(dataCopy)](
|
|
125
123
|
jsi::Runtime & /*runtime*/,
|
|
126
124
|
std::shared_ptr<Promise> promise) mutable {
|
|
127
125
|
platformContext->createImageBitmapFromDataAsync(
|
|
128
126
|
dataCopy,
|
|
129
127
|
[callInvoker, promise](ImageData imageData) {
|
|
130
|
-
auto imageBitmap =
|
|
131
|
-
std::make_shared<ImageBitmap>(imageData);
|
|
128
|
+
auto imageBitmap = std::make_shared<ImageBitmap>(imageData);
|
|
132
129
|
callInvoker->invokeAsync([promise, imageBitmap]() {
|
|
133
130
|
promise->resolve(
|
|
134
131
|
JSIConverter<std::shared_ptr<ImageBitmap>>::toJSI(
|
|
@@ -158,12 +155,11 @@ public:
|
|
|
158
155
|
blobId, offset, size,
|
|
159
156
|
[callInvoker, promise](ImageData imageData) {
|
|
160
157
|
auto imageBitmap = std::make_shared<ImageBitmap>(imageData);
|
|
161
|
-
callInvoker->invokeAsync(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
});
|
|
158
|
+
callInvoker->invokeAsync([promise, imageBitmap]() {
|
|
159
|
+
promise->resolve(
|
|
160
|
+
JSIConverter<std::shared_ptr<ImageBitmap>>::toJSI(
|
|
161
|
+
promise->runtime, imageBitmap));
|
|
162
|
+
});
|
|
167
163
|
},
|
|
168
164
|
[callInvoker, promise](std::string error) {
|
|
169
165
|
callInvoker->invokeAsync(
|
|
@@ -172,6 +168,38 @@ public:
|
|
|
172
168
|
});
|
|
173
169
|
}
|
|
174
170
|
|
|
171
|
+
std::shared_ptr<VideoFrame> loadVideoFrame(std::string path) {
|
|
172
|
+
auto frame = _platformContext->loadVideoFrame(path);
|
|
173
|
+
return std::make_shared<VideoFrame>(std::move(frame));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
std::shared_ptr<VideoFrame> createTestVideoFrame(double width, double height) {
|
|
177
|
+
auto frame = _platformContext->createTestVideoFrame(
|
|
178
|
+
static_cast<uint32_t>(width), static_cast<uint32_t>(height));
|
|
179
|
+
return std::make_shared<VideoFrame>(std::move(frame));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Wrap a CVPixelBufferRef / AHardwareBuffer* pointer (typed as void* via
|
|
183
|
+
// BigInt on the JS side) into one of our VideoFrames. The native side
|
|
184
|
+
// CFRetains / acquires so the caller can release immediately.
|
|
185
|
+
std::shared_ptr<VideoFrame> createVideoFrameFromNativeBuffer(void *pointer) {
|
|
186
|
+
auto handle = _platformContext->wrapNativeBuffer(pointer);
|
|
187
|
+
return std::make_shared<VideoFrame>(std::move(handle));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
std::shared_ptr<VideoPlayer>
|
|
191
|
+
createVideoPlayer(std::string path, std::optional<std::string> pixelFormat) {
|
|
192
|
+
auto format = (pixelFormat && pixelFormat.value() == "nv12")
|
|
193
|
+
? VideoPixelFormat::NV12
|
|
194
|
+
: VideoPixelFormat::BGRA8;
|
|
195
|
+
auto impl = _platformContext->createVideoPlayer(path, format);
|
|
196
|
+
return std::make_shared<VideoPlayer>(std::move(impl));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
std::string writeTestVideoFile() {
|
|
200
|
+
return _platformContext->writeTestVideoFile();
|
|
201
|
+
}
|
|
202
|
+
|
|
175
203
|
std::shared_ptr<Canvas> getNativeSurface(int contextId) {
|
|
176
204
|
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
177
205
|
auto info = registry.getSurfaceInfo(contextId);
|
|
@@ -192,6 +220,16 @@ public:
|
|
|
192
220
|
&RNWebGPU::getNativeSurface);
|
|
193
221
|
installMethod(runtime, prototype, "MakeWebGPUCanvasContext",
|
|
194
222
|
&RNWebGPU::MakeWebGPUCanvasContext);
|
|
223
|
+
installMethod(runtime, prototype, "loadVideoFrame",
|
|
224
|
+
&RNWebGPU::loadVideoFrame);
|
|
225
|
+
installMethod(runtime, prototype, "createTestVideoFrame",
|
|
226
|
+
&RNWebGPU::createTestVideoFrame);
|
|
227
|
+
installMethod(runtime, prototype, "createVideoFrameFromNativeBuffer",
|
|
228
|
+
&RNWebGPU::createVideoFrameFromNativeBuffer);
|
|
229
|
+
installMethod(runtime, prototype, "createVideoPlayer",
|
|
230
|
+
&RNWebGPU::createVideoPlayer);
|
|
231
|
+
installMethod(runtime, prototype, "writeTestVideoFile",
|
|
232
|
+
&RNWebGPU::writeTestVideoFile);
|
|
195
233
|
}
|
|
196
234
|
|
|
197
235
|
private:
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <unordered_set>
|
|
5
|
+
#include <vector>
|
|
6
|
+
|
|
7
|
+
#include "webgpu/webgpu_cpp.h"
|
|
8
|
+
|
|
9
|
+
namespace rnwgpu {
|
|
10
|
+
|
|
11
|
+
// Umbrella feature name owned by react-native-wgpu. Backed by a
|
|
12
|
+
// platform-specific pair of Dawn features. The prefix is intentional: this
|
|
13
|
+
// string is not part of the WebGPU spec, it is our API surface for the
|
|
14
|
+
// "import a native surface as a sampleable texture" capability.
|
|
15
|
+
inline constexpr const char *kRnNativeTextureFeature =
|
|
16
|
+
"rnwebgpu/native-texture";
|
|
17
|
+
|
|
18
|
+
// Dawn features that back the umbrella on the current platform. Empty on
|
|
19
|
+
// platforms where the capability is not available, in which case the umbrella
|
|
20
|
+
// behaves as a no-op (it won't appear in adapter.features and asking for it
|
|
21
|
+
// in requiredFeatures expands to nothing).
|
|
22
|
+
inline std::vector<wgpu::FeatureName> rnNativeTextureBackingFeatures() {
|
|
23
|
+
#if defined(__APPLE__)
|
|
24
|
+
return {wgpu::FeatureName::SharedTextureMemoryIOSurface,
|
|
25
|
+
wgpu::FeatureName::SharedFenceMTLSharedEvent};
|
|
26
|
+
#elif defined(__ANDROID__)
|
|
27
|
+
return {wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer,
|
|
28
|
+
wgpu::FeatureName::SharedFenceSyncFD};
|
|
29
|
+
#else
|
|
30
|
+
return {};
|
|
31
|
+
#endif
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// If every Dawn feature backing the umbrella is in `enabled`, add the
|
|
35
|
+
// umbrella name to `out`. Used by adapter.features / device.features so JS
|
|
36
|
+
// callers can see (and call .has on) the same name they pass in.
|
|
37
|
+
inline void
|
|
38
|
+
maybeSynthesizeRnNativeTextureFeature(
|
|
39
|
+
const std::unordered_set<wgpu::FeatureName> &enabled,
|
|
40
|
+
std::unordered_set<std::string> &out) {
|
|
41
|
+
auto backing = rnNativeTextureBackingFeatures();
|
|
42
|
+
if (backing.empty()) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
for (auto f : backing) {
|
|
46
|
+
if (enabled.find(f) == enabled.end()) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
out.insert(kRnNativeTextureFeature);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
} // namespace rnwgpu
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <functional>
|
|
4
|
+
#include <memory>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <utility>
|
|
7
|
+
|
|
8
|
+
#include "JSIConverter.h"
|
|
9
|
+
#include "NativeObject.h"
|
|
10
|
+
#include "PlatformContext.h"
|
|
11
|
+
|
|
12
|
+
namespace rnwgpu {
|
|
13
|
+
|
|
14
|
+
namespace jsi = facebook::jsi;
|
|
15
|
+
|
|
16
|
+
// VideoFrame is a small RAII wrapper around a platform-specific native handle
|
|
17
|
+
// (IOSurfaceRef-backed CVPixelBuffer on Apple, AHardwareBuffer on Android).
|
|
18
|
+
// It surfaces the raw handle as a BigInt to JS so callers can hand it to
|
|
19
|
+
// GPUDevice.importSharedTextureMemory, and owns a deleter so the underlying
|
|
20
|
+
// object stays alive until the JS object is GC'd (or release() is called).
|
|
21
|
+
class VideoFrame : public NativeObject<VideoFrame> {
|
|
22
|
+
public:
|
|
23
|
+
// JS-facing brand. installConstructor() exposes this as globalThis[CLASS_NAME]
|
|
24
|
+
// and keys the NativeObjectRegistry / worklet serializer off it, so it must
|
|
25
|
+
// NOT be "VideoFrame": that would install our constructor over the WebCodecs
|
|
26
|
+
// `VideoFrame` global and shadow it at runtime. "NativeVideoFrame" matches the
|
|
27
|
+
// public TypeScript type (see src/types.ts) and keeps the two namespaces
|
|
28
|
+
// distinct. The C++ class stays `VideoFrame` for brevity; only the brand is
|
|
29
|
+
// namespaced.
|
|
30
|
+
static constexpr const char *CLASS_NAME = "NativeVideoFrame";
|
|
31
|
+
|
|
32
|
+
explicit VideoFrame(VideoFrameHandle handle)
|
|
33
|
+
: NativeObject(CLASS_NAME), _handle(std::move(handle)) {}
|
|
34
|
+
|
|
35
|
+
~VideoFrame() override { release(); }
|
|
36
|
+
|
|
37
|
+
std::string getBrand() { return CLASS_NAME; }
|
|
38
|
+
|
|
39
|
+
// The native handle (IOSurfaceRef / AHardwareBuffer*) as a uintptr_t value.
|
|
40
|
+
// Exposed as a BigInt on the JS side.
|
|
41
|
+
void *getHandle() { return _handle.handle; }
|
|
42
|
+
uint32_t getWidth() { return _handle.width; }
|
|
43
|
+
uint32_t getHeight() { return _handle.height; }
|
|
44
|
+
|
|
45
|
+
// Pixel format as a JS-visible string: "bgra8" | "nv12".
|
|
46
|
+
std::string getPixelFormat() {
|
|
47
|
+
return _handle.pixelFormat == VideoPixelFormat::NV12 ? "nv12" : "bgra8";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Direct access to the underlying handle, for use by importExternalTexture /
|
|
51
|
+
// importSharedTextureMemory inside the C++ layer (not exposed to JS).
|
|
52
|
+
const VideoFrameHandle &handle() const { return _handle; }
|
|
53
|
+
|
|
54
|
+
void release() {
|
|
55
|
+
if (_handle.deleter) {
|
|
56
|
+
_handle.deleter();
|
|
57
|
+
_handle.deleter = nullptr;
|
|
58
|
+
}
|
|
59
|
+
_handle.handle = nullptr;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
|
|
63
|
+
installGetter(runtime, prototype, "__brand", &VideoFrame::getBrand);
|
|
64
|
+
installGetter(runtime, prototype, "handle", &VideoFrame::getHandle);
|
|
65
|
+
installGetter(runtime, prototype, "width", &VideoFrame::getWidth);
|
|
66
|
+
installGetter(runtime, prototype, "height", &VideoFrame::getHeight);
|
|
67
|
+
installGetter(runtime, prototype, "pixelFormat",
|
|
68
|
+
&VideoFrame::getPixelFormat);
|
|
69
|
+
installMethod(runtime, prototype, "release", &VideoFrame::release);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private:
|
|
73
|
+
VideoFrameHandle _handle;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
} // namespace rnwgpu
|