react-native-webgpu 0.15.1 → 0.16.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.
Files changed (47) hide show
  1. package/android/CMakeLists.txt +5 -0
  2. package/android/cpp/cpp-adapter.cpp +160 -49
  3. package/android/src/main/java/com/webgpu/SurfaceFrameRateVote.java +196 -0
  4. package/android/src/main/java/com/webgpu/WebGPUView.java +29 -2
  5. package/apple/ApplePlatformContext.h +1 -0
  6. package/cpp/jsi/JSICache.cpp +2 -0
  7. package/cpp/jsi/NativeObject.h +36 -12
  8. package/cpp/rnwgpu/RNWebGPUManager.cpp +4 -0
  9. package/cpp/rnwgpu/SurfaceRegistry.h +28 -4
  10. package/cpp/rnwgpu/api/GPUDevice.cpp +96 -0
  11. package/cpp/rnwgpu/api/GPUDevice.h +22 -0
  12. package/cpp/rnwgpu/api/GPUError.h +1 -0
  13. package/cpp/rnwgpu/api/GPUExtent2D.h +56 -0
  14. package/cpp/rnwgpu/api/GPUExternalTexture.cpp +32 -408
  15. package/cpp/rnwgpu/api/GPUExternalTexture.h +12 -37
  16. package/cpp/rnwgpu/api/GPUInternalError.h +1 -0
  17. package/cpp/rnwgpu/api/GPUNativeBufferExternalTexture.h +60 -0
  18. package/cpp/rnwgpu/api/GPUNativeBufferTexture.h +52 -0
  19. package/cpp/rnwgpu/api/GPUNativeBufferWrapper.cpp +144 -0
  20. package/cpp/rnwgpu/api/GPUNativeBufferWrapper.h +142 -0
  21. package/cpp/rnwgpu/api/GPUOutOfMemoryError.h +1 -0
  22. package/cpp/rnwgpu/api/GPUQueue.h +1 -0
  23. package/cpp/rnwgpu/api/GPUSharedFence.h +1 -0
  24. package/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp +12 -44
  25. package/cpp/rnwgpu/api/GPUSharedTextureMemory.h +1 -0
  26. package/cpp/rnwgpu/api/GPUUncapturedErrorEvent.h +1 -0
  27. package/cpp/rnwgpu/api/GPUValidationError.h +1 -0
  28. package/cpp/rnwgpu/api/NativeFrameImport.cpp +638 -0
  29. package/cpp/rnwgpu/api/NativeFrameImport.h +86 -0
  30. package/cpp/rnwgpu/api/VideoFrame.h +21 -7
  31. package/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +153 -1
  32. package/cpp/rnwgpu/api/descriptors/GPUNativeBufferTextureDescriptor.h +55 -0
  33. package/cpp/rnwgpu/async/RuntimeContext.cpp +1 -0
  34. package/lib/commonjs/Canvas.js.map +1 -1
  35. package/lib/commonjs/index.js.map +1 -1
  36. package/lib/module/Canvas.js.map +1 -1
  37. package/lib/module/index.js.map +1 -1
  38. package/lib/typescript/src/Canvas.d.ts +2 -31
  39. package/lib/typescript/src/Canvas.d.ts.map +1 -1
  40. package/lib/typescript/src/index.d.ts +4 -2
  41. package/lib/typescript/src/index.d.ts.map +1 -1
  42. package/lib/typescript/src/types.d.ts +33 -0
  43. package/lib/typescript/src/types.d.ts.map +1 -1
  44. package/package.json +1 -1
  45. package/src/Canvas.tsx +3 -36
  46. package/src/index.tsx +24 -0
  47. package/src/types.ts +97 -0
@@ -59,7 +59,7 @@ struct Size {
59
59
  using NativeSurfaceReleaser = std::function<void(void *)>;
60
60
 
61
61
  #if defined(__ANDROID__)
62
- // --- AHB-pool presentation mode (WebGPUHardwareBufferView)
62
+ // --- AHB-pool presentation mode (WebGPUNativeBufferView)
63
63
  // -----------------------------
64
64
  //
65
65
  // A third presentation backend (besides the on-screen wgpu::Surface swapchain
@@ -71,7 +71,7 @@ using NativeSurfaceReleaser = std::function<void(void *)>;
71
71
  // like the swapchain, so the canvas texture always matches the app's other
72
72
  // attachments (e.g. its depth texture).
73
73
 
74
- #define RNWGPU_LOG_TAG "WebGPUHardwareBufferView"
74
+ #define RNWGPU_LOG_TAG "WebGPUNativeBufferView"
75
75
  // Failure / anomaly reporting only (never per-frame).
76
76
  #define RNWGPU_POOL_WARN(...) \
77
77
  __android_log_print(ANDROID_LOG_WARN, RNWGPU_LOG_TAG, __VA_ARGS__)
@@ -435,7 +435,7 @@ public:
435
435
  bool hasNativeSurface() {
436
436
  std::shared_lock<std::shared_mutex> lock(_mutex);
437
437
  #if defined(__ANDROID__)
438
- // A WebGPUHardwareBufferView in pool mode owns presentation the same way a
438
+ // A WebGPUNativeBufferView in pool mode owns presentation the same way a
439
439
  // surface-backed view does, and retires the entry on its own teardown.
440
440
  if (_poolMode.load()) {
441
441
  return true;
@@ -548,16 +548,27 @@ public:
548
548
  if (device) {
549
549
  dawn::native::metal::WaitForCommandsToBeScheduled(device.Get());
550
550
  }
551
+ #endif
552
+ #if defined(__ANDROID__)
553
+ std::function<void()> framePresented;
551
554
  #endif
552
555
  {
553
556
  std::unique_lock<std::shared_mutex> lock(_mutex);
554
557
  if (_surface && _acquiredFromSurface) {
555
558
  _surface.Present();
559
+ #if defined(__ANDROID__)
560
+ framePresented = _framePresented;
561
+ #endif
556
562
  }
557
563
  _acquiredFromSurface = false;
558
564
  _frameInFlight = false;
559
565
  _frameEpoch++;
560
566
  }
567
+ #if defined(__ANDROID__)
568
+ if (framePresented) {
569
+ framePresented();
570
+ }
571
+ #endif
561
572
  applyPendingAttach();
562
573
  }
563
574
 
@@ -691,6 +702,16 @@ public:
691
702
  std::lock_guard<std::mutex> poolLock(_poolMutex);
692
703
  _poolFrameReady = std::move(cb);
693
704
  }
705
+
706
+ // Invoked from the presenting thread (never under _mutex) after each frame
707
+ // presentFrame() shows on the attached surface; the blit of the last
708
+ // offscreen frame onto a newly attached surface does not count. The view
709
+ // uses it to vote the display's refresh rate while the canvas animates
710
+ // (see SurfaceFrameRateVote.java). Pass nullptr to unregister.
711
+ void setFramePresentedCallback(std::function<void()> cb) {
712
+ std::unique_lock<std::shared_mutex> lock(_mutex);
713
+ _framePresented = std::move(cb);
714
+ }
694
715
  #endif
695
716
 
696
717
  private:
@@ -704,7 +725,7 @@ private:
704
725
  {
705
726
  std::unique_lock<std::shared_mutex> lock(_mutex);
706
727
  #if defined(__ANDROID__)
707
- // Leaving pool mode (the WebGPUHardwareBufferView detached): drop the
728
+ // Leaving pool mode (the WebGPUNativeBufferView detached): drop the
708
729
  // pool. A configured context keeps rendering into the offscreen
709
730
  // fallback, exactly like the surface path.
710
731
  if (_poolMode.load()) {
@@ -1239,6 +1260,9 @@ private:
1239
1260
  static constexpr int kPoolSize =
1240
1261
  5; // 2 held + 1 rendering + 1 waiting + 1 ready
1241
1262
 
1263
+ // See setFramePresentedCallback(); read under _mutex, called outside it.
1264
+ std::function<void()> _framePresented;
1265
+
1242
1266
  std::atomic<bool> _poolMode{false};
1243
1267
  std::mutex _poolMutex;
1244
1268
  std::condition_variable _freeCv; // a slot returned to Free
@@ -1,5 +1,6 @@
1
1
  #include "GPUDevice.h"
2
2
 
3
+ #include <cstdio>
3
4
  #include <memory>
4
5
  #include <string>
5
6
  #include <unordered_set>
@@ -15,6 +16,7 @@
15
16
  #include "GPUInternalError.h"
16
17
  #include "GPUOutOfMemoryError.h"
17
18
  #include "GPUValidationError.h"
19
+ #include "NativeFrameImport.h"
18
20
  #include "SurfaceRegistry.h"
19
21
 
20
22
  namespace rnwgpu {
@@ -130,6 +132,14 @@ std::shared_ptr<GPUSupportedLimits> GPUDevice::getLimits() {
130
132
  return std::make_shared<GPUSupportedLimits>(limits);
131
133
  }
132
134
 
135
+ std::shared_ptr<GPUAdapterInfo> GPUDevice::getAdapterInfo() {
136
+ wgpu::AdapterInfo info = {};
137
+ if (_instance.GetAdapterInfo(&info) != wgpu::Status::Success) {
138
+ throw std::runtime_error("failed to get the device's adapter info");
139
+ }
140
+ return std::make_shared<GPUAdapterInfo>(info);
141
+ }
142
+
133
143
  std::shared_ptr<GPUQueue> GPUDevice::getQueue() {
134
144
  auto result = _instance.GetQueue();
135
145
  return std::make_shared<GPUQueue>(_instance, result, _async, _videoFrameBlit,
@@ -413,6 +423,92 @@ std::shared_ptr<GPUSharedFence> GPUDevice::importSharedFence(
413
423
  std::move(label));
414
424
  }
415
425
 
426
+ std::shared_ptr<GPUNativeBufferTexture> GPUDevice::createNativeBufferTexture(
427
+ std::shared_ptr<VideoFrame> source,
428
+ std::optional<std::shared_ptr<GPUNativeBufferTextureDescriptor>>
429
+ descriptor) {
430
+ static constexpr const char *kCaller = "GPUDevice::createNativeBufferTexture";
431
+ if (!source) {
432
+ throw std::runtime_error("GPUDevice::createNativeBufferTexture(): "
433
+ "source (NativeVideoFrame) is required");
434
+ }
435
+ std::string label;
436
+ std::optional<double> usage;
437
+ if (descriptor.has_value() && *descriptor) {
438
+ label = (*descriptor)->label.value_or("");
439
+ usage = (*descriptor)->usage;
440
+ }
441
+ auto memory =
442
+ native_frame::importMemory(_instance, source->handle(), label, kCaller);
443
+ wgpu::Texture texture;
444
+ if (usage.has_value()) {
445
+ // Dawn's layer describes the texture from the memory's properties, with
446
+ // the caller's usage. An unsupported usage is a validation error and an
447
+ // error texture, as with createTexture().
448
+ wgpu::SharedTextureMemoryProperties properties{};
449
+ (void)memory.GetProperties(&properties);
450
+ wgpu::TextureDescriptor desc{};
451
+ if (!label.empty()) {
452
+ desc.label = wgpu::StringView(label.c_str(), label.size());
453
+ }
454
+ desc.usage = static_cast<wgpu::TextureUsage>(static_cast<uint64_t>(*usage));
455
+ desc.dimension = wgpu::TextureDimension::e2D;
456
+ desc.size = properties.size;
457
+ desc.format = properties.format;
458
+ desc.mipLevelCount = 1;
459
+ desc.sampleCount = 1;
460
+ texture = memory.CreateTexture(&desc);
461
+ } else {
462
+ texture = memory.CreateTexture();
463
+ }
464
+ if (texture == nullptr) {
465
+ throw std::runtime_error("GPUDevice::createNativeBufferTexture(): "
466
+ "CreateTexture returned null");
467
+ }
468
+ auto wrapped = std::make_shared<GPUTexture>(std::move(texture), label);
469
+ return std::make_shared<GPUNativeBufferTexture>(
470
+ _instance, std::move(memory), std::move(wrapped), std::move(source),
471
+ std::move(label));
472
+ }
473
+
474
+ std::shared_ptr<GPUNativeBufferExternalTexture>
475
+ GPUDevice::createNativeBufferExternalTexture(
476
+ std::shared_ptr<VideoFrame> source,
477
+ std::optional<std::shared_ptr<GPUExternalTextureDescriptor>> descriptor) {
478
+ static constexpr const char *kCaller =
479
+ "GPUDevice::createNativeBufferExternalTexture";
480
+ if (!source) {
481
+ throw std::runtime_error(
482
+ "GPUDevice::createNativeBufferExternalTexture(): source "
483
+ "(NativeVideoFrame) is required");
484
+ }
485
+ std::shared_ptr<GPUExternalTextureDescriptor> options =
486
+ descriptor.has_value() && *descriptor
487
+ ? *descriptor
488
+ : std::make_shared<GPUExternalTextureDescriptor>();
489
+ const auto &frame = source->handle();
490
+ std::string label = options->label.value_or("external-texture");
491
+ // The import, the texture and the external texture, once per buffer. No
492
+ // access begins here: the wrapper's beginAccess() / endAccess() bracket
493
+ // each use.
494
+ auto memory = native_frame::importMemory(_instance, frame, label, kCaller);
495
+ auto texture = memory.CreateTexture();
496
+ if (texture == nullptr) {
497
+ throw std::runtime_error(
498
+ "GPUDevice::createNativeBufferExternalTexture(): CreateTexture "
499
+ "returned null");
500
+ }
501
+ auto external = native_frame::createExternalTexture(
502
+ _instance, memory, texture, frame, *options, label, kCaller);
503
+ // Non-owning: the wrapper owns the import (see GPUExternalTexture's
504
+ // constructor).
505
+ auto externalTexture = std::make_shared<GPUExternalTexture>(
506
+ std::move(external), nullptr, nullptr, nullptr, label);
507
+ return std::make_shared<GPUNativeBufferExternalTexture>(
508
+ _instance, std::move(memory), std::move(texture),
509
+ std::move(externalTexture), std::move(source), std::move(label));
510
+ }
511
+
416
512
  async::AsyncTaskHandle GPUDevice::createComputePipelineAsync(
417
513
  jsi::Runtime &runtime,
418
514
  std::shared_ptr<GPUComputePipelineDescriptor> descriptor) {
@@ -20,6 +20,7 @@
20
20
 
21
21
  #include "webgpu/webgpu_cpp.h"
22
22
 
23
+ #include "GPUAdapterInfo.h"
23
24
  #include "GPUBindGroup.h"
24
25
  #include "GPUBindGroupDescriptor.h"
25
26
  #include "GPUBindGroupLayout.h"
@@ -34,6 +35,9 @@
34
35
  #include "GPUError.h"
35
36
  #include "GPUExternalTexture.h"
36
37
  #include "GPUExternalTextureDescriptor.h"
38
+ #include "GPUNativeBufferExternalTexture.h"
39
+ #include "GPUNativeBufferTexture.h"
40
+ #include "GPUNativeBufferTextureDescriptor.h"
37
41
  #include "GPUPipelineLayout.h"
38
42
  #include "GPUPipelineLayoutDescriptor.h"
39
43
  #include "GPUQuerySet.h"
@@ -124,6 +128,17 @@ public:
124
128
  std::shared_ptr<GPUSharedTextureMemoryDescriptor> descriptor);
125
129
  std::shared_ptr<GPUSharedFence>
126
130
  importSharedFence(std::shared_ptr<GPUSharedFenceDescriptor> descriptor);
131
+ // Import a native buffer once and bracket each use with beginAccess /
132
+ // endAccess: the counterparts of createTexture / createExternalTexture in
133
+ // GPUAndroidHardwareBufferUtil of Dawn's Android layer.
134
+ std::shared_ptr<GPUNativeBufferTexture> createNativeBufferTexture(
135
+ std::shared_ptr<VideoFrame> source,
136
+ std::optional<std::shared_ptr<GPUNativeBufferTextureDescriptor>>
137
+ descriptor);
138
+ std::shared_ptr<GPUNativeBufferExternalTexture>
139
+ createNativeBufferExternalTexture(
140
+ std::shared_ptr<VideoFrame> source,
141
+ std::optional<std::shared_ptr<GPUExternalTextureDescriptor>> descriptor);
127
142
  std::shared_ptr<GPUBindGroupLayout> createBindGroupLayout(
128
143
  std::shared_ptr<GPUBindGroupLayoutDescriptor> descriptor);
129
144
  std::shared_ptr<GPUPipelineLayout>
@@ -153,6 +168,7 @@ public:
153
168
 
154
169
  std::unordered_set<std::string> getFeatures();
155
170
  std::shared_ptr<GPUSupportedLimits> getLimits();
171
+ std::shared_ptr<GPUAdapterInfo> getAdapterInfo();
156
172
  std::shared_ptr<GPUQueue> getQueue();
157
173
  jsi::Value getLost(jsi::Runtime &runtime, const jsi::Object &wrapper);
158
174
  void notifyDeviceLost(wgpu::DeviceLostReason reason, std::string message);
@@ -183,6 +199,10 @@ public:
183
199
  &GPUDevice::importSharedTextureMemory);
184
200
  installMethod(runtime, prototype, "importSharedFence",
185
201
  &GPUDevice::importSharedFence);
202
+ installMethod(runtime, prototype, "createNativeBufferTexture",
203
+ &GPUDevice::createNativeBufferTexture);
204
+ installMethod(runtime, prototype, "createNativeBufferExternalTexture",
205
+ &GPUDevice::createNativeBufferExternalTexture);
186
206
  installMethod(runtime, prototype, "createBindGroupLayout",
187
207
  &GPUDevice::createBindGroupLayout);
188
208
  installMethod(runtime, prototype, "createPipelineLayout",
@@ -211,6 +231,8 @@ public:
211
231
  &GPUDevice::popErrorScope);
212
232
  installGetter(runtime, prototype, "features", &GPUDevice::getFeatures);
213
233
  installGetter(runtime, prototype, "limits", &GPUDevice::getLimits);
234
+ installGetter(runtime, prototype, "adapterInfo",
235
+ &GPUDevice::getAdapterInfo);
214
236
  installGetter(runtime, prototype, "queue", &GPUDevice::getQueue);
215
237
  // `lost` is installed manually: the getter needs the wrapper object
216
238
  // itself, because the promise (and its resolve function) are cached as
@@ -1,6 +1,7 @@
1
1
  #pragma once
2
2
 
3
3
  #include <string>
4
+ #include <utility>
4
5
 
5
6
  #include "NativeObject.h"
6
7
 
@@ -0,0 +1,56 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <stdexcept>
5
+
6
+ #include "JSIConverter.h"
7
+
8
+ #include "webgpu/webgpu_cpp.h"
9
+
10
+ namespace rnwgpu {
11
+
12
+ // A 2D size, as an object ({ width, height }) or an array ([width, height]),
13
+ // the two forms the spec gives GPUExtent3D. Both members are required in
14
+ // either form: a crop size with a missing one would be empty.
15
+ struct GPUExtent2D {
16
+ double width = 0;
17
+ double height = 0;
18
+ };
19
+
20
+ template <> struct JSIConverter<std::shared_ptr<GPUExtent2D>> {
21
+ static std::shared_ptr<GPUExtent2D>
22
+ fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) {
23
+ auto result = std::make_unique<GPUExtent2D>();
24
+ if (!outOfBounds && arg.isObject()) {
25
+ if (arg.getObject(runtime).isArray(runtime)) {
26
+ auto array = arg.getObject(runtime).asArray(runtime);
27
+ if (array.size(runtime) < 2) {
28
+ throw std::runtime_error(
29
+ "Expected an array of size 2 for GPUExtent2D");
30
+ }
31
+ result->width = array.getValueAtIndex(runtime, 0).asNumber();
32
+ result->height = array.getValueAtIndex(runtime, 1).asNumber();
33
+ } else {
34
+ auto object = arg.getObject(runtime);
35
+ auto width = object.getProperty(runtime, "width");
36
+ auto height = object.getProperty(runtime, "height");
37
+ if (!width.isNumber() || !height.isNumber()) {
38
+ throw std::runtime_error(
39
+ "Expected numbers for the width and height of GPUExtent2D");
40
+ }
41
+ result->width = width.asNumber();
42
+ result->height = height.asNumber();
43
+ }
44
+ } else {
45
+ throw std::runtime_error("Expected an object for GPUExtent2D");
46
+ }
47
+ return result;
48
+ }
49
+ static jsi::Value toJSI(jsi::Runtime &runtime,
50
+ std::shared_ptr<GPUExtent2D> arg) {
51
+ // No conversions here
52
+ return jsi::Value::null();
53
+ }
54
+ };
55
+
56
+ } // namespace rnwgpu