react-native-webgpu 0.14.2 → 0.15.1

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 (108) hide show
  1. package/android/cpp/AndroidColorSpace.h +107 -0
  2. package/android/cpp/AndroidPlatformContext.h +100 -9
  3. package/android/cpp/AndroidVideoPlayer.h +46 -1
  4. package/android/cpp/cpp-adapter.cpp +53 -1
  5. package/android/src/main/java/com/webgpu/SyncFences.java +88 -0
  6. package/android/src/main/java/com/webgpu/ViewSnapshot.java +66 -23
  7. package/android/src/main/java/com/webgpu/WebGPUModule.java +69 -5
  8. package/android/src/main/java/com/webgpu/WebGPUVideoPlayer.java +109 -0
  9. package/apple/ApplePlatformContext.h +5 -5
  10. package/apple/ApplePlatformContext.mm +301 -90
  11. package/apple/AppleVideoPlayer.mm +68 -35
  12. package/cpp/dawn/common/ExternalTextureParams.h +67 -0
  13. package/cpp/rnwgpu/PlatformContext.h +71 -16
  14. package/cpp/rnwgpu/api/GPUAdapter.cpp +35 -0
  15. package/cpp/rnwgpu/api/GPUExternalTexture.cpp +172 -156
  16. package/cpp/rnwgpu/api/GPUExternalTexture.h +2 -19
  17. package/cpp/rnwgpu/api/GPUQueue.cpp +101 -3
  18. package/cpp/rnwgpu/api/RNWebGPU.h +9 -3
  19. package/cpp/rnwgpu/api/VideoFrameBlit.h +39 -24
  20. package/cpp/rnwgpu/api/descriptors/GPUDrawElementImageSource.h +7 -0
  21. package/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +10 -3
  22. package/lib/commonjs/Canvas.js +32 -5
  23. package/lib/commonjs/Canvas.js.map +1 -1
  24. package/lib/commonjs/WebPolyfillGPUModule.js +6 -3
  25. package/lib/commonjs/WebPolyfillGPUModule.js.map +1 -1
  26. package/lib/commonjs/constants.js +6 -3
  27. package/lib/commonjs/constants.js.map +1 -1
  28. package/lib/commonjs/index.js +1 -0
  29. package/lib/commonjs/index.js.map +1 -1
  30. package/lib/commonjs/install.js +9 -22
  31. package/lib/commonjs/install.js.map +1 -1
  32. package/lib/commonjs/main/index.js +8 -7
  33. package/lib/commonjs/main/index.js.map +1 -1
  34. package/lib/commonjs/main/index.web.js +1 -1
  35. package/lib/commonjs/main/installNative.js +20 -0
  36. package/lib/commonjs/main/installNative.js.map +1 -0
  37. package/lib/commonjs/main/installNative.web.js +4 -0
  38. package/lib/commonjs/main/installNative.web.js.map +1 -0
  39. package/lib/commonjs/mock.js +60 -13
  40. package/lib/commonjs/mock.js.map +1 -1
  41. package/lib/module/Canvas.js +33 -6
  42. package/lib/module/Canvas.js.map +1 -1
  43. package/lib/module/WebPolyfillGPUModule.js +6 -3
  44. package/lib/module/WebPolyfillGPUModule.js.map +1 -1
  45. package/lib/module/constants.js +6 -3
  46. package/lib/module/constants.js.map +1 -1
  47. package/lib/module/index.js +8 -1
  48. package/lib/module/index.js.map +1 -1
  49. package/lib/module/install.js +8 -20
  50. package/lib/module/install.js.map +1 -1
  51. package/lib/module/main/index.js +6 -7
  52. package/lib/module/main/index.js.map +1 -1
  53. package/lib/module/main/index.web.js +1 -1
  54. package/lib/module/main/index.web.js.map +1 -1
  55. package/lib/module/main/installNative.js +18 -0
  56. package/lib/module/main/installNative.js.map +1 -0
  57. package/lib/module/main/installNative.web.js +6 -0
  58. package/lib/module/main/installNative.web.js.map +1 -0
  59. package/lib/module/mock.js +55 -1
  60. package/lib/module/mock.js.map +1 -1
  61. package/lib/typescript/lib/commonjs/Canvas.d.ts.map +1 -1
  62. package/lib/typescript/lib/commonjs/install.d.ts +41 -3
  63. package/lib/typescript/lib/commonjs/install.d.ts.map +1 -1
  64. package/lib/typescript/lib/commonjs/main/installNative.d.ts +2 -0
  65. package/lib/typescript/lib/commonjs/main/installNative.d.ts.map +1 -0
  66. package/lib/typescript/lib/commonjs/main/installNative.web.d.ts +2 -0
  67. package/lib/typescript/lib/commonjs/main/installNative.web.d.ts.map +1 -0
  68. package/lib/typescript/lib/commonjs/mock.d.ts +39 -0
  69. package/lib/typescript/lib/commonjs/mock.d.ts.map +1 -1
  70. package/lib/typescript/lib/module/Canvas.d.ts.map +1 -1
  71. package/lib/typescript/lib/module/install.d.ts +0 -1
  72. package/lib/typescript/lib/module/install.d.ts.map +1 -1
  73. package/lib/typescript/lib/module/main/installNative.d.ts +2 -0
  74. package/lib/typescript/lib/module/main/installNative.d.ts.map +1 -0
  75. package/lib/typescript/lib/module/main/installNative.web.d.ts +2 -0
  76. package/lib/typescript/lib/module/main/installNative.web.d.ts.map +1 -0
  77. package/lib/typescript/lib/module/mock.d.ts +39 -1
  78. package/lib/typescript/lib/module/mock.d.ts.map +1 -1
  79. package/lib/typescript/src/Canvas.d.ts.map +1 -1
  80. package/lib/typescript/src/constants.d.ts.map +1 -1
  81. package/lib/typescript/src/index.d.ts +2 -2
  82. package/lib/typescript/src/index.d.ts.map +1 -1
  83. package/lib/typescript/src/install.d.ts +0 -5
  84. package/lib/typescript/src/install.d.ts.map +1 -1
  85. package/lib/typescript/src/main/index.d.ts +1 -0
  86. package/lib/typescript/src/main/index.d.ts.map +1 -1
  87. package/lib/typescript/src/main/index.web.d.ts +1 -1
  88. package/lib/typescript/src/main/index.web.d.ts.map +1 -1
  89. package/lib/typescript/src/main/installNative.d.ts +2 -0
  90. package/lib/typescript/src/main/installNative.d.ts.map +1 -0
  91. package/lib/typescript/src/main/installNative.web.d.ts +2 -0
  92. package/lib/typescript/src/main/installNative.web.d.ts.map +1 -0
  93. package/lib/typescript/src/mock.d.ts +5 -1
  94. package/lib/typescript/src/mock.d.ts.map +1 -1
  95. package/lib/typescript/src/types.d.ts +1 -0
  96. package/lib/typescript/src/types.d.ts.map +1 -1
  97. package/package.json +1 -1
  98. package/src/Canvas.tsx +44 -28
  99. package/src/WebPolyfillGPUModule.ts +3 -1
  100. package/src/constants.ts +6 -3
  101. package/src/index.tsx +18 -10
  102. package/src/install.ts +9 -18
  103. package/src/main/index.tsx +7 -10
  104. package/src/main/index.web.tsx +1 -1
  105. package/src/main/installNative.ts +20 -0
  106. package/src/main/installNative.web.ts +5 -0
  107. package/src/mock.ts +60 -1
  108. package/src/types.ts +6 -0
@@ -1,6 +1,8 @@
1
1
  package com.webgpu;
2
2
 
3
3
  import android.graphics.Bitmap;
4
+ import android.hardware.HardwareBuffer;
5
+ import android.os.Build;
4
6
  import android.util.Log;
5
7
  import android.view.View;
6
8
 
@@ -57,9 +59,12 @@ public class WebGPUModule extends NativeWebGPUModuleSpec {
57
59
  * Called from C++ (AndroidPlatformContext::snapshotView) on an arbitrary
58
60
  * thread for GPUQueue.drawElementImageToTexture. Hops to the UI thread,
59
61
  * resolves the view for {@code tag}, rasterizes the requested rectangle and
60
- * always reports back through {@link #onViewSnapshot}, with either a bitmap
61
- * or an error message. {@code callback} is an opaque native pointer that
62
- * must be handed back exactly once.
62
+ * always reports back exactly once: through {@link #onViewSnapshotBuffer}
63
+ * with the buffer the hardware renderer drew into, when the caller allows
64
+ * it and the platform can tell when the drawing is done (API 33), or else
65
+ * through {@link #onViewSnapshot} with a bitmap or an error message.
66
+ * {@code callback} is an opaque native pointer that must be handed back
67
+ * exactly once.
63
68
  *
64
69
  * The source rectangle is in density-independent points (React Native
65
70
  * layout units) and is converted to pixels here; a non-positive
@@ -75,11 +80,15 @@ public class WebGPUModule extends NativeWebGPUModuleSpec {
75
80
  final double sourceHeight,
76
81
  final int width,
77
82
  final int height,
83
+ final boolean allowHardwareBuffer,
78
84
  final long callback) {
79
85
  UiThreadUtil.runOnUiThread(
80
86
  () -> {
81
87
  Bitmap bitmap = null;
82
88
  String error = null;
89
+ // Set once the callback was handed to onViewSnapshotBuffer; nothing
90
+ // may report again after that.
91
+ final boolean[] handedOver = {false};
83
92
  try {
84
93
  ReactApplicationContext context = getReactApplicationContext();
85
94
  UIManager uiManager = UIManagerHelper.getUIManagerForReactTag(context, tag);
@@ -105,17 +114,72 @@ public class WebGPUModule extends NativeWebGPUModuleSpec {
105
114
  throw new IllegalArgumentException(
106
115
  "drawElementImageToTexture: the source rectangle is empty");
107
116
  }
108
- bitmap = ViewSnapshot.snapshot(view, sx, sy, sw, sh, w, h);
117
+ // The zero-copy path: the renderer's buffer goes to the GPU with
118
+ // the fence that says when the drawing is done. The fence is
119
+ // exposed from API 33; before that, and when the hardware render
120
+ // fails, the pixels are read back into a bitmap as usual.
121
+ if (allowHardwareBuffer
122
+ && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
123
+ && view.isHardwareAccelerated()) {
124
+ try {
125
+ ViewSnapshot.renderHardware(
126
+ view,
127
+ sx,
128
+ sy,
129
+ sw,
130
+ sh,
131
+ w,
132
+ h,
133
+ image -> {
134
+ HardwareBuffer buffer = image.getHardwareBuffer();
135
+ if (buffer == null) {
136
+ throw new IllegalStateException(
137
+ "HardwareRenderer image has no HardwareBuffer");
138
+ }
139
+ int fenceFd = SyncFences.acquireFenceFd(image);
140
+ // Native acquires its own reference to the buffer and
141
+ // adopts the fence descriptor.
142
+ handedOver[0] = true;
143
+ onViewSnapshotBuffer(callback, buffer, fenceFd);
144
+ buffer.close();
145
+ return null;
146
+ });
147
+ } catch (Throwable t) {
148
+ if (handedOver[0]) {
149
+ throw t;
150
+ }
151
+ Log.w(NAME, "HardwareRenderer snapshot failed, reading the pixels back instead", t);
152
+ }
153
+ }
154
+ if (!handedOver[0]) {
155
+ bitmap = ViewSnapshot.snapshot(view, sx, sy, sw, sh, w, h);
156
+ }
109
157
  } catch (Throwable t) {
158
+ if (handedOver[0]) {
159
+ // The result is already on its way; only the cleanup failed.
160
+ Log.w(NAME, "drawElementImageToTexture: cleanup after the snapshot failed", t);
161
+ return;
162
+ }
110
163
  error = t.getMessage() != null ? t.getMessage() : t.toString();
111
164
  }
112
- onViewSnapshot(callback, bitmap, error);
165
+ if (!handedOver[0]) {
166
+ onViewSnapshot(callback, bitmap, error);
167
+ }
113
168
  });
114
169
  }
115
170
 
116
171
  @DoNotStrip
117
172
  private native void onViewSnapshot(long callback, Bitmap bitmap, String error);
118
173
 
174
+ /**
175
+ * The zero-copy completion of {@link #snapshotView}: the buffer the hardware
176
+ * renderer drew the view into and the fence that signals when the drawing
177
+ * is done (a sync file descriptor native takes ownership of, -1 for none).
178
+ * Native acquires its own reference to the buffer before returning.
179
+ */
180
+ @DoNotStrip
181
+ private native void onViewSnapshotBuffer(long callback, HardwareBuffer buffer, int fenceFd);
182
+
119
183
  /**
120
184
  * Called from C++ (AndroidPlatformContext::createVideoPlayer) for
121
185
  * RNWebGPU.createVideoPlayer. Throws when the source cannot be opened; the
@@ -61,6 +61,23 @@ public class WebGPUVideoPlayer {
61
61
  private volatile int rotation = 0;
62
62
  private volatile double frameRate = 0;
63
63
  private volatile double durationSeconds = 0;
64
+ // The color space of the video track as the container declares it, packed
65
+ // like a data space (see dataSpaceFromContainer); 0 when it says nothing.
66
+ private volatile int containerDataSpace = 0;
67
+
68
+ // The layout of android.hardware.DataSpace (API 33), which is also the
69
+ // ADataSpace of the NDK: standard << 16, transfer << 22, range << 27. Spelled
70
+ // out so that the mapping compiles and runs on every supported API level.
71
+ private static final int DATASPACE_STANDARD_BT709 = 1 << 16;
72
+ private static final int DATASPACE_STANDARD_BT601_625 = 2 << 16;
73
+ private static final int DATASPACE_STANDARD_BT601_525 = 4 << 16;
74
+ private static final int DATASPACE_STANDARD_BT2020 = 6 << 16;
75
+ private static final int DATASPACE_TRANSFER_LINEAR = 1 << 22;
76
+ private static final int DATASPACE_TRANSFER_SMPTE_170M = 3 << 22;
77
+ private static final int DATASPACE_TRANSFER_ST2084 = 7 << 22;
78
+ private static final int DATASPACE_TRANSFER_HLG = 8 << 22;
79
+ private static final int DATASPACE_RANGE_FULL = 1 << 27;
80
+ private static final int DATASPACE_RANGE_LIMITED = 2 << 27;
64
81
 
65
82
  WebGPUVideoPlayer(Context context, String source) {
66
83
  Uri uri = parseSource(source);
@@ -160,6 +177,17 @@ public class WebGPUVideoPlayer {
160
177
  if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
161
178
  frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
162
179
  }
180
+ containerDataSpace =
181
+ dataSpaceFromContainer(
182
+ format.containsKey(MediaFormat.KEY_COLOR_STANDARD)
183
+ ? format.getInteger(MediaFormat.KEY_COLOR_STANDARD)
184
+ : 0,
185
+ format.containsKey(MediaFormat.KEY_COLOR_TRANSFER)
186
+ ? format.getInteger(MediaFormat.KEY_COLOR_TRANSFER)
187
+ : 0,
188
+ format.containsKey(MediaFormat.KEY_COLOR_RANGE)
189
+ ? format.getInteger(MediaFormat.KEY_COLOR_RANGE)
190
+ : 0);
163
191
  break;
164
192
  }
165
193
  }
@@ -185,6 +213,77 @@ public class WebGPUVideoPlayer {
185
213
  }
186
214
  }
187
215
 
216
+ // The MediaFormat color keys of the video track (KEY_COLOR_STANDARD,
217
+ // KEY_COLOR_TRANSFER, KEY_COLOR_RANGE; 0 when absent) packed like a data
218
+ // space, so that the native side reads one representation whatever its
219
+ // source.
220
+ private static int dataSpaceFromContainer(int standard, int transfer, int range) {
221
+ int dataSpace = 0;
222
+ switch (standard) {
223
+ case MediaFormat.COLOR_STANDARD_BT709:
224
+ dataSpace |= DATASPACE_STANDARD_BT709;
225
+ break;
226
+ case MediaFormat.COLOR_STANDARD_BT601_PAL:
227
+ dataSpace |= DATASPACE_STANDARD_BT601_625;
228
+ break;
229
+ case MediaFormat.COLOR_STANDARD_BT601_NTSC:
230
+ dataSpace |= DATASPACE_STANDARD_BT601_525;
231
+ break;
232
+ case MediaFormat.COLOR_STANDARD_BT2020:
233
+ dataSpace |= DATASPACE_STANDARD_BT2020;
234
+ break;
235
+ default:
236
+ break;
237
+ }
238
+ switch (transfer) {
239
+ case MediaFormat.COLOR_TRANSFER_LINEAR:
240
+ dataSpace |= DATASPACE_TRANSFER_LINEAR;
241
+ break;
242
+ case MediaFormat.COLOR_TRANSFER_SDR_VIDEO:
243
+ dataSpace |= DATASPACE_TRANSFER_SMPTE_170M;
244
+ break;
245
+ case MediaFormat.COLOR_TRANSFER_ST2084:
246
+ dataSpace |= DATASPACE_TRANSFER_ST2084;
247
+ break;
248
+ case MediaFormat.COLOR_TRANSFER_HLG:
249
+ dataSpace |= DATASPACE_TRANSFER_HLG;
250
+ break;
251
+ default:
252
+ break;
253
+ }
254
+ switch (range) {
255
+ case MediaFormat.COLOR_RANGE_FULL:
256
+ dataSpace |= DATASPACE_RANGE_FULL;
257
+ break;
258
+ case MediaFormat.COLOR_RANGE_LIMITED:
259
+ dataSpace |= DATASPACE_RANGE_LIMITED;
260
+ break;
261
+ default:
262
+ break;
263
+ }
264
+ return dataSpace;
265
+ }
266
+
267
+ /**
268
+ * The color space of a frame returned by {@link #copyLatestFrame}, as a data space (the
269
+ * packing of {@code android.hardware.DataSpace}): the one the decoder stamps on the frame
270
+ * (API 33), or what the container declares for the video track. 0 when neither says anything.
271
+ */
272
+ @DoNotStrip
273
+ public int frameDataSpace(Image image) {
274
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
275
+ try {
276
+ int dataSpace = image.getDataSpace();
277
+ if (dataSpace != 0) {
278
+ return dataSpace;
279
+ }
280
+ } catch (IllegalStateException e) {
281
+ // The frame was closed under us; fall back to the container.
282
+ }
283
+ }
284
+ return containerDataSpace;
285
+ }
286
+
188
287
  // The decoder reports the frame size (possibly more than once for adaptive
189
288
  // streams); the ImageReader that receives the frames is sized accordingly.
190
289
  private void onVideoSizeChanged(int w, int h) {
@@ -273,6 +372,16 @@ public class WebGPUVideoPlayer {
273
372
  return image;
274
373
  }
275
374
 
375
+ /**
376
+ * The acquire fence of a frame returned by {@link #copyLatestFrame}, as a sync file descriptor
377
+ * the caller owns, or -1 when there is none. The decoder may still be writing the frame when it
378
+ * is acquired; the GPU work that samples it has to wait on this fence (see {@link SyncFences}).
379
+ */
380
+ @DoNotStrip
381
+ public static int acquireFenceFd(Image image) {
382
+ return SyncFences.acquireFenceFd(image);
383
+ }
384
+
276
385
  /** Hands the buffer of a frame returned by {@link #copyLatestFrame} back to the decoder. */
277
386
  @DoNotStrip
278
387
  public void closeImage(Image image) {
@@ -17,7 +17,8 @@ public:
17
17
  ~ApplePlatformContext() = default;
18
18
 
19
19
  void snapshotView(const ViewSnapshotRequest &request,
20
- std::function<void(ImageData)> onSuccess,
20
+ std::function<void(ImageData)> onPixels,
21
+ std::function<void(VideoFrameHandle)> onFrame,
21
22
  std::function<void(std::string)> onError) override;
22
23
 
23
24
  ImageData createImageBitmap(std::string blobId, double offset,
@@ -36,12 +37,11 @@ public:
36
37
 
37
38
  VideoFrameHandle loadVideoFrame(const std::string &path) override;
38
39
 
39
- VideoFrameHandle createTestVideoFrame(uint32_t width,
40
- uint32_t height) override;
40
+ VideoFrameHandle createTestVideoFrame(uint32_t width, uint32_t height,
41
+ VideoPixelFormat format) override;
41
42
 
42
43
  std::unique_ptr<IVideoPlayer>
43
- createVideoPlayer(const std::string &path,
44
- VideoPixelFormat format) override;
44
+ createVideoPlayer(const std::string &path, VideoPixelFormat format) override;
45
45
 
46
46
  std::string writeTestVideoFile() override;
47
47