@shopify/react-native-skia 2.6.4 → 2.6.5

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 (106) hide show
  1. package/android/CMakeLists.txt +7 -4
  2. package/android/build.gradle +22 -3
  3. package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +62 -0
  4. package/apple/RNSkApplePlatformContext.h +2 -0
  5. package/apple/RNSkApplePlatformContext.mm +71 -0
  6. package/apple/RNWebGPUAppleNativeBuffer.mm +33 -0
  7. package/cpp/api/JsiNativeBuffer.h +9 -1
  8. package/cpp/api/JsiSkAnimatedImageFactory.h +1 -1
  9. package/cpp/api/JsiSkApi.h +2 -2
  10. package/cpp/api/JsiSkCanvas.h +1 -1
  11. package/cpp/api/JsiSkDataFactory.h +1 -1
  12. package/cpp/api/JsiSkFont.h +1 -1
  13. package/cpp/api/JsiSkFontMgr.h +1 -1
  14. package/cpp/api/JsiSkHostObjects.h +3 -3
  15. package/cpp/api/JsiSkImage.h +2 -2
  16. package/cpp/api/JsiSkImageFactory.h +2 -2
  17. package/cpp/api/JsiSkPath.h +1 -1
  18. package/cpp/api/JsiSkPathFactory.h +1 -1
  19. package/cpp/api/JsiSkSurface.h +13 -5
  20. package/cpp/api/JsiSkTypeface.h +1 -1
  21. package/cpp/api/JsiSkTypefaceFontProvider.h +1 -1
  22. package/cpp/api/JsiSkiaContext.h +2 -2
  23. package/cpp/api/JsiTextureInfo.h +1 -1
  24. package/cpp/api/JsiVideo.h +2 -2
  25. package/cpp/api/recorder/Drawings.h +1 -1
  26. package/cpp/api/recorder/JsiRecorder.h +4 -4
  27. package/cpp/api/recorder/RNRecorder.h +1 -1
  28. package/cpp/jsi/ViewProperty.h +1 -1
  29. package/cpp/rnskia/RNDawnContext.h +13 -0
  30. package/cpp/rnskia/RNDawnUtils.h +11 -1
  31. package/cpp/rnskia/RNSkJsiViewApi.h +2 -2
  32. package/cpp/rnskia/RNSkManager.cpp +88 -2
  33. package/cpp/rnskia/RNSkPictureView.h +4 -4
  34. package/cpp/rnskia/RNSkPlatformContext.h +7 -0
  35. package/cpp/rnskia/RNSkView.h +9 -6
  36. package/cpp/rnwgpu/ArrayBuffer.h +51 -7
  37. package/cpp/rnwgpu/api/AppleNativeBuffer.h +22 -0
  38. package/cpp/rnwgpu/api/Convertors.h +33 -11
  39. package/cpp/rnwgpu/api/GPUAdapter.cpp +28 -2
  40. package/cpp/rnwgpu/api/GPUBuffer.h +1 -1
  41. package/cpp/rnwgpu/api/GPUDevice.cpp +29 -2
  42. package/cpp/rnwgpu/api/GPUDevice.h +6 -0
  43. package/cpp/rnwgpu/api/GPUExternalTexture.cpp +139 -0
  44. package/cpp/rnwgpu/api/GPUExternalTexture.h +52 -2
  45. package/cpp/rnwgpu/api/GPUQueue.cpp +50 -45
  46. package/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp +82 -0
  47. package/cpp/rnwgpu/api/GPUSharedTextureMemory.h +70 -0
  48. package/cpp/rnwgpu/api/ImageBitmap.h +62 -0
  49. package/cpp/rnwgpu/api/NativeBufferUtils.h +87 -0
  50. package/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h +4 -1
  51. package/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +1 -1
  52. package/cpp/rnwgpu/api/descriptors/GPUDawnTogglesDescriptor.h +56 -0
  53. package/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h +10 -0
  54. package/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +43 -24
  55. package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +9 -9
  56. package/cpp/rnwgpu/api/descriptors/GPUImageCopyTexture.h +1 -1
  57. package/cpp/rnwgpu/api/descriptors/GPUImageCopyTextureTagged.h +2 -2
  58. package/cpp/rnwgpu/api/descriptors/GPUSharedTextureMemoryDescriptor.h +73 -0
  59. package/cpp/rnwgpu/api/descriptors/GPUTextureDescriptor.h +1 -1
  60. package/cpp/rnwgpu/api/descriptors/GPUUncapturedErrorEventInit.h +1 -1
  61. package/cpp/skia/include/core/SkRegion.h +10 -5
  62. package/cpp/skia/include/effects/SkRuntimeEffect.h +2 -2
  63. package/cpp/skia/include/gpu/graphite/Context.h +1 -1
  64. package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.d.ts +10 -1
  65. package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
  66. package/lib/commonjs/skia/types/WebGPU.d.ts +88 -0
  67. package/lib/commonjs/skia/types/WebGPU.js +6 -0
  68. package/lib/commonjs/skia/types/WebGPU.js.map +1 -0
  69. package/lib/commonjs/skia/types/index.d.ts +1 -0
  70. package/lib/commonjs/skia/types/index.js +11 -0
  71. package/lib/commonjs/skia/types/index.js.map +1 -1
  72. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
  73. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js +19 -0
  74. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js.map +1 -1
  75. package/lib/commonjs/skia/web/JsiSkPath.js.map +1 -1
  76. package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.d.ts +10 -1
  77. package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
  78. package/lib/module/skia/types/WebGPU.d.ts +88 -0
  79. package/lib/module/skia/types/WebGPU.js +2 -0
  80. package/lib/module/skia/types/WebGPU.js.map +1 -0
  81. package/lib/module/skia/types/index.d.ts +1 -0
  82. package/lib/module/skia/types/index.js +1 -0
  83. package/lib/module/skia/types/index.js.map +1 -1
  84. package/lib/module/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
  85. package/lib/module/skia/web/JsiSkNativeBufferFactory.js +19 -0
  86. package/lib/module/skia/web/JsiSkNativeBufferFactory.js.map +1 -1
  87. package/lib/module/skia/web/JsiSkPath.js.map +1 -1
  88. package/lib/module/web/LoadSkiaWeb.js +1 -2
  89. package/lib/module/web/LoadSkiaWeb.js.map +1 -1
  90. package/lib/typescript/lib/commonjs/skia/types/WebGPU.d.ts +1 -0
  91. package/lib/typescript/lib/commonjs/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
  92. package/lib/typescript/lib/module/skia/types/WebGPU.d.ts +1 -0
  93. package/lib/typescript/lib/module/skia/types/index.d.ts +1 -0
  94. package/lib/typescript/lib/module/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
  95. package/lib/typescript/src/skia/types/NativeBuffer/NativeBufferFactory.d.ts +10 -1
  96. package/lib/typescript/src/skia/types/WebGPU.d.ts +88 -0
  97. package/lib/typescript/src/skia/types/index.d.ts +1 -0
  98. package/lib/typescript/src/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
  99. package/package.json +10 -8
  100. package/react-native-skia.podspec +59 -7
  101. package/src/skia/types/NativeBuffer/NativeBufferFactory.ts +10 -1
  102. package/src/skia/types/WebGPU.ts +108 -0
  103. package/src/skia/types/index.ts +1 -0
  104. package/src/skia/web/JsiSkNativeBufferFactory.ts +20 -0
  105. package/src/skia/web/JsiSkPath.ts +8 -2
  106. package/scripts/install-libs.js +0 -133
@@ -1,6 +1,8 @@
1
1
  #pragma once
2
2
 
3
+ #include <memory>
3
4
  #include <string>
5
+ #include <utility>
4
6
 
5
7
  #include "descriptors/Unions.h"
6
8
 
@@ -12,16 +14,61 @@ namespace rnwgpu {
12
14
 
13
15
  namespace jsi = facebook::jsi;
14
16
 
17
+ struct GPUExternalTextureDescriptor;
18
+
15
19
  class GPUExternalTexture : public NativeObject<GPUExternalTexture> {
16
20
  public:
17
21
  static constexpr const char *CLASS_NAME = "GPUExternalTexture";
18
22
 
19
- explicit GPUExternalTexture(wgpu::ExternalTexture instance, std::string label)
20
- : NativeObject(CLASS_NAME), _instance(instance), _label(label) {}
23
+ // Import a native buffer (via descriptor.source, a CVPixelBufferRef /
24
+ // AHardwareBuffer* from Skia's NativeBuffer API) 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 (the native buffer's surface) can reclaim it.
37
+ GPUExternalTexture(wgpu::ExternalTexture instance,
38
+ wgpu::SharedTextureMemory memory, wgpu::Texture texture,
39
+ std::string label)
40
+ : NativeObject(CLASS_NAME), _instance(std::move(instance)),
41
+ _memory(std::move(memory)), _texture(std::move(texture)),
42
+ _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 stays claimed until GC runs. EndAccess is
55
+ // the designed post-submit call: Dawn keeps the texture alive for in-flight
56
+ // GPU work via the fences it returns.
57
+ void destroy() {
58
+ if (_memory && _texture) {
59
+ wgpu::SharedTextureMemoryEndAccessState state{};
60
+ #if defined(__ANDROID__)
61
+ // Dawn's Vulkan backend requires the released VkImageLayout to be chained
62
+ // (matches BeginAccess in GPUExternalTexture::Create).
63
+ wgpu::SharedTextureMemoryVkImageLayoutEndState vkEnd{};
64
+ state.nextInChain = &vkEnd;
65
+ #endif
66
+ (void)_memory.EndAccess(_texture, &state);
67
+ }
68
+ _texture = nullptr;
69
+ _memory = nullptr;
70
+ }
71
+
25
72
  std::string getLabel() { return _label; }
26
73
  void setLabel(const std::string &label) {
27
74
  _label = label;
@@ -33,12 +80,15 @@ public:
33
80
  installGetterSetter(runtime, prototype, "label",
34
81
  &GPUExternalTexture::getLabel,
35
82
  &GPUExternalTexture::setLabel);
83
+ installMethod(runtime, prototype, "destroy", &GPUExternalTexture::destroy);
36
84
  }
37
85
 
38
86
  inline const wgpu::ExternalTexture get() { return _instance; }
39
87
 
40
88
  private:
41
89
  wgpu::ExternalTexture _instance;
90
+ wgpu::SharedTextureMemory _memory;
91
+ wgpu::Texture _texture;
42
92
  std::string _label;
43
93
  };
44
94
 
@@ -1,5 +1,6 @@
1
1
  #include "GPUQueue.h"
2
2
 
3
+ #include <cstring>
3
4
  #include <limits>
4
5
  #include <memory>
5
6
  #include <vector>
@@ -103,51 +104,55 @@ void GPUQueue::copyExternalImageToTexture(
103
104
  std::shared_ptr<GPUImageCopyExternalImage> source,
104
105
  std::shared_ptr<GPUImageCopyTextureTagged> destination,
105
106
  std::shared_ptr<GPUExtent3D> size) {
106
- // wgpu::TexelCopyTextureInfo dst{};
107
- // wgpu::TexelCopyBufferLayout layout{};
108
- // wgpu::Extent3D sz{};
109
- // Convertor conv;
110
- // uint32_t bytesPerPixel =
111
- // source->source->getSize() /
112
- // (source->source->getWidth() * source->source->getHeight());
113
- // auto dataLayout = std::make_shared<GPUImageDataLayout>(GPUImageDataLayout{
114
- // std::optional<double>{0.0},
115
- // std::optional<double>{
116
- // static_cast<double>(bytesPerPixel * source->source->getWidth())},
117
- // std::optional<double>{static_cast<double>(source->source->getHeight())}});
118
- // if (!conv(dst.aspect, destination->aspect) ||
119
- // !conv(dst.mipLevel, destination->mipLevel) ||
120
- // !conv(dst.origin, destination->origin) ||
121
- // !conv(dst.texture, destination->texture) ||
122
- // !conv(layout, dataLayout) || //
123
- // !conv(sz, size)) {
124
- // throw std::runtime_error("Invalid input for GPUQueue::writeTexture()");
125
- // }
126
- //
127
- // if (source->flipY.value_or(false)) {
128
- // // Calculate the row size and total size
129
- // uint32_t rowSize = bytesPerPixel * source->source->getWidth();
130
- // uint32_t totalSize = source->source->getSize();
131
- //
132
- // // Create a new buffer for the flipped data
133
- // std::vector<uint8_t> flippedData(totalSize);
134
- //
135
- // // Flip the data vertically
136
- // for (uint32_t row = 0; row < source->source->getHeight(); ++row) {
137
- // std::memcpy(flippedData.data() +
138
- // (source->source->getHeight() - 1 - row) * rowSize,
139
- // static_cast<const uint8_t *>(source->source->getData()) +
140
- // row * rowSize,
141
- // rowSize);
142
- // }
143
- // // Use the flipped data for writing to texture
144
- // _instance.WriteTexture(&dst, flippedData.data(), totalSize, &layout,
145
- // &sz);
146
- // } else {
147
- //
148
- // _instance.WriteTexture(&dst, source->source->getData(),
149
- // source->source->getSize(), &layout, &sz);
150
- // }
107
+ if (!source || source->source == nullptr) {
108
+ throw std::runtime_error("GPUQueue::copyExternalImageToTexture(): "
109
+ "source.source (ImageBitmap) is required");
110
+ }
111
+ // ImageBitmap holds decoded, row-major RGBA8 pixels. We upload them with
112
+ // WriteTexture (a CPU staging copy) rather than a GPU blit; that is enough
113
+ // for the common "decode an image, sample it" path and avoids needing a
114
+ // source GPUTexture.
115
+ const auto &pixels = source->source->data();
116
+ auto width = static_cast<uint32_t>(source->source->getWidth());
117
+ auto height = static_cast<uint32_t>(source->source->getHeight());
118
+ if (pixels.empty() || width == 0 || height == 0) {
119
+ throw std::runtime_error("GPUQueue::copyExternalImageToTexture(): "
120
+ "ImageBitmap has no pixels (was it closed?)");
121
+ }
122
+ auto bytesPerPixel = static_cast<uint32_t>(
123
+ pixels.size() / (static_cast<size_t>(width) * height));
124
+ uint32_t rowSize = bytesPerPixel * width;
125
+
126
+ wgpu::TexelCopyTextureInfo dst{};
127
+ wgpu::TexelCopyBufferLayout layout{};
128
+ wgpu::Extent3D sz{};
129
+ Convertor conv;
130
+ auto dataLayout = std::make_shared<GPUImageDataLayout>(
131
+ GPUImageDataLayout{std::optional<double>{0.0},
132
+ std::optional<double>{static_cast<double>(rowSize)},
133
+ std::optional<double>{static_cast<double>(height)}});
134
+ if (!conv(dst.aspect, destination->aspect) ||
135
+ !conv(dst.mipLevel, destination->mipLevel) ||
136
+ !conv(dst.origin, destination->origin) ||
137
+ !conv(dst.texture, destination->texture) || !conv(layout, dataLayout) ||
138
+ !conv(sz, size)) {
139
+ throw std::runtime_error(
140
+ "Invalid input for GPUQueue::copyExternalImageToTexture()");
141
+ }
142
+
143
+ if (source->flipY.value_or(false)) {
144
+ // Flip rows so the image is uploaded bottom-up (matches the WebGPU
145
+ // copyExternalImageToTexture flipY semantics).
146
+ std::vector<uint8_t> flippedData(pixels.size());
147
+ for (uint32_t row = 0; row < height; ++row) {
148
+ std::memcpy(flippedData.data() + (height - 1 - row) * rowSize,
149
+ pixels.data() + row * rowSize, rowSize);
150
+ }
151
+ _instance.WriteTexture(&dst, flippedData.data(), flippedData.size(),
152
+ &layout, &sz);
153
+ } else {
154
+ _instance.WriteTexture(&dst, pixels.data(), pixels.size(), &layout, &sz);
155
+ }
151
156
  }
152
157
 
153
158
  void GPUQueue::writeTexture(std::shared_ptr<GPUImageCopyTexture> destination,
@@ -0,0 +1,82 @@
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
+ // The texture aliases the shared memory; it doesn't own GPU allocation, so
16
+ // it doesn't report memory pressure.
17
+ return std::make_shared<GPUTexture>(texture, "", false);
18
+ }
19
+
20
+ wgpu::TextureDescriptor desc{};
21
+ Convertor conv;
22
+ if (!conv(desc, descriptor.value())) {
23
+ throw std::runtime_error(
24
+ "GPUSharedTextureMemory::createTexture(): Error with "
25
+ "GPUTextureDescriptor");
26
+ }
27
+ auto texture = _instance.CreateTexture(&desc);
28
+ return std::make_shared<GPUTexture>(
29
+ texture, descriptor.value()->label.value_or(""), false);
30
+ }
31
+
32
+ bool GPUSharedTextureMemory::beginAccess(std::shared_ptr<GPUTexture> texture,
33
+ bool initialized) {
34
+ if (!texture) {
35
+ throw std::runtime_error(
36
+ "GPUSharedTextureMemory::beginAccess(): texture is null");
37
+ }
38
+ wgpu::SharedTextureMemoryBeginAccessDescriptor desc{};
39
+ desc.initialized = initialized;
40
+ desc.concurrentRead = false;
41
+ desc.fenceCount = 0;
42
+ desc.fences = nullptr;
43
+ desc.signaledValues = nullptr;
44
+
45
+ #if defined(__ANDROID__)
46
+ // Dawn's Vulkan backend (AHardwareBuffer) validates that the begin-access
47
+ // descriptor chains a SharedTextureMemoryVkImageLayoutBeginState specifying
48
+ // the VkImageLayout to acquire the image into. UNDEFINED (= 0) on both ends
49
+ // is the canonical "no prior GPU producer" pattern: Dawn performs an
50
+ // external-queue acquire from VK_QUEUE_FAMILY_EXTERNAL which preserves the
51
+ // AHB contents, then transitions to whatever layout the texture's actual
52
+ // usage requires.
53
+ wgpu::SharedTextureMemoryVkImageLayoutBeginState vkLayout{};
54
+ vkLayout.oldLayout = 0;
55
+ vkLayout.newLayout = 0;
56
+ desc.nextInChain = &vkLayout;
57
+ #endif
58
+
59
+ auto status = _instance.BeginAccess(texture->get(), &desc);
60
+ return static_cast<bool>(status);
61
+ }
62
+
63
+ bool GPUSharedTextureMemory::endAccess(std::shared_ptr<GPUTexture> texture) {
64
+ if (!texture) {
65
+ throw std::runtime_error(
66
+ "GPUSharedTextureMemory::endAccess(): texture is null");
67
+ }
68
+ wgpu::SharedTextureMemoryEndAccessState state{};
69
+
70
+ #if defined(__ANDROID__)
71
+ // Dawn's Vulkan backend writes the released old/new VkImageLayouts back into
72
+ // a chained SharedTextureMemoryVkImageLayoutEndState; validation requires
73
+ // the chain even when the caller doesn't read the values.
74
+ wgpu::SharedTextureMemoryVkImageLayoutEndState vkLayout{};
75
+ state.nextInChain = &vkLayout;
76
+ #endif
77
+
78
+ auto status = _instance.EndAccess(texture->get(), &state);
79
+ return static_cast<bool>(status);
80
+ }
81
+
82
+ } // namespace rnwgpu
@@ -0,0 +1,70 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <optional>
5
+ #include <string>
6
+
7
+ #include "jsi2/NativeObject.h"
8
+
9
+ #include "webgpu/webgpu_cpp.h"
10
+
11
+ #include "GPUTexture.h"
12
+ #include "descriptors/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> createTexture(
31
+ std::optional<std::shared_ptr<GPUTextureDescriptor>> descriptor);
32
+
33
+ // Returns true on success. `initialized` marks whether the shared memory's
34
+ // content should be preserved. Fence-based synchronization isn't exposed yet;
35
+ // we take the implicit/no-fence path that matches the common RN use cases
36
+ // (still images, single-producer frames).
37
+ bool beginAccess(std::shared_ptr<GPUTexture> texture, bool initialized);
38
+
39
+ // Returns true on success. Drops any fences produced by end-access (we do
40
+ // not yet surface them to JS).
41
+ bool endAccess(std::shared_ptr<GPUTexture> texture);
42
+
43
+ std::string getLabel() { return _label; }
44
+ void setLabel(const std::string &label) {
45
+ _label = label;
46
+ _instance.SetLabel(_label.c_str());
47
+ }
48
+
49
+ static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
50
+ installGetter(runtime, prototype, "__brand",
51
+ &GPUSharedTextureMemory::getBrand);
52
+ installMethod(runtime, prototype, "createTexture",
53
+ &GPUSharedTextureMemory::createTexture);
54
+ installMethod(runtime, prototype, "beginAccess",
55
+ &GPUSharedTextureMemory::beginAccess);
56
+ installMethod(runtime, prototype, "endAccess",
57
+ &GPUSharedTextureMemory::endAccess);
58
+ installGetterSetter(runtime, prototype, "label",
59
+ &GPUSharedTextureMemory::getLabel,
60
+ &GPUSharedTextureMemory::setLabel);
61
+ }
62
+
63
+ inline const wgpu::SharedTextureMemory get() { return _instance; }
64
+
65
+ private:
66
+ wgpu::SharedTextureMemory _instance;
67
+ std::string _label;
68
+ };
69
+
70
+ } // namespace rnwgpu
@@ -0,0 +1,62 @@
1
+ #pragma once
2
+
3
+ #include <cstdint>
4
+ #include <memory>
5
+ #include <utility>
6
+ #include <vector>
7
+
8
+ #include "jsi2/NativeObject.h"
9
+
10
+ namespace rnwgpu {
11
+
12
+ namespace jsi = facebook::jsi;
13
+
14
+ // DRAFT — compile-unverified. Minimal ImageBitmap holding decoded, unpremul
15
+ // RGBA8 pixels plus its dimensions. Produced by the global createImageBitmap()
16
+ // binding (see RNSkManager.cpp). Decoding is done with Skia's own codec, so no
17
+ // platform-specific image decoder is required.
18
+ //
19
+ // FOLLOW-UP: to make an ImageBitmap usable as a copyExternalImageToTexture
20
+ // source, uncomment the `source` field + ImageBitmap converter in
21
+ // rnwgpu/api/descriptors/GPUImageCopyExternalImage.h and upload `data()` in
22
+ // GPUQueue::copyExternalImageToTexture. That GPU wiring is intentionally out of
23
+ // scope for this draft.
24
+ class ImageBitmap : public NativeObject<ImageBitmap> {
25
+ public:
26
+ static constexpr const char *CLASS_NAME = "ImageBitmap";
27
+
28
+ ImageBitmap(std::vector<uint8_t> data, size_t width, size_t height)
29
+ : NativeObject(CLASS_NAME), _data(std::move(data)), _width(width),
30
+ _height(height) {}
31
+
32
+ size_t getWidth() { return _width; }
33
+
34
+ size_t getHeight() { return _height; }
35
+
36
+ // Per the spec, close() releases the bitmap's underlying pixels and zeroes
37
+ // its dimensions. Idempotent.
38
+ void close() {
39
+ _data.clear();
40
+ _data.shrink_to_fit();
41
+ _width = 0;
42
+ _height = 0;
43
+ }
44
+
45
+ // Decoded, unpremultiplied RGBA8 pixels (row-major, width*height*4 bytes).
46
+ const std::vector<uint8_t> &data() const { return _data; }
47
+
48
+ static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
49
+ installGetter(runtime, prototype, "width", &ImageBitmap::getWidth);
50
+ installGetter(runtime, prototype, "height", &ImageBitmap::getHeight);
51
+ installMethod(runtime, prototype, "close", &ImageBitmap::close);
52
+ }
53
+
54
+ size_t getMemoryPressure() override { return _data.size(); }
55
+
56
+ private:
57
+ std::vector<uint8_t> _data;
58
+ size_t _width;
59
+ size_t _height;
60
+ };
61
+
62
+ } // namespace rnwgpu
@@ -0,0 +1,87 @@
1
+ #pragma once
2
+
3
+ #include <cstdint>
4
+ #include <stdexcept>
5
+ #include <string>
6
+
7
+ #include "webgpu/webgpu_cpp.h"
8
+
9
+ #if defined(__APPLE__)
10
+ #include "AppleNativeBuffer.h"
11
+ #elif defined(__ANDROID__)
12
+ #include <android/hardware_buffer.h>
13
+ #endif
14
+
15
+ namespace rnwgpu {
16
+
17
+ // Import a Skia NativeBuffer pointer (a CVPixelBufferRef on Apple, an
18
+ // AHardwareBuffer* on Android, as returned by Skia.NativeBuffer.MakeFromImage /
19
+ // MakeTestBuffer) as a wgpu::SharedTextureMemory on `device`. When non-null,
20
+ // outWidth/outHeight receive the surface dimensions. Returns a null
21
+ // SharedTextureMemory if the import itself fails (the caller decides how to
22
+ // report that); throws std::runtime_error for pre-import failures (a buffer
23
+ // with no IOSurface, or an unsupported platform).
24
+ //
25
+ // The platform-specific chained descriptor only needs to outlive the
26
+ // ImportSharedTextureMemory call, so it lives entirely within this function.
27
+ // Shared by GPUDevice::importSharedTextureMemory and
28
+ // GPUExternalTexture::Create.
29
+ inline wgpu::SharedTextureMemory importNativeBufferAsSharedTextureMemory(
30
+ const wgpu::Device &device, void *bufferPtr, const std::string &label,
31
+ uint32_t *outWidth, uint32_t *outHeight) {
32
+ wgpu::SharedTextureMemoryDescriptor memDesc{};
33
+ if (!label.empty()) {
34
+ memDesc.label = wgpu::StringView(label.c_str(), label.size());
35
+ }
36
+
37
+ uint32_t width = 0;
38
+ uint32_t height = 0;
39
+ wgpu::SharedTextureMemory memory;
40
+
41
+ #if defined(__APPLE__)
42
+ // Skia's NativeBuffer is a CVPixelBufferRef; extract its backing IOSurface
43
+ // (and dimensions) in Objective-C++ since CoreVideo isn't available here.
44
+ void *ioSurface = GetIOSurfaceFromNativeBuffer(bufferPtr, &width, &height);
45
+ if (ioSurface == nullptr) {
46
+ throw std::runtime_error(
47
+ "importNativeBufferAsSharedTextureMemory(): native "
48
+ "buffer has no IOSurface");
49
+ }
50
+ wgpu::SharedTextureMemoryIOSurfaceDescriptor platformDesc{};
51
+ platformDesc.ioSurface = ioSurface;
52
+ // Default off: enabling it propagates StorageBinding into properties.usage,
53
+ // which then forces memory.createTexture() (no-descriptor form) to validate
54
+ // the format against storage capabilities. bgra8unorm (the standard
55
+ // CVPixelBuffer format) only supports storage when the device opts into the
56
+ // bgra8unorm-storage feature, so unconditionally setting this here breaks the
57
+ // common sample-only case.
58
+ platformDesc.allowStorageBinding = false;
59
+ memDesc.nextInChain = &platformDesc;
60
+ memory = device.ImportSharedTextureMemory(&memDesc);
61
+ #elif defined(__ANDROID__)
62
+ auto *ahb = reinterpret_cast<AHardwareBuffer *>(bufferPtr);
63
+ AHardwareBuffer_Desc ahbDesc = {};
64
+ AHardwareBuffer_describe(ahb, &ahbDesc);
65
+ width = ahbDesc.width;
66
+ height = ahbDesc.height;
67
+ wgpu::SharedTextureMemoryAHardwareBufferDescriptor platformDesc{};
68
+ platformDesc.handle = ahb;
69
+ memDesc.nextInChain = &platformDesc;
70
+ memory = device.ImportSharedTextureMemory(&memDesc);
71
+ #else
72
+ (void)device;
73
+ (void)bufferPtr;
74
+ throw std::runtime_error(
75
+ "importNativeBufferAsSharedTextureMemory(): unsupported platform");
76
+ #endif
77
+
78
+ if (outWidth != nullptr) {
79
+ *outWidth = width;
80
+ }
81
+ if (outHeight != nullptr) {
82
+ *outHeight = height;
83
+ }
84
+ return memory;
85
+ }
86
+
87
+ } // namespace rnwgpu
@@ -20,7 +20,7 @@ struct GPUBindGroupEntry {
20
20
  std::shared_ptr<GPUSampler> sampler = nullptr;
21
21
  std::shared_ptr<GPUTextureView> textureView = nullptr;
22
22
  std::shared_ptr<GPUBufferBinding> buffer = nullptr;
23
- // external textures
23
+ std::shared_ptr<GPUExternalTexture> externalTexture = nullptr;
24
24
  };
25
25
 
26
26
  } // namespace rnwgpu
@@ -45,6 +45,9 @@ template <> struct JSIConverter<std::shared_ptr<rnwgpu::GPUBindGroupEntry>> {
45
45
  } else if (obj.hasNativeState<rnwgpu::GPUTextureView>(runtime)) {
46
46
  result->textureView =
47
47
  obj.getNativeState<rnwgpu::GPUTextureView>(runtime);
48
+ } else if (obj.hasNativeState<rnwgpu::GPUExternalTexture>(runtime)) {
49
+ result->externalTexture =
50
+ obj.getNativeState<rnwgpu::GPUExternalTexture>(runtime);
48
51
  } else if (obj.hasNativeState<rnwgpu::GPUBuffer>(runtime)) {
49
52
  auto binding = std::make_shared<rnwgpu::GPUBufferBinding>();
50
53
  binding->buffer = obj.getNativeState<rnwgpu::GPUBuffer>(runtime);
@@ -7,7 +7,7 @@
7
7
 
8
8
  #include "jsi2/JSIConverter.h"
9
9
 
10
- #include "GPUDevice.h"
10
+ #include "rnwgpu/api/GPUDevice.h"
11
11
 
12
12
  namespace jsi = facebook::jsi;
13
13
 
@@ -0,0 +1,56 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <string>
5
+ #include <vector>
6
+
7
+ #include "webgpu/webgpu_cpp.h"
8
+
9
+ #include "jsi2/JSIConverter.h"
10
+
11
+ namespace jsi = facebook::jsi;
12
+
13
+ namespace rnwgpu {
14
+
15
+ // Non-standard, Dawn-only. Mirrors wgpu::DawnTogglesDescriptor field-for-field
16
+ // so the mapping to the native chained struct is 1:1. Chained onto the
17
+ // wgpu::DeviceDescriptor in GPUAdapter::requestDevice.
18
+ struct GPUDawnTogglesDescriptor {
19
+ std::optional<std::vector<std::string>> enabledToggles; // Iterable<string>
20
+ std::optional<std::vector<std::string>> disabledToggles; // Iterable<string>
21
+ };
22
+
23
+ } // namespace rnwgpu
24
+
25
+ namespace rnwgpu {
26
+
27
+ template <>
28
+ struct JSIConverter<std::shared_ptr<rnwgpu::GPUDawnTogglesDescriptor>> {
29
+ static std::shared_ptr<rnwgpu::GPUDawnTogglesDescriptor>
30
+ fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) {
31
+ auto result = std::make_unique<rnwgpu::GPUDawnTogglesDescriptor>();
32
+ if (!outOfBounds && arg.isObject()) {
33
+ auto value = arg.getObject(runtime);
34
+ if (value.hasProperty(runtime, "enabledToggles")) {
35
+ auto prop = value.getProperty(runtime, "enabledToggles");
36
+ result->enabledToggles =
37
+ JSIConverter<std::optional<std::vector<std::string>>>::fromJSI(
38
+ runtime, prop, false);
39
+ }
40
+ if (value.hasProperty(runtime, "disabledToggles")) {
41
+ auto prop = value.getProperty(runtime, "disabledToggles");
42
+ result->disabledToggles =
43
+ JSIConverter<std::optional<std::vector<std::string>>>::fromJSI(
44
+ runtime, prop, false);
45
+ }
46
+ }
47
+ return result;
48
+ }
49
+ static jsi::Value
50
+ toJSI(jsi::Runtime &runtime,
51
+ std::shared_ptr<rnwgpu::GPUDawnTogglesDescriptor> arg) {
52
+ throw std::runtime_error("Invalid GPUDawnTogglesDescriptor::toJSI()");
53
+ }
54
+ };
55
+
56
+ } // namespace rnwgpu
@@ -9,6 +9,7 @@
9
9
 
10
10
  #include "jsi2/JSIConverter.h"
11
11
 
12
+ #include "GPUDawnTogglesDescriptor.h"
12
13
  #include "GPUQueueDescriptor.h"
13
14
 
14
15
  namespace jsi = facebook::jsi;
@@ -23,6 +24,9 @@ struct GPUDeviceDescriptor {
23
24
  std::optional<std::shared_ptr<GPUQueueDescriptor>>
24
25
  defaultQueue; // GPUQueueDescriptor
25
26
  std::optional<std::string> label; // string
27
+ // Non-standard Dawn-only device toggles, chained onto the wgpu::Device
28
+ // descriptor in GPUAdapter::requestDevice.
29
+ std::optional<std::shared_ptr<GPUDawnTogglesDescriptor>> dawnToggles;
26
30
  };
27
31
 
28
32
  } // namespace rnwgpu
@@ -86,6 +90,12 @@ template <> struct JSIConverter<std::shared_ptr<rnwgpu::GPUDeviceDescriptor>> {
86
90
  result->label = JSIConverter<std::optional<std::string>>::fromJSI(
87
91
  runtime, prop, false);
88
92
  }
93
+ if (value.hasProperty(runtime, "dawnToggles")) {
94
+ auto prop = value.getProperty(runtime, "dawnToggles");
95
+ result->dawnToggles = JSIConverter<std::optional<
96
+ std::shared_ptr<GPUDawnTogglesDescriptor>>>::fromJSI(runtime, prop,
97
+ false);
98
+ }
89
99
  }
90
100
 
91
101
  return result;