react-native-webgpu 0.15.0 → 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.
@@ -42,159 +42,279 @@ ApplePlatformContext::ApplePlatformContext(ViewLookup viewLookup)
42
42
 
43
43
  namespace {
44
44
 
45
- // Rasterize `request` on the main thread into tightly packed, premultiplied
46
- // BGRA8 pixels. Throws std::runtime_error with a user-facing message.
47
- ImageData snapshotViewOnMainThread(const ApplePlatformContext::ViewLookup &lookup,
48
- const ViewSnapshotRequest &request) {
45
+ // A view that UIKit declined to render (it is not in a window). The pixel
46
+ // path would fail the same way, so there is no point falling back to it.
47
+ struct ViewNotRenderable : std::runtime_error {
48
+ using std::runtime_error::runtime_error;
49
+ };
50
+
51
+ // The view, the output size and the rectangle to draw it in, resolved from a
52
+ // request on the main thread. Throws std::runtime_error with a user-facing
53
+ // message.
54
+ struct ResolvedSnapshot {
55
+ RNWGPlatformView *view = nil;
56
+ CGRect bounds = CGRectZero;
57
+ // The source rectangle in points (view space).
58
+ double sourceX = 0;
59
+ double sourceY = 0;
60
+ double sourceWidth = 0;
61
+ double sourceHeight = 0;
62
+ // The output size in pixels.
63
+ uint32_t width = 0;
64
+ uint32_t height = 0;
65
+ CGFloat scaleX = 1;
66
+ CGFloat scaleY = 1;
67
+ // The view's bounds, scaled and offset so that the source rectangle covers
68
+ // the whole output, in pixels and with UIKit's top-left origin.
69
+ CGRect drawRect = CGRectZero;
70
+ };
71
+
72
+ ResolvedSnapshot resolveSnapshot(const ApplePlatformContext::ViewLookup &lookup,
73
+ const ViewSnapshotRequest &request) {
49
74
  if (!lookup) {
50
75
  throw std::runtime_error(
51
76
  "drawElementImageToTexture: no view registry is available");
52
77
  }
53
- RNWGPlatformView *view = (__bridge RNWGPlatformView *)lookup(request.viewTag);
54
- if (view == nil) {
78
+ ResolvedSnapshot snapshot;
79
+ snapshot.view = (__bridge RNWGPlatformView *)lookup(request.viewTag);
80
+ if (snapshot.view == nil) {
55
81
  throw std::runtime_error(
56
82
  "drawElementImageToTexture: no native view found for tag " +
57
83
  std::to_string(request.viewTag) +
58
84
  " (is the view mounted, and rendered with collapsable={false}?)");
59
85
  }
60
- const CGRect bounds = view.bounds;
86
+ snapshot.bounds = snapshot.view.bounds;
87
+ const CGRect bounds = snapshot.bounds;
61
88
  if (bounds.size.width <= 0 || bounds.size.height <= 0) {
62
89
  throw std::runtime_error(
63
90
  "drawElementImageToTexture: the view has no size yet");
64
91
  }
65
92
 
66
93
  // Source rectangle in points (view space); the whole view by default.
67
- const double sourceX = request.sourceX;
68
- const double sourceY = request.sourceY;
69
- const double sourceWidth =
94
+ snapshot.sourceX = request.sourceX;
95
+ snapshot.sourceY = request.sourceY;
96
+ snapshot.sourceWidth =
70
97
  request.sourceWidth > 0 ? request.sourceWidth : bounds.size.width;
71
- const double sourceHeight =
98
+ snapshot.sourceHeight =
72
99
  request.sourceHeight > 0 ? request.sourceHeight : bounds.size.height;
73
100
 
74
101
  // Natural pixel size: points times the screen scale the view is shown at.
75
102
  #if !TARGET_OS_OSX
76
- CGFloat scale = view.window.screen.scale;
103
+ CGFloat scale = snapshot.view.window.screen.scale;
77
104
  if (scale <= 0) {
78
105
  scale = UIScreen.mainScreen.scale;
79
106
  }
80
107
  #else
81
- CGFloat scale = view.window.backingScaleFactor;
108
+ CGFloat scale = snapshot.view.window.backingScaleFactor;
82
109
  if (scale <= 0) {
83
110
  scale = NSScreen.mainScreen.backingScaleFactor;
84
111
  }
85
112
  #endif
86
- const uint32_t width =
113
+ snapshot.width =
87
114
  request.width > 0
88
115
  ? request.width
89
- : static_cast<uint32_t>(std::llround(sourceWidth * scale));
90
- const uint32_t height =
116
+ : static_cast<uint32_t>(std::llround(snapshot.sourceWidth * scale));
117
+ snapshot.height =
91
118
  request.height > 0
92
119
  ? request.height
93
- : static_cast<uint32_t>(std::llround(sourceHeight * scale));
94
- if (width == 0 || height == 0) {
120
+ : static_cast<uint32_t>(std::llround(snapshot.sourceHeight * scale));
121
+ if (snapshot.width == 0 || snapshot.height == 0) {
95
122
  throw std::runtime_error(
96
123
  "drawElementImageToTexture: the source rectangle is empty");
97
124
  }
98
125
 
99
126
  // The view's bounds are drawn scaled so that the source rectangle covers
100
127
  // the whole output.
101
- const CGFloat scaleX = static_cast<CGFloat>(width) / sourceWidth;
102
- const CGFloat scaleY = static_cast<CGFloat>(height) / sourceHeight;
103
- const CGRect drawRect =
104
- CGRectMake(-sourceX * scaleX, -sourceY * scaleY,
105
- bounds.size.width * scaleX, bounds.size.height * scaleY);
128
+ snapshot.scaleX = static_cast<CGFloat>(snapshot.width) / snapshot.sourceWidth;
129
+ snapshot.scaleY =
130
+ static_cast<CGFloat>(snapshot.height) / snapshot.sourceHeight;
131
+ snapshot.drawRect = CGRectMake(-snapshot.sourceX * snapshot.scaleX,
132
+ -snapshot.sourceY * snapshot.scaleY,
133
+ bounds.size.width * snapshot.scaleX,
134
+ bounds.size.height * snapshot.scaleY);
135
+ return snapshot;
136
+ }
137
+
138
+ // A premultiplied BGRA8 Core Graphics context over `pixels`, the layout both
139
+ // snapshot paths produce. Returns NULL when Core Graphics rejects it.
140
+ CGContextRef createBgraContext(void *pixels, uint32_t width, uint32_t height,
141
+ size_t bytesPerRow) {
142
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
143
+ CGContextRef context = CGBitmapContextCreate(
144
+ pixels, width, height, 8, bytesPerRow, colorSpace,
145
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
146
+ CGColorSpaceRelease(colorSpace);
147
+ return context;
148
+ }
106
149
 
107
- CGImageRef cgImage = NULL;
108
150
  #if !TARGET_OS_OSX
109
- // drawViewHierarchyInRect renders what is on screen (including Metal /
110
- // CAMetalLayer content), which is what "the element as displayed" means.
111
- // afterScreenUpdates:YES flushes pending layout and layer changes first, so
112
- // a snapshot taken right after a state change reflects that change.
113
- UIGraphicsImageRendererFormat *format =
114
- [UIGraphicsImageRendererFormat defaultFormat];
115
- format.scale = 1.0;
116
- format.opaque = NO;
117
- format.preferredRange = UIGraphicsImageRendererFormatRangeStandard;
118
- UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc]
119
- initWithSize:CGSizeMake(width, height)
120
- format:format];
121
- // drawViewHierarchyInRect returns NO and draws nothing when the view is not
122
- // in a window (e.g. a screen pushed under another one). The image would
123
- // then be fully transparent, so treat it as a failure instead.
124
- __block BOOL drawn = NO;
125
- UIImage *image = [renderer
126
- imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) {
127
- drawn = [view drawViewHierarchyInRect:drawRect afterScreenUpdates:YES];
128
- }];
151
+ // Draws the view hierarchy through `context`, a bitmap context of exactly
152
+ // `snapshot.width` x `snapshot.height` pixels (Core Graphics orientation; the
153
+ // flip to UIKit's top-left origin is applied here).
154
+ //
155
+ // drawViewHierarchyInRect renders what is on screen (including Metal /
156
+ // CAMetalLayer content), which is what "the element as displayed" means.
157
+ // afterScreenUpdates:YES flushes pending layout and layer changes first, so a
158
+ // snapshot taken right after a state change reflects that change; NO draws
159
+ // the last committed frame and skips that round trip to the render server.
160
+ //
161
+ // drawViewHierarchyInRect returns NO and draws nothing when the view is not
162
+ // in a window (e.g. a screen pushed under another one). The output would then
163
+ // be fully transparent, so that is reported as a failure instead.
164
+ void drawViewHierarchy(const ResolvedSnapshot &snapshot, CGContextRef context,
165
+ bool afterScreenUpdates) {
166
+ CGContextSaveGState(context);
167
+ CGContextTranslateCTM(context, 0, snapshot.height);
168
+ CGContextScaleCTM(context, 1, -1);
169
+ UIGraphicsPushContext(context);
170
+ const BOOL drawn =
171
+ [snapshot.view drawViewHierarchyInRect:snapshot.drawRect
172
+ afterScreenUpdates:afterScreenUpdates ? YES : NO];
173
+ UIGraphicsPopContext();
174
+ CGContextRestoreGState(context);
129
175
  if (!drawn) {
130
- throw std::runtime_error(
176
+ throw ViewNotRenderable(
131
177
  "drawElementImageToTexture: the view could not be rendered (is it "
132
178
  "attached to a window?)");
133
179
  }
134
- cgImage = image.CGImage;
135
- if (cgImage != NULL) {
136
- CGImageRetain(cgImage);
137
- }
138
- #else
139
- NSBitmapImageRep *rep = [view bitmapImageRepForCachingDisplayInRect:bounds];
140
- if (rep != nil) {
141
- [view cacheDisplayInRect:bounds toBitmapImageRep:rep];
142
- cgImage = rep.CGImage;
143
- if (cgImage != NULL) {
144
- CGImageRetain(cgImage);
180
+ }
181
+
182
+ // Releases a pixel buffer when it goes out of scope.
183
+ struct PixelBufferRelease {
184
+ CVPixelBufferRef buffer;
185
+ ~PixelBufferRelease() {
186
+ if (buffer != NULL) {
187
+ CFRelease(buffer);
145
188
  }
146
189
  }
147
- #endif
148
- if (cgImage == NULL) {
190
+ };
191
+
192
+ // The zero-copy path: renders the view into an IOSurface-backed BGRA pixel
193
+ // buffer, which the caller imports as shared texture memory and draws into
194
+ // the destination on the GPU (VideoFrameBlit, which also converts the
195
+ // premultiplied pixels to straight alpha when asked). UIKit rasterizes
196
+ // straight into the surface's memory through a Core Graphics context, so the
197
+ // pixels are never copied or converted on the CPU. Throws on an allocation
198
+ // failure, which the caller answers with the pixel path.
199
+ VideoFrameHandle renderViewIntoSurface(const ResolvedSnapshot &snapshot,
200
+ bool afterScreenUpdates) {
201
+ NSDictionary *attributes = @{
202
+ (NSString *)kCVPixelBufferIOSurfacePropertiesKey : @{},
203
+ (NSString *)kCVPixelBufferMetalCompatibilityKey : @YES,
204
+ };
205
+ CVPixelBufferRef pixelBuffer = NULL;
206
+ const CVReturn created =
207
+ CVPixelBufferCreate(kCFAllocatorDefault, snapshot.width, snapshot.height,
208
+ kCVPixelFormatType_32BGRA,
209
+ (__bridge CFDictionaryRef)attributes, &pixelBuffer);
210
+ if (created != kCVReturnSuccess || pixelBuffer == NULL) {
149
211
  throw std::runtime_error(
150
- "drawElementImageToTexture: the view could not be rendered");
212
+ "drawElementImageToTexture: could not allocate an IOSurface for the "
213
+ "view (CVPixelBufferCreate returned " +
214
+ std::to_string(created) + ")");
151
215
  }
216
+ // wrapCVPixelBuffer retains its own reference for the frame.
217
+ PixelBufferRelease release{pixelBuffer};
152
218
 
153
- // Normalize into premultiplied BGRA8 with no row padding, whatever the
154
- // renderer produced.
219
+ if (CVPixelBufferLockBaseAddress(pixelBuffer, 0) != kCVReturnSuccess) {
220
+ throw std::runtime_error(
221
+ "drawElementImageToTexture: could not lock the IOSurface");
222
+ }
223
+ CGContextRef context = createBgraContext(
224
+ CVPixelBufferGetBaseAddress(pixelBuffer), snapshot.width, snapshot.height,
225
+ CVPixelBufferGetBytesPerRow(pixelBuffer));
226
+ if (context == NULL) {
227
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
228
+ throw std::runtime_error(
229
+ "drawElementImageToTexture: could not draw into the IOSurface");
230
+ }
231
+ try {
232
+ // A fresh surface holds whatever was in that memory, and the view may be
233
+ // transparent.
234
+ CGContextClearRect(context,
235
+ CGRectMake(0, 0, snapshot.width, snapshot.height));
236
+ drawViewHierarchy(snapshot, context, afterScreenUpdates);
237
+ } catch (...) {
238
+ CGContextRelease(context);
239
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
240
+ throw;
241
+ }
242
+ CGContextRelease(context);
243
+ // Unlocking publishes the CPU writes to the GPU.
244
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
245
+ return wrapCVPixelBuffer(pixelBuffer);
246
+ }
247
+ #endif
248
+
249
+ // The pixel path: rasterizes the view into tightly packed, premultiplied
250
+ // BGRA8 pixels that the caller uploads with writeTexture.
251
+ ImageData renderViewIntoPixels(const ResolvedSnapshot &snapshot,
252
+ bool afterScreenUpdates) {
155
253
  ImageData result;
156
- result.width = width;
157
- result.height = height;
254
+ result.width = snapshot.width;
255
+ result.height = snapshot.height;
158
256
  result.format = wgpu::TextureFormat::BGRA8Unorm;
159
257
  result.premultiplied = true;
160
- result.data.assign(static_cast<size_t>(width) * height * 4, 0);
161
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
162
- CGContextRef context = CGBitmapContextCreate(
163
- result.data.data(), width, height, 8, static_cast<size_t>(width) * 4,
164
- colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
165
- CGColorSpaceRelease(colorSpace);
258
+ // Zeroed: the view may be transparent.
259
+ result.data.assign(static_cast<size_t>(snapshot.width) * snapshot.height * 4,
260
+ 0);
261
+ CGContextRef context =
262
+ createBgraContext(result.data.data(), snapshot.width, snapshot.height,
263
+ static_cast<size_t>(snapshot.width) * 4);
166
264
  if (context == NULL) {
167
- CGImageRelease(cgImage);
168
265
  throw std::runtime_error(
169
266
  "drawElementImageToTexture: could not allocate the pixel buffer");
170
267
  }
171
268
  #if !TARGET_OS_OSX
172
- // The renderer already produced exactly width x height pixels.
173
- const CGRect imageRect = CGRectMake(0, 0, width, height);
269
+ // UIKit draws straight into the vector; no intermediate image.
270
+ try {
271
+ drawViewHierarchy(snapshot, context, afterScreenUpdates);
272
+ } catch (...) {
273
+ CGContextRelease(context);
274
+ throw;
275
+ }
174
276
  #else
277
+ (void)afterScreenUpdates;
278
+ CGImageRef cgImage = NULL;
279
+ NSBitmapImageRep *rep =
280
+ [snapshot.view bitmapImageRepForCachingDisplayInRect:snapshot.bounds];
281
+ if (rep != nil) {
282
+ [snapshot.view cacheDisplayInRect:snapshot.bounds toBitmapImageRep:rep];
283
+ cgImage = rep.CGImage;
284
+ if (cgImage != NULL) {
285
+ CGImageRetain(cgImage);
286
+ }
287
+ }
288
+ if (cgImage == NULL) {
289
+ CGContextRelease(context);
290
+ throw std::runtime_error(
291
+ "drawElementImageToTexture: the view could not be rendered");
292
+ }
175
293
  // The cached display covers the whole view at the backing scale; draw it so
176
294
  // that the source rectangle fills the output. CoreGraphics' origin is the
177
295
  // bottom-left corner, hence the flipped vertical offset.
178
- const CGRect imageRect = CGRectMake(
179
- -sourceX * scaleX,
180
- -(bounds.size.height - sourceY - sourceHeight) * scaleY,
181
- bounds.size.width * scaleX, bounds.size.height * scaleY);
182
- #endif
296
+ const CGRect imageRect =
297
+ CGRectMake(-snapshot.sourceX * snapshot.scaleX,
298
+ -(snapshot.bounds.size.height - snapshot.sourceY -
299
+ snapshot.sourceHeight) *
300
+ snapshot.scaleY,
301
+ snapshot.bounds.size.width * snapshot.scaleX,
302
+ snapshot.bounds.size.height * snapshot.scaleY);
183
303
  CGContextSetBlendMode(context, kCGBlendModeCopy);
184
304
  CGContextDrawImage(context, imageRect, cgImage);
185
- CGContextRelease(context);
186
305
  CGImageRelease(cgImage);
306
+ #endif
307
+ CGContextRelease(context);
187
308
  return result;
188
309
  }
189
310
 
190
311
  } // namespace
191
312
 
192
- // Always delivers pixels: the view is drawn into a CPU bitmap, so there is no
193
- // GPU frame to hand over (onFrame is unused).
313
+ // On iOS a caller that can draw a GPU frame (allowFrame) gets the view
314
+ // rendered into an IOSurface; everything else, and macOS, gets pixels.
194
315
  void ApplePlatformContext::snapshotView(
195
- const ViewSnapshotRequest &request,
196
- std::function<void(ImageData)> onPixels,
197
- std::function<void(VideoFrameHandle)> /* onFrame */,
316
+ const ViewSnapshotRequest &request, std::function<void(ImageData)> onPixels,
317
+ std::function<void(VideoFrameHandle)> onFrame,
198
318
  std::function<void(std::string)> onError) {
199
319
  // Copies: the block outlives this call.
200
320
  ViewLookup lookup = _viewLookup;
@@ -202,7 +322,29 @@ void ApplePlatformContext::snapshotView(
202
322
  dispatch_async(dispatch_get_main_queue(), ^{
203
323
  @autoreleasepool {
204
324
  try {
205
- onPixels(snapshotViewOnMainThread(lookup, snapshotRequest));
325
+ const ResolvedSnapshot snapshot =
326
+ resolveSnapshot(lookup, snapshotRequest);
327
+ #if !TARGET_OS_OSX
328
+ if (snapshotRequest.allowFrame) {
329
+ try {
330
+ onFrame(renderViewIntoSurface(snapshot,
331
+ snapshotRequest.afterScreenUpdates));
332
+ return;
333
+ } catch (const ViewNotRenderable &) {
334
+ throw;
335
+ } catch (const std::exception &error) {
336
+ // An IOSurface could not be set up; the pixel path draws the
337
+ // same view.
338
+ NSLog(@"[WebGPU] drawElementImageToTexture: %s; reading the "
339
+ @"pixels back instead",
340
+ error.what());
341
+ }
342
+ }
343
+ #else
344
+ (void)onFrame;
345
+ #endif
346
+ onPixels(
347
+ renderViewIntoPixels(snapshot, snapshotRequest.afterScreenUpdates));
206
348
  } catch (const std::exception &error) {
207
349
  onError(error.what());
208
350
  } catch (...) {
@@ -325,12 +467,10 @@ void ApplePlatformContext::createImageBitmapFromDataAsync(
325
467
  });
326
468
  }
327
469
 
328
- VideoFrameHandle
329
- ApplePlatformContext::loadVideoFrame(const std::string &path) {
470
+ VideoFrameHandle ApplePlatformContext::loadVideoFrame(const std::string &path) {
330
471
  NSString *nsPath = [NSString stringWithUTF8String:path.c_str()];
331
- NSURL *url = [nsPath hasPrefix:@"file://"]
332
- ? [NSURL URLWithString:nsPath]
333
- : [NSURL fileURLWithPath:nsPath];
472
+ NSURL *url = [nsPath hasPrefix:@"file://"] ? [NSURL URLWithString:nsPath]
473
+ : [NSURL fileURLWithPath:nsPath];
334
474
  AVURLAsset *asset = [AVURLAsset assetWithURL:url];
335
475
 
336
476
  NSArray<AVAssetTrack *> *videoTracks =
@@ -350,8 +490,7 @@ ApplePlatformContext::loadVideoFrame(const std::string &path) {
350
490
  }
351
491
 
352
492
  NSDictionary *outputSettings = @{
353
- (NSString *)kCVPixelBufferPixelFormatTypeKey :
354
- @(kCVPixelFormatType_32BGRA),
493
+ (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA),
355
494
  (NSString *)kCVPixelBufferIOSurfacePropertiesKey : @{},
356
495
  (NSString *)kCVPixelBufferMetalCompatibilityKey : @YES,
357
496
  };
@@ -405,7 +544,7 @@ ApplePlatformContext::loadVideoFrame(const std::string &path) {
405
544
 
406
545
  std::unique_ptr<IVideoPlayer>
407
546
  ApplePlatformContext::createVideoPlayer(const std::string &path,
408
- VideoPixelFormat format) {
547
+ VideoPixelFormat format) {
409
548
  return createAppleVideoPlayer(path, format);
410
549
  }
411
550
 
@@ -148,6 +148,12 @@ struct ViewSnapshotRequest {
148
148
  // destination itself. A platform that renders the view into a GPU buffer
149
149
  // then hands that buffer over instead of reading the pixels back.
150
150
  bool allowFrame = false;
151
+ // iOS: whether to flush pending layout and layer changes before drawing
152
+ // (drawViewHierarchyInRect's afterScreenUpdates), so a snapshot taken right
153
+ // after a state change reflects it; false draws the last committed frame
154
+ // without that round trip. Android renders the views' current display
155
+ // lists either way.
156
+ bool afterScreenUpdates = true;
151
157
  };
152
158
 
153
159
  class PlatformContext {
@@ -357,12 +357,15 @@ async::AsyncTaskHandle GPUQueue::drawElementImageToTexture(
357
357
  "a positive width and height");
358
358
  }
359
359
 
360
+ request.afterScreenUpdates = source->afterScreenUpdates.value_or(true);
361
+
360
362
  // With RENDER_ATTACHMENT as well, a platform that renders the view into a
361
- // GPU buffer (Android 13 and above, through HardwareRenderer) hands that
362
- // buffer over instead of reading the pixels back, and the view is drawn into
363
- // the destination on the GPU (VideoFrameBlit), which writes the color aspect
364
- // of the first layer. An omitted aspect means "all" (dst.aspect itself stays
365
- // at Dawn's Undefined default, which WriteTexture reads the same way).
363
+ // GPU buffer (Android 13 and above through HardwareRenderer, iOS through an
364
+ // IOSurface) hands that buffer over instead of reading the pixels back, and
365
+ // the view is drawn into the destination on the GPU (VideoFrameBlit), which
366
+ // writes the color aspect of the first layer. An omitted aspect means "all"
367
+ // (dst.aspect itself stays at Dawn's Undefined default, which WriteTexture
368
+ // reads the same way).
366
369
  request.allowFrame =
367
370
  (texture.GetUsage() & wgpu::TextureUsage::RenderAttachment) != 0 &&
368
371
  info->aspect.value_or(wgpu::TextureAspect::All) ==
@@ -22,6 +22,9 @@ struct GPUDrawElementImageSource {
22
22
  std::optional<double> sourceY; // float
23
23
  std::optional<double> sourceWidth; // float
24
24
  std::optional<double> sourceHeight; // float
25
+ // iOS: pass false to draw the last committed frame instead of waiting for
26
+ // pending layout and layer changes (default true). Ignored on Android.
27
+ std::optional<bool> afterScreenUpdates;
25
28
  };
26
29
 
27
30
  } // namespace rnwgpu
@@ -93,6 +96,10 @@ struct JSIConverter<std::shared_ptr<rnwgpu::GPUDrawElementImageSource>> {
93
96
  result->sourceHeight = JSIConverter<std::optional<double>>::fromJSI(
94
97
  runtime, obj.getProperty(runtime, "sourceHeight"), false);
95
98
  }
99
+ if (obj.hasProperty(runtime, "afterScreenUpdates")) {
100
+ result->afterScreenUpdates = JSIConverter<std::optional<bool>>::fromJSI(
101
+ runtime, obj.getProperty(runtime, "afterScreenUpdates"), false);
102
+ }
96
103
  return result;
97
104
  }
98
105
 
@@ -73,6 +73,7 @@ export interface GPUDrawElementImageSource {
73
73
  sourceY?: number;
74
74
  sourceWidth?: number;
75
75
  sourceHeight?: number;
76
+ afterScreenUpdates?: boolean;
76
77
  }
77
78
  export interface GPUDrawElementImageDestination extends GPUCopyExternalImageDestInfo {
78
79
  size?: GPUExtent3DStrict;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG,MAAM,CAAC;AAE7B,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IAGrB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9D,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IACjE,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAClC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAChD;AAED,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG;IAC/C;;;;;;;;OAQG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,UAAU,CAAC,WAAW,EAAE,QAAQ,GAAG,eAAe,GAAG,IAAI,CAAC;IAC1D,gBAAgB,EAAE,MAAM,YAAY,CAAC;CACtC;AAKD,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,MAAM,CAAC;AAkBtD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C,OAAO,IAAI,IAAI,CAAC;CACjB;AAMD,MAAM,WAAW,kCAAmC,SAAQ,IAAI,CAC9D,4BAA4B,EAC5B,QAAQ,CACT;IACC,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAQD,MAAM,WAAW,WAAW;IAC1B,eAAe,IAAI,gBAAgB,GAAG,IAAI,CAAC;IAC3C,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IAGd,OAAO,IAAI,IAAI,CAAC;IAChB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAGzB,WAAW,EAAE,MAAM,CAAC;IAEpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,MAAM,EAAE,MAAM,CAAC;IAGf,IAAI,EAAE,OAAO,CAAC;IAEd,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAI7B,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;IAEtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AASD,MAAM,WAAW,oCAAoC;IACnD,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IAOvC,WAAW,CAAC,EAAE,sBAAsB,CAAC;CACtC;AAMD,MAAM,MAAM,6BAA6B,GACvC,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC;AAO3D,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,6BAA6B,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD,MAAM,WAAW,8BAA+B,SAAQ,4BAA4B;IAClF,IAAI,CAAC,EAAE,iBAAiB,CAAC;CAC1B;AAED,MAAM,WAAW,gCAAgC;IAM/C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,MAAM,MAAM,kBAAkB,GAC5B,kBAAkB,GAAG,SAAS,GAAG,wBAAwB,CAAC;AAE5D,MAAM,WAAW,wBAAwB;IAGvC,IAAI,EAAE,kBAAkB,CAAC;IAGzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,kBAAkB,CAAC;IAIzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IAGd,MAAM,IAAI,wBAAwB,CAAC;IAInC,OAAO,IAAI,IAAI,CAAC;CACjB;AAID,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,cAAc,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAID,MAAM,WAAW,oCAAoC;IACnD,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,mBAAmB,EAAE,CAAC;CAC/B;AAQD,MAAM,WAAW,wBAAwB;IACvC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAMD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,UAAU,CAAC,EAAE,oBAAoB,GAAG,UAAU,CAAC;IAM7D,WAAW,CACT,OAAO,EAAE,UAAU,EACnB,WAAW,EAAE,OAAO,EACpB,MAAM,CAAC,EAAE,mBAAmB,EAAE,GAC7B,IAAI,CAAC;IAGR,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,oCAAoC,CAAC;IAMrE,OAAO,IAAI,IAAI,CAAC;CACjB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-webgpu",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "description": "React Native WebGPU",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
package/src/types.ts CHANGED
@@ -152,6 +152,12 @@ export interface GPUDrawElementImageSource {
152
152
  sourceY?: number;
153
153
  sourceWidth?: number;
154
154
  sourceHeight?: number;
155
+ // iOS only (default true): flush pending layout and layer changes before
156
+ // drawing, so a snapshot taken right after a state change reflects it. Pass
157
+ // false to draw the last committed frame instead, which skips a round trip
158
+ // to the render server; the choice for repeated captures. Android renders
159
+ // the views' current display lists either way.
160
+ afterScreenUpdates?: boolean;
155
161
  }
156
162
 
157
163
  // The destination argument of drawElementImageToTexture: