react-native-webgpu 0.10.5 → 0.11.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 (61) hide show
  1. package/android/cpp/AndroidPlatformContext.h +100 -9
  2. package/android/cpp/AndroidVideoPlayer.h +307 -0
  3. package/android/cpp/cpp-adapter.cpp +66 -6
  4. package/android/src/main/java/com/webgpu/ViewSnapshot.java +162 -0
  5. package/android/src/main/java/com/webgpu/WebGPUModule.java +78 -0
  6. package/android/src/main/java/com/webgpu/WebGPUVideoPlayer.java +420 -0
  7. package/apple/ApplePlatformContext.h +14 -1
  8. package/apple/ApplePlatformContext.mm +176 -1
  9. package/apple/AppleVideoPlayer.mm +157 -47
  10. package/apple/WebGPUModule.mm +20 -1
  11. package/cpp/rnwgpu/PlatformContext.h +76 -1
  12. package/cpp/rnwgpu/RNWebGPUManager.cpp +7 -0
  13. package/cpp/rnwgpu/api/GPUDevice.cpp +2 -1
  14. package/cpp/rnwgpu/api/GPUDevice.h +6 -0
  15. package/cpp/rnwgpu/api/GPUQueue.cpp +261 -4
  16. package/cpp/rnwgpu/api/GPUQueue.h +29 -2
  17. package/cpp/rnwgpu/api/VideoFrameBlit.h +355 -0
  18. package/cpp/rnwgpu/api/VideoPlayer.h +50 -3
  19. package/cpp/rnwgpu/api/descriptors/GPUDrawElementImageDestination.h +60 -0
  20. package/cpp/rnwgpu/api/descriptors/GPUDrawElementImageSource.h +106 -0
  21. package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +30 -3
  22. package/lib/commonjs/importDevice.js +2 -2
  23. package/lib/commonjs/index.js.map +1 -1
  24. package/lib/commonjs/main/index.js +45 -0
  25. package/lib/commonjs/main/index.js.map +1 -1
  26. package/lib/commonjs/main/index.web.js +11 -0
  27. package/lib/commonjs/main/index.web.js.map +1 -1
  28. package/lib/commonjs/video.js +58 -0
  29. package/lib/commonjs/video.js.map +1 -0
  30. package/lib/module/importDevice.js +2 -2
  31. package/lib/module/index.js.map +1 -1
  32. package/lib/module/main/index.js +34 -0
  33. package/lib/module/main/index.js.map +1 -1
  34. package/lib/module/main/index.web.js +1 -0
  35. package/lib/module/main/index.web.js.map +1 -1
  36. package/lib/module/video.js +49 -0
  37. package/lib/module/video.js.map +1 -0
  38. package/lib/typescript/lib/commonjs/video.d.ts +30 -0
  39. package/lib/typescript/lib/commonjs/video.d.ts.map +1 -0
  40. package/lib/typescript/lib/module/main/index.d.ts +1 -0
  41. package/lib/typescript/lib/module/main/index.web.d.ts +1 -0
  42. package/lib/typescript/lib/module/video.d.ts +4 -0
  43. package/lib/typescript/lib/module/video.d.ts.map +1 -0
  44. package/lib/typescript/src/importDevice.d.ts +2 -2
  45. package/lib/typescript/src/index.d.ts +8 -3
  46. package/lib/typescript/src/index.d.ts.map +1 -1
  47. package/lib/typescript/src/main/index.d.ts +1 -0
  48. package/lib/typescript/src/main/index.d.ts.map +1 -1
  49. package/lib/typescript/src/main/index.web.d.ts +1 -0
  50. package/lib/typescript/src/main/index.web.d.ts.map +1 -1
  51. package/lib/typescript/src/types.d.ts +32 -0
  52. package/lib/typescript/src/types.d.ts.map +1 -1
  53. package/lib/typescript/src/video.d.ts +41 -0
  54. package/lib/typescript/src/video.d.ts.map +1 -0
  55. package/package.json +1 -1
  56. package/src/importDevice.ts +2 -2
  57. package/src/index.tsx +57 -3
  58. package/src/main/index.tsx +50 -0
  59. package/src/main/index.web.tsx +1 -0
  60. package/src/types.ts +89 -7
  61. package/src/video.ts +69 -0
@@ -67,6 +67,10 @@ RNWebGPUManager::RNWebGPUManager(
67
67
  // no invoker (best-effort; see README "Threading model").
68
68
  async::RuntimeContext::registerMainRuntime(_jsRuntime, _jsCallInvoker);
69
69
 
70
+ // Expose the platform context to API objects created later without a
71
+ // reference to it (GPUQueue::drawElementImageToTexture).
72
+ PlatformContext::setCurrent(_platformContext);
73
+
70
74
  auto gpu = std::make_shared<GPU>(*_jsRuntime);
71
75
  auto rnWebGPU =
72
76
  std::make_shared<RNWebGPU>(gpu, _platformContext, _jsCallInvoker);
@@ -248,6 +252,9 @@ RNWebGPUManager::~RNWebGPUManager() {
248
252
  // contextId counter, and stale entries would alias new canvases onto dead
249
253
  // surfaces.
250
254
  SurfaceRegistry::getInstance().clear();
255
+ if (PlatformContext::current() == _platformContext) {
256
+ PlatformContext::setCurrent(nullptr);
257
+ }
251
258
  _jsRuntime = nullptr;
252
259
  _jsCallInvoker = nullptr;
253
260
  }
@@ -133,7 +133,8 @@ std::shared_ptr<GPUSupportedLimits> GPUDevice::getLimits() {
133
133
 
134
134
  std::shared_ptr<GPUQueue> GPUDevice::getQueue() {
135
135
  auto result = _instance.GetQueue();
136
- return std::make_shared<GPUQueue>(result, _async, _label);
136
+ return std::make_shared<GPUQueue>(_instance, result, _async, _videoFrameBlit,
137
+ _label);
137
138
  }
138
139
 
139
140
  std::shared_ptr<GPUCommandEncoder> GPUDevice::createCommandEncoder(
@@ -54,6 +54,7 @@
54
54
  #include "GPUTexture.h"
55
55
  #include "GPUTextureDescriptor.h"
56
56
  #include "GPUUncapturedErrorEvent.h"
57
+ #include "VideoFrameBlit.h"
57
58
 
58
59
  namespace rnwgpu {
59
60
 
@@ -285,6 +286,11 @@ private:
285
286
  wgpu::Device _instance;
286
287
  std::shared_ptr<async::RuntimeContext> _async;
287
288
  std::string _label;
289
+ // Renders native video frames into textures for
290
+ // GPUQueue.copyExternalImageToTexture; shared by every GPUQueue wrapper of
291
+ // this device so the pipelines are created once.
292
+ std::shared_ptr<VideoFrameBlit> _videoFrameBlit =
293
+ std::make_shared<VideoFrameBlit>();
288
294
  // Guards the device-lost state below. getLost() runs on a JS thread, but
289
295
  // Dawn's AllowSpontaneous device-lost callback (and device destruction) can
290
296
  // fire notifyDeviceLost() from other threads, so the mutex keeps these
@@ -1,10 +1,16 @@
1
1
  #include "GPUQueue.h"
2
2
 
3
+ #include <algorithm>
4
+ #include <cmath>
3
5
  #include <limits>
4
6
  #include <memory>
7
+ #include <string>
8
+ #include <utility>
5
9
  #include <vector>
6
10
 
7
11
  #include "Convertors.h"
12
+ #include "ImageBitmap.h"
13
+ #include "PlatformContext.h"
8
14
 
9
15
  namespace rnwgpu {
10
16
 
@@ -103,6 +109,68 @@ async::AsyncTaskHandle GPUQueue::onSubmittedWorkDone(jsi::Runtime &runtime) {
103
109
  });
104
110
  }
105
111
 
112
+ void GPUQueue::copyVideoFrameToTexture(
113
+ const GPUImageCopyExternalImage &source,
114
+ const GPUImageCopyTextureTagged &destination, const wgpu::Extent3D &size) {
115
+ if (!destination.texture) {
116
+ throw std::runtime_error(
117
+ "copyExternalImageToTexture: destination.texture is required");
118
+ }
119
+ if (destination.aspect.value_or(wgpu::TextureAspect::All) !=
120
+ wgpu::TextureAspect::All) {
121
+ throw std::runtime_error(
122
+ "copyExternalImageToTexture: a native frame can only be copied into "
123
+ "the color aspect");
124
+ }
125
+ if (size.depthOrArrayLayers > 1) {
126
+ throw std::runtime_error(
127
+ "copyExternalImageToTexture: a native frame is a single 2D image");
128
+ }
129
+ constexpr double kMaxCoordinate =
130
+ static_cast<double>(std::numeric_limits<uint32_t>::max());
131
+ auto coordinate = [&](double value, const char *name) {
132
+ if (!(value >= 0) || value > kMaxCoordinate) {
133
+ throw std::runtime_error(std::string("copyExternalImageToTexture: ") +
134
+ name +
135
+ " must be a non-negative integer coordinate");
136
+ }
137
+ return static_cast<uint32_t>(value);
138
+ };
139
+ const double rotation = source.rotation.value_or(0);
140
+ if (rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270) {
141
+ throw std::runtime_error(
142
+ "copyExternalImageToTexture: rotation must be 0, 90, 180 or 270");
143
+ }
144
+
145
+ VideoFrameBlit::Request request;
146
+ request.frame = source.videoFrame;
147
+ if (const auto origin = source.origin.value_or(nullptr)) {
148
+ request.originX = coordinate(origin->x, "origin.x");
149
+ request.originY = coordinate(origin->y, "origin.y");
150
+ }
151
+ request.width = size.width;
152
+ request.height = size.height;
153
+ request.flipY = source.flipY.value_or(false);
154
+ request.rotation = rotation;
155
+ request.mirrored = source.mirrored.value_or(false);
156
+ request.texture = destination.texture->get();
157
+ request.mipLevel = coordinate(destination.mipLevel.value_or(0), "mipLevel");
158
+ wgpu::Origin3D dstOrigin{};
159
+ Convertor conv;
160
+ if (!conv(dstOrigin, destination.origin)) {
161
+ throw std::runtime_error(
162
+ "copyExternalImageToTexture: invalid destination origin");
163
+ }
164
+ if (dstOrigin.z != 0) {
165
+ throw std::runtime_error(
166
+ "copyExternalImageToTexture: a native frame can only be copied into "
167
+ "the first layer of the texture");
168
+ }
169
+ request.dstX = dstOrigin.x;
170
+ request.dstY = dstOrigin.y;
171
+ _videoFrameBlit->copy(_device, _instance, request);
172
+ }
173
+
106
174
  void GPUQueue::copyExternalImageToTexture(
107
175
  std::shared_ptr<GPUImageCopyExternalImage> source,
108
176
  std::shared_ptr<GPUImageCopyTextureTagged> destination,
@@ -111,6 +179,17 @@ void GPUQueue::copyExternalImageToTexture(
111
179
  wgpu::TexelCopyBufferLayout layout{};
112
180
  wgpu::Extent3D sz{};
113
181
  Convertor conv;
182
+ if (source->videoFrame) {
183
+ if (!conv(sz, size)) {
184
+ throw std::runtime_error("copyExternalImageToTexture: invalid copy size");
185
+ }
186
+ copyVideoFrameToTexture(*source, *destination, sz);
187
+ return;
188
+ }
189
+ if (!source->source) {
190
+ throw std::runtime_error("copyExternalImageToTexture: the source must be "
191
+ "an ImageBitmap or a NativeVideoFrame");
192
+ }
114
193
  uint32_t bytesPerPixel =
115
194
  source->source->getSize() /
116
195
  (source->source->getWidth() * source->source->getHeight());
@@ -139,10 +218,8 @@ void GPUQueue::copyExternalImageToTexture(
139
218
  throw std::runtime_error(
140
219
  "The source origin must be a non-negative integer coordinate.");
141
220
  }
142
- const size_t sourceOriginX =
143
- origin ? static_cast<size_t>(origin->x) : 0;
144
- const size_t sourceOriginY =
145
- origin ? static_cast<size_t>(origin->y) : 0;
221
+ const size_t sourceOriginX = origin ? static_cast<size_t>(origin->x) : 0;
222
+ const size_t sourceOriginY = origin ? static_cast<size_t>(origin->y) : 0;
146
223
  if (sourceOriginX > source->source->getWidth() ||
147
224
  sz.width > source->source->getWidth() - sourceOriginX ||
148
225
  sourceOriginY > source->source->getHeight() ||
@@ -193,6 +270,186 @@ void GPUQueue::copyExternalImageToTexture(
193
270
  }
194
271
  }
195
272
 
273
+ async::AsyncTaskHandle GPUQueue::drawElementImageToTexture(
274
+ jsi::Runtime &runtime, std::shared_ptr<GPUDrawElementImageSource> source,
275
+ std::shared_ptr<GPUDrawElementImageDestination> destination) {
276
+ auto platform = PlatformContext::current();
277
+ if (!platform) {
278
+ throw std::runtime_error(
279
+ "drawElementImageToTexture: react-native-webgpu is not installed");
280
+ }
281
+ if (!destination || !destination->info || !destination->info->texture) {
282
+ throw std::runtime_error(
283
+ "drawElementImageToTexture: `destination.texture` is required");
284
+ }
285
+ const auto &info = destination->info;
286
+
287
+ // Destination texture: only the 8-bit RGBA/BGRA formats the platform
288
+ // rasterizers produce natively are accepted (with a byte swizzle between
289
+ // the two); anything else would need a GPU blit.
290
+ wgpu::TexelCopyTextureInfo dst{};
291
+ Convertor conv;
292
+ if (!conv(dst.aspect, info->aspect) || !conv(dst.mipLevel, info->mipLevel) ||
293
+ !conv(dst.origin, info->origin) || !conv(dst.texture, info->texture)) {
294
+ throw std::runtime_error("drawElementImageToTexture: invalid destination");
295
+ }
296
+ const wgpu::Texture texture = info->texture->get();
297
+ bool destinationIsBgra = false;
298
+ switch (texture.GetFormat()) {
299
+ case wgpu::TextureFormat::RGBA8Unorm:
300
+ case wgpu::TextureFormat::RGBA8UnormSrgb:
301
+ destinationIsBgra = false;
302
+ break;
303
+ case wgpu::TextureFormat::BGRA8Unorm:
304
+ case wgpu::TextureFormat::BGRA8UnormSrgb:
305
+ destinationIsBgra = true;
306
+ break;
307
+ default:
308
+ throw std::runtime_error(
309
+ "drawElementImageToTexture: the destination texture must be "
310
+ "rgba8unorm, rgba8unorm-srgb, bgra8unorm or bgra8unorm-srgb");
311
+ }
312
+ if (!(texture.GetUsage() & wgpu::TextureUsage::CopyDst)) {
313
+ throw std::runtime_error(
314
+ "drawElementImageToTexture: the destination texture must have "
315
+ "GPUTextureUsage.COPY_DST");
316
+ }
317
+ if (texture.GetDimension() != wgpu::TextureDimension::e2D ||
318
+ texture.GetSampleCount() != 1) {
319
+ throw std::runtime_error(
320
+ "drawElementImageToTexture: the destination must be a single-sampled "
321
+ "2D texture");
322
+ }
323
+ if (dst.mipLevel >= texture.GetMipLevelCount()) {
324
+ throw std::runtime_error(
325
+ "drawElementImageToTexture: destination.mipLevel is out of range");
326
+ }
327
+ const uint32_t mipWidth =
328
+ std::max<uint32_t>(1, texture.GetWidth() >> dst.mipLevel);
329
+ const uint32_t mipHeight =
330
+ std::max<uint32_t>(1, texture.GetHeight() >> dst.mipLevel);
331
+ if (dst.origin.z >= texture.GetDepthOrArrayLayers()) {
332
+ throw std::runtime_error(
333
+ "drawElementImageToTexture: destination.origin.z is out of range");
334
+ }
335
+
336
+ // Source rectangle (points, view space). Omitted width/height mean "the
337
+ // whole view", which only the platform knows.
338
+ ViewSnapshotRequest request{};
339
+ request.viewTag = source->viewTag;
340
+ request.sourceX = source->sourceX.value_or(0.0);
341
+ request.sourceY = source->sourceY.value_or(0.0);
342
+ request.sourceWidth = source->sourceWidth.value_or(0.0);
343
+ request.sourceHeight = source->sourceHeight.value_or(0.0);
344
+ if (!std::isfinite(request.sourceX) || !std::isfinite(request.sourceY) ||
345
+ !std::isfinite(request.sourceWidth) ||
346
+ !std::isfinite(request.sourceHeight) ||
347
+ (source->sourceWidth.has_value() && request.sourceWidth <= 0) ||
348
+ (source->sourceHeight.has_value() && request.sourceHeight <= 0)) {
349
+ throw std::runtime_error(
350
+ "drawElementImageToTexture: the source rectangle must be finite with "
351
+ "a positive width and height");
352
+ }
353
+
354
+ // Destination size (pixels). Omitted means the source rectangle's natural
355
+ // pixel size (points times the device pixel ratio), which the platform
356
+ // computes; the bounds check then happens once the pixels are back.
357
+ if (destination->size.has_value()) {
358
+ wgpu::Extent3D size{};
359
+ if (!conv(size, destination->size.value())) {
360
+ throw std::runtime_error(
361
+ "drawElementImageToTexture: invalid destination.size");
362
+ }
363
+ if (size.width == 0 || size.height == 0 || size.depthOrArrayLayers != 1) {
364
+ throw std::runtime_error(
365
+ "drawElementImageToTexture: destination.size must have a positive "
366
+ "width and height and a depthOrArrayLayers of 1");
367
+ }
368
+ if (size.width > mipWidth - std::min(dst.origin.x, mipWidth) ||
369
+ size.height > mipHeight - std::min(dst.origin.y, mipHeight)) {
370
+ throw std::runtime_error(
371
+ "drawElementImageToTexture: destination.origin + destination.size "
372
+ "exceeds the texture's extent at destination.mipLevel");
373
+ }
374
+ request.width = size.width;
375
+ request.height = size.height;
376
+ }
377
+
378
+ // premultipliedAlpha defaults to false, like copyExternalImageToTexture.
379
+ const bool destinationPremultiplied =
380
+ info->premultipliedAlpha.value_or(false);
381
+
382
+ // Settle on the CALLING runtime's context (see GPUBuffer::mapAsync): the
383
+ // snapshot completes on the UI thread and is deposited into that context's
384
+ // mailbox; the texture write and the resolve then run on the runtime's own
385
+ // thread during its next tick.
386
+ auto context =
387
+ async::RuntimeContext::getOrCreate(runtime, _async->instance());
388
+ auto queue = _instance;
389
+ // Keeps the destination texture alive until the write is issued.
390
+ auto gpuTexture = info->texture;
391
+ return context->postTask(
392
+ [platform, request, dst, mipWidth, mipHeight, destinationIsBgra,
393
+ destinationPremultiplied, queue,
394
+ gpuTexture](const async::AsyncTaskHandle::ResolveFunction &resolve,
395
+ const async::AsyncTaskHandle::RejectFunction &reject) {
396
+ platform->snapshotView(
397
+ request,
398
+ [resolve, reject, dst, mipWidth, mipHeight, destinationIsBgra,
399
+ destinationPremultiplied, queue,
400
+ gpuTexture](ImageData image) mutable {
401
+ // Arbitrary (UI) thread: validate without touching JSI.
402
+ if (image.width == 0 || image.height == 0 ||
403
+ image.data.size() < image.width * image.height * 4) {
404
+ reject("drawElementImageToTexture: the view produced no "
405
+ "pixels (is it mounted with a non-zero size?)");
406
+ return;
407
+ }
408
+ if (image.width >
409
+ mipWidth - std::min<uint32_t>(dst.origin.x, mipWidth) ||
410
+ image.height >
411
+ mipHeight - std::min<uint32_t>(dst.origin.y, mipHeight)) {
412
+ reject("drawElementImageToTexture: the view's natural pixel "
413
+ "size (" +
414
+ std::to_string(image.width) + "x" +
415
+ std::to_string(image.height) +
416
+ ") does not fit in the destination texture at "
417
+ "destination.origin; pass destination.size to scale "
418
+ "it, or create a larger texture");
419
+ return;
420
+ }
421
+ resolve([image = std::move(image), dst, destinationIsBgra,
422
+ destinationPremultiplied, queue,
423
+ gpuTexture](jsi::Runtime &) mutable -> jsi::Value {
424
+ // Owning runtime's thread. Bring the pixels into the
425
+ // destination's channel order and alpha representation, then
426
+ // issue the write.
427
+ const bool sourceIsBgra =
428
+ image.format == wgpu::TextureFormat::BGRA8Unorm ||
429
+ image.format == wgpu::TextureFormat::BGRA8UnormSrgb;
430
+ uint8_t *pixels = image.data.data();
431
+ const size_t byteLength = image.width * image.height * 4;
432
+ if (sourceIsBgra != destinationIsBgra) {
433
+ for (size_t i = 0; i + 3 < byteLength; i += 4) {
434
+ std::swap(pixels[i], pixels[i + 2]);
435
+ }
436
+ }
437
+ convertAlpha(pixels, byteLength, image.premultiplied,
438
+ destinationPremultiplied);
439
+ wgpu::TexelCopyBufferLayout layout{};
440
+ layout.offset = 0;
441
+ layout.bytesPerRow = static_cast<uint32_t>(image.width * 4);
442
+ layout.rowsPerImage = static_cast<uint32_t>(image.height);
443
+ wgpu::Extent3D extent{static_cast<uint32_t>(image.width),
444
+ static_cast<uint32_t>(image.height), 1};
445
+ queue.WriteTexture(&dst, pixels, byteLength, &layout, &extent);
446
+ return jsi::Value::undefined();
447
+ });
448
+ },
449
+ [reject](std::string error) { reject(std::move(error)); });
450
+ });
451
+ }
452
+
196
453
  void GPUQueue::writeTexture(std::shared_ptr<GPUImageCopyTexture> destination,
197
454
  std::shared_ptr<ArrayBuffer> data,
198
455
  std::shared_ptr<GPUImageDataLayout> dataLayout,
@@ -16,8 +16,11 @@
16
16
  #include "ArrayBuffer.h"
17
17
  #include "GPUBuffer.h"
18
18
  #include "GPUCommandBuffer.h"
19
+ #include "GPUDrawElementImageDestination.h"
20
+ #include "GPUDrawElementImageSource.h"
19
21
  #include "GPUImageCopyExternalImage.h"
20
22
  #include "GPUImageCopyTextureTagged.h"
23
+ #include "VideoFrameBlit.h"
21
24
 
22
25
  namespace rnwgpu {
23
26
 
@@ -27,10 +30,12 @@ class GPUQueue : public NativeObject<GPUQueue> {
27
30
  public:
28
31
  static constexpr const char *CLASS_NAME = "GPUQueue";
29
32
 
30
- explicit GPUQueue(wgpu::Queue instance,
33
+ explicit GPUQueue(wgpu::Device device, wgpu::Queue instance,
31
34
  std::shared_ptr<async::RuntimeContext> async,
35
+ std::shared_ptr<VideoFrameBlit> videoFrameBlit,
32
36
  std::string label)
33
- : NativeObject(CLASS_NAME), _instance(instance), _async(async),
37
+ : NativeObject(CLASS_NAME), _device(device), _instance(instance),
38
+ _async(async), _videoFrameBlit(std::move(videoFrameBlit)),
34
39
  _label(label) {}
35
40
 
36
41
  public:
@@ -46,11 +51,25 @@ public:
46
51
  std::shared_ptr<ArrayBuffer> data,
47
52
  std::shared_ptr<GPUImageDataLayout> dataLayout,
48
53
  std::shared_ptr<GPUExtent3D> size);
54
+ // The source is an ImageBitmap (uploaded from the CPU) or, as a React
55
+ // Native extension, a NativeVideoFrame rendered into the destination through
56
+ // an external texture (see VideoFrameBlit).
49
57
  void copyExternalImageToTexture(
50
58
  std::shared_ptr<GPUImageCopyExternalImage> source,
51
59
  std::shared_ptr<GPUImageCopyTextureTagged> destination,
52
60
  std::shared_ptr<GPUExtent3D> copySize);
53
61
 
62
+ // Non-spec React Native extension modeled on the html-in-canvas proposal's
63
+ // GPUQueue.drawElementImageToTexture: rasterizes a native view (the
64
+ // "element") and writes the pixels into `destination.texture`. Unlike the
65
+ // web API it returns a Promise, because the view can only be rasterized on
66
+ // the platform UI thread; the texture write is issued on the calling
67
+ // runtime's thread right before the promise resolves, so work submitted
68
+ // after `await` observes the new contents.
69
+ async::AsyncTaskHandle drawElementImageToTexture(
70
+ jsi::Runtime &runtime, std::shared_ptr<GPUDrawElementImageSource> source,
71
+ std::shared_ptr<GPUDrawElementImageDestination> destination);
72
+
54
73
  std::string getLabel() { return _label; }
55
74
  void setLabel(const std::string &label) {
56
75
  _label = label;
@@ -66,6 +85,8 @@ public:
66
85
  installMethod(runtime, prototype, "writeTexture", &GPUQueue::writeTexture);
67
86
  installMethod(runtime, prototype, "copyExternalImageToTexture",
68
87
  &GPUQueue::copyExternalImageToTexture);
88
+ installMethodWithRuntime(runtime, prototype, "drawElementImageToTexture",
89
+ &GPUQueue::drawElementImageToTexture);
69
90
  installGetterSetter(runtime, prototype, "label", &GPUQueue::getLabel,
70
91
  &GPUQueue::setLabel);
71
92
  }
@@ -73,8 +94,14 @@ public:
73
94
  inline const wgpu::Queue get() { return _instance; }
74
95
 
75
96
  private:
97
+ void copyVideoFrameToTexture(const GPUImageCopyExternalImage &source,
98
+ const GPUImageCopyTextureTagged &destination,
99
+ const wgpu::Extent3D &size);
100
+
101
+ wgpu::Device _device;
76
102
  wgpu::Queue _instance;
77
103
  std::shared_ptr<async::RuntimeContext> _async;
104
+ std::shared_ptr<VideoFrameBlit> _videoFrameBlit;
78
105
  std::string _label;
79
106
  };
80
107