react-native-webgpu 0.16.1 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/android/src/main/java/com/webgpu/BackingViewKind.java +38 -0
  2. package/android/src/main/java/com/webgpu/WebGPUSurfaceView.java +19 -2
  3. package/android/src/main/java/com/webgpu/WebGPUView.java +78 -76
  4. package/android/src/main/java/com/webgpu/WebGPUViewManager.java +13 -6
  5. package/cpp/jsi/NativeObject.h +42 -32
  6. package/cpp/rnwgpu/RNWebGPUManager.cpp +2 -5
  7. package/cpp/rnwgpu/api/GPUFeatures.h +1 -0
  8. package/cpp/rnwgpu/api/VideoFrame.h +2 -2
  9. package/lib/commonjs/Canvas.js +85 -39
  10. package/lib/commonjs/Canvas.js.map +1 -1
  11. package/lib/commonjs/WebGPUViewNativeComponent.js.map +1 -1
  12. package/lib/commonjs/WebGPUViewNativeComponent.web.js +3 -5
  13. package/lib/commonjs/WebGPUViewNativeComponent.web.js.map +1 -1
  14. package/lib/commonjs/mock.js +0 -1
  15. package/lib/commonjs/mock.js.map +1 -1
  16. package/lib/module/Canvas.js +85 -39
  17. package/lib/module/Canvas.js.map +1 -1
  18. package/lib/module/WebGPUViewNativeComponent.js.map +1 -1
  19. package/lib/module/WebGPUViewNativeComponent.web.js +3 -5
  20. package/lib/module/WebGPUViewNativeComponent.web.js.map +1 -1
  21. package/lib/module/mock.js +0 -1
  22. package/lib/module/mock.js.map +1 -1
  23. package/lib/typescript/lib/commonjs/Canvas.d.ts +1 -2
  24. package/lib/typescript/lib/commonjs/Canvas.d.ts.map +1 -1
  25. package/lib/typescript/lib/commonjs/WebGPUViewNativeComponent.web.d.ts.map +1 -1
  26. package/lib/typescript/lib/commonjs/mock.d.ts +1 -2
  27. package/lib/typescript/lib/commonjs/mock.d.ts.map +1 -1
  28. package/lib/typescript/lib/module/Canvas.d.ts +1 -2
  29. package/lib/typescript/lib/module/Canvas.d.ts.map +1 -1
  30. package/lib/typescript/lib/module/WebGPUViewNativeComponent.web.d.ts.map +1 -1
  31. package/lib/typescript/lib/module/mock.d.ts +1 -2
  32. package/lib/typescript/lib/module/mock.d.ts.map +1 -1
  33. package/lib/typescript/src/Canvas.d.ts +61 -29
  34. package/lib/typescript/src/Canvas.d.ts.map +1 -1
  35. package/lib/typescript/src/WebGPUViewNativeComponent.d.ts +3 -2
  36. package/lib/typescript/src/WebGPUViewNativeComponent.d.ts.map +1 -1
  37. package/lib/typescript/src/WebGPUViewNativeComponent.web.d.ts +3 -2
  38. package/lib/typescript/src/WebGPUViewNativeComponent.web.d.ts.map +1 -1
  39. package/lib/typescript/src/mock.d.ts +2 -2
  40. package/lib/typescript/src/mock.d.ts.map +1 -1
  41. package/package.json +3 -3
  42. package/src/Canvas.tsx +153 -77
  43. package/src/WebGPUViewNativeComponent.ts +6 -4
  44. package/src/WebGPUViewNativeComponent.web.ts +7 -5
  45. package/src/index.tsx +3 -3
  46. package/src/mock.ts +5 -7
@@ -0,0 +1,38 @@
1
+ package com.webgpu;
2
+
3
+ import androidx.annotation.Nullable;
4
+
5
+ /**
6
+ * The Android view a WebGPUView draws into, see WebGPUView.updateView(), and
7
+ * the rules the props resolve by. The JS side (Canvas.tsx) mirrors them to
8
+ * warn in development.
9
+ */
10
+ enum BackingViewKind {
11
+ SURFACE_VIEW,
12
+ TEXTURE_VIEW,
13
+ HARDWARE_BUFFER_VIEW;
14
+
15
+ /**
16
+ * The kind the androidBackingView prop names; a TextureView by default. A
17
+ * HardwareBufferView (a plain View drawing AHardwareBuffers inline) needs
18
+ * Android 10: below it, the request falls back to a TextureView, which
19
+ * composites the same way, and the JS side warns about it in development.
20
+ */
21
+ static BackingViewKind fromBackingView(@Nullable String backingView, boolean hardwareBufferSupported) {
22
+ if ("SurfaceView".equals(backingView)) {
23
+ return SURFACE_VIEW;
24
+ }
25
+ if ("HardwareBufferView".equals(backingView) && hardwareBufferSupported) {
26
+ return HARDWARE_BUFFER_VIEW;
27
+ }
28
+ return TEXTURE_VIEW;
29
+ }
30
+
31
+ /**
32
+ * Whether the canvas composites as opaque: what the prop asks for, except
33
+ * that a HardwareBufferView always composites with alpha.
34
+ */
35
+ static boolean resolveOpaque(BackingViewKind kind, boolean opaque) {
36
+ return opaque && kind != HARDWARE_BUFFER_VIEW;
37
+ }
38
+ }
@@ -13,10 +13,12 @@ public class WebGPUSurfaceView extends SurfaceView implements SurfaceHolder.Call
13
13
 
14
14
  WebGPUAPI mApi;
15
15
 
16
- public WebGPUSurfaceView(Context context, WebGPUAPI api, boolean zOrderOnTop, boolean opaque) {
16
+ public WebGPUSurfaceView(Context context, WebGPUAPI api, boolean zOrderOnTop,
17
+ boolean zOrderMediaOverlay, boolean opaque) {
17
18
  super(context);
18
19
  mApi = api;
19
- setZOrderOnTop(zOrderOnTop);
20
+ // Both are read when the surface is created.
21
+ setZOrder(zOrderOnTop, zOrderMediaOverlay);
20
22
  setOpaque(opaque);
21
23
  getHolder().addCallback(this);
22
24
  }
@@ -27,6 +29,21 @@ public class WebGPUSurfaceView extends SurfaceView implements SurfaceHolder.Call
27
29
  getHolder().setFormat(opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT);
28
30
  }
29
31
 
32
+ // The sublayer the surface is composited at, relative to the window: above
33
+ // it (on top), or below it, above the other SurfaceViews there (media
34
+ // overlay) or among them (the default). setZOrderOnTop(false) resets the
35
+ // request to the default, so it goes first. Before Android 11 the request
36
+ // is read when the surface is created; from Android 11 on, SurfaceView
37
+ // applies a changed request with the window's next frame (its pre-draw
38
+ // listener runs updateSurface()), which invalidate() schedules.
39
+ public void setZOrder(boolean onTop, boolean mediaOverlay) {
40
+ setZOrderOnTop(onTop);
41
+ if (!onTop) {
42
+ setZOrderMediaOverlay(mediaOverlay);
43
+ }
44
+ invalidate();
45
+ }
46
+
30
47
  @Override
31
48
  protected void onDetachedFromWindow() {
32
49
  super.onDetachedFromWindow();
@@ -6,31 +6,36 @@ import android.util.Log;
6
6
  import android.view.Surface;
7
7
  import android.view.View;
8
8
 
9
+ import androidx.annotation.Nullable;
10
+
9
11
  import com.facebook.proguard.annotations.DoNotStrip;
10
12
  import com.facebook.react.uimanager.ThemedReactContext;
11
13
  import com.facebook.react.views.view.ReactViewGroup;
12
14
 
15
+ /**
16
+ * The Android view behind <Canvas>. It is backed by a TextureView, a
17
+ * SurfaceView or a HardwareBufferView, named by the androidBackingView prop
18
+ * and created once, from the props of the first transaction, for the life of
19
+ * the view (see updateView()).
20
+ */
13
21
  public class WebGPUView extends ReactViewGroup implements WebGPUAPI {
14
22
  private static final String TAG = "WebGPUView";
15
23
 
16
- // Backing view kinds, see updateView().
17
- private static final int KIND_SURFACE_VIEW = 0;
18
- private static final int KIND_TEXTURE_VIEW = 1;
19
- private static final int KIND_HARDWARE_BUFFER_VIEW = 2;
20
-
21
24
  private int mContextId;
22
- // Props. opaque is applied in place, and so is zOrderOnTop where Android
23
- // allows it (see setZOrderOnTop); surfaceType is read once, when the
25
+ // Props. opaque is applied in place, and so are the z-order props where
26
+ // Android allows it (see takesZOrder); backingView is read once, when the
24
27
  // backing view is created (see updateView()).
25
- private boolean mOpaque = true;
26
- private String mSurfaceType = "auto";
28
+ private BackingViewKind mBackingView = BackingViewKind.TEXTURE_VIEW;
29
+ private boolean mOpaque = false;
27
30
  private boolean mZOrderOnTop = false;
31
+ private boolean mZOrderMediaOverlay = false;
28
32
  private WebGPUModule mModule;
29
33
  // The backing view, created by the first prop transaction and kept, with
30
- // the kind it was created with. The kind is -1 until then: it is what
34
+ // the kind it was created with. The kind is null until then: it is what
31
35
  // tells a mounted canvas apart.
32
36
  private View mView = null;
33
- private int mKind = -1;
37
+ @Nullable
38
+ private BackingViewKind mKind = null;
34
39
  // Only a SurfaceView votes: a TextureView or HardwareBufferView is
35
40
  // composited into the window, which votes for it.
36
41
  private final SurfaceFrameRateVote mFrameRateVote = new SurfaceFrameRateVote(
@@ -58,11 +63,7 @@ public class WebGPUView extends ReactViewGroup implements WebGPUAPI {
58
63
  mContextId = contextId;
59
64
  }
60
65
 
61
- public void setOpaque(boolean value) {
62
- mOpaque = value;
63
- }
64
-
65
- // The backing view is chosen from the props of the first transaction and
66
+ // The backing view is created from the props of the first transaction and
66
67
  // kept (see updateView()). React calls a setter again only when its prop
67
68
  // changed, so a call on a mounted canvas is a change: the setters below
68
69
  // apply it in place where the view can take it, else they ignore it and
@@ -70,98 +71,99 @@ public class WebGPUView extends ReactViewGroup implements WebGPUAPI {
70
71
  // new key). The JS side warns about the same changes in development (see
71
72
  // Canvas.tsx), mirroring these rules.
72
73
 
73
- public void setSurfaceType(String value) {
74
- if (mKind != -1) {
75
- warnIgnoredOnceMounted("android.surfaceType");
74
+ public void setBackingView(@Nullable String value) {
75
+ if (mKind != null) {
76
+ warnIgnoredOnceMounted("android.backingView");
76
77
  return;
77
78
  }
78
- mSurfaceType = value;
79
+ boolean hardwareBufferSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
80
+ mBackingView = BackingViewKind.fromBackingView(value, hardwareBufferSupported);
81
+ }
82
+
83
+ public void setOpaque(boolean value) {
84
+ mOpaque = value;
79
85
  }
80
86
 
81
87
  public void setZOrderOnTop(boolean value) {
82
- if (mKind == -1) {
88
+ if (takesZOrder("android.zOrderOnTop")) {
83
89
  mZOrderOnTop = value;
84
- return;
85
- }
86
- // Only a SurfaceView has a z-order of its own: elsewhere the prop never
87
- // applied, and the change is moot.
88
- if (mKind != KIND_SURFACE_VIEW) {
89
- return;
90
- }
91
- if (!zOrderChangesInPlace()) {
92
- warnIgnoredOnceMounted("android.zOrderOnTop");
93
- return;
90
+ applyZOrder();
94
91
  }
95
- mZOrderOnTop = value;
96
- ((WebGPUSurfaceView) mView).setZOrderOnTop(value);
97
92
  }
98
93
 
99
- private void warnIgnoredOnceMounted(String prop) {
100
- Log.w(TAG, "Ignoring a change of " + prop + " on a mounted canvas: the backing view"
101
- + " is chosen when the canvas mounts. Remount the canvas (give it a new key)"
102
- + " to change it.");
94
+ public void setZOrderMediaOverlay(boolean value) {
95
+ if (takesZOrder("android.zOrderMediaOverlay")) {
96
+ mZOrderMediaOverlay = value;
97
+ applyZOrder();
98
+ }
103
99
  }
104
100
 
105
- // SurfaceView.setZOrderOnTop() moves a live surface since Android 11, for
106
- // an app targeting it; before that, the surface reads it when it is
107
- // created (see updateView()).
108
- private boolean zOrderChangesInPlace() {
109
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
101
+ // Whether a z-order prop is taken. Before the backing view exists it is
102
+ // read when the view is created. After that only a SurfaceView has a
103
+ // z-order of its own (elsewhere the prop never applied, and the change is
104
+ // moot), and SurfaceView moves a live surface since Android 11, for an app
105
+ // targeting it; before that, the surface reads it when it is created.
106
+ private boolean takesZOrder(String prop) {
107
+ if (mKind == null) {
108
+ return true;
109
+ }
110
+ if (mKind != BackingViewKind.SURFACE_VIEW) {
111
+ return false;
112
+ }
113
+ boolean inPlace = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
110
114
  && getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R;
115
+ if (!inPlace) {
116
+ warnIgnoredOnceMounted(prop);
117
+ }
118
+ return inPlace;
111
119
  }
112
120
 
113
- // Resolve the backing view from the props. "auto" picks SurfaceView for an
114
- // opaque canvas and TextureView for a non-opaque one. WebGPUHardwareBufferView
115
- // (a plain View drawing AHardwareBuffers inline, API 29+) is opt-in via
116
- // surfaceType until it gets a runtime fallback to TextureView when the
117
- // AHardwareBuffer import fails on a device; below API 29 the request itself
118
- // falls back to TextureView.
119
- private int resolveKind() {
120
- if ("SurfaceView".equals(mSurfaceType)) {
121
- return KIND_SURFACE_VIEW;
122
- }
123
- if ("TextureView".equals(mSurfaceType)) {
124
- return KIND_TEXTURE_VIEW;
121
+ private void applyZOrder() {
122
+ if (mKind == BackingViewKind.SURFACE_VIEW) {
123
+ ((WebGPUSurfaceView) mView).setZOrder(mZOrderOnTop, mZOrderMediaOverlay);
125
124
  }
126
- if ("HardwareBufferView".equals(mSurfaceType)) {
127
- boolean hardwareBufferSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
128
- return hardwareBufferSupported ? KIND_HARDWARE_BUFFER_VIEW : KIND_TEXTURE_VIEW;
129
- }
130
- return mOpaque ? KIND_SURFACE_VIEW : KIND_TEXTURE_VIEW;
125
+ }
126
+
127
+ private void warnIgnoredOnceMounted(String prop) {
128
+ Log.w(TAG, "Ignoring a change of " + prop + " on a mounted canvas: the backing view"
129
+ + " is chosen when the canvas mounts. Remount the canvas (give it a new key)"
130
+ + " to change it.");
131
131
  }
132
132
 
133
133
  // Apply the complete prop transaction once, after contextId and all rendering
134
134
  // options have arrived. The first one creates the backing view, which is
135
135
  // then kept: a SurfaceView must know its z-order before it attaches (before
136
- // Android 11), and replacing a backing view on screen hands the canvas from
137
- // one view to another, which no release of Android does without a frame of
138
- // nothing, or of black, in between (the two views are composited by
139
- // different frames). A canvas that needs another backing view is remounted
140
- // instead. Later transactions apply the opacity in place (the setters decide
136
+ // Android 11), and keeping a canvas on screen while its backing view is
137
+ // replaced takes hold-and-retire logic specific to each Android release (see
138
+ // PR #563, and react-native-skia's #4189 and #4192), which this view does
139
+ // not carry. A canvas that needs another backing view is remounted instead,
140
+ // and is off screen for a frame or two until the new view draws its first
141
+ // frame. Later transactions apply the opacity in place (the setters decide
141
142
  // what else is taken); WebGPUHardwareBufferView always composites with
142
143
  // alpha, so there it is a no-op.
143
144
  public void updateView() {
144
- if (mKind != -1) {
145
- if (mKind == KIND_TEXTURE_VIEW) {
146
- ((WebGPUTextureView) mView).setOpaque(mOpaque);
147
- } else if (mKind == KIND_SURFACE_VIEW) {
148
- ((WebGPUSurfaceView) mView).setOpaque(mOpaque);
145
+ if (mKind != null) {
146
+ boolean opaque = BackingViewKind.resolveOpaque(mKind, mOpaque);
147
+ if (mKind == BackingViewKind.TEXTURE_VIEW) {
148
+ ((WebGPUTextureView) mView).setOpaque(opaque);
149
+ } else if (mKind == BackingViewKind.SURFACE_VIEW) {
150
+ ((WebGPUSurfaceView) mView).setOpaque(opaque);
149
151
  }
150
152
  return;
151
153
  }
152
- int kind = resolveKind();
153
- boolean zOrderOnTop = kind == KIND_SURFACE_VIEW && mZOrderOnTop;
154
+ BackingViewKind kind = mBackingView;
154
155
  mKind = kind;
156
+ boolean opaque = BackingViewKind.resolveOpaque(kind, mOpaque);
155
157
  Context ctx = getContext();
156
158
  switch (kind) {
157
- case KIND_HARDWARE_BUFFER_VIEW:
159
+ case HARDWARE_BUFFER_VIEW:
158
160
  mView = new WebGPUHardwareBufferView(ctx, this);
159
161
  break;
160
- case KIND_TEXTURE_VIEW:
161
- mView = new WebGPUTextureView(ctx, this, mOpaque);
162
+ case TEXTURE_VIEW:
163
+ mView = new WebGPUTextureView(ctx, this, opaque);
162
164
  break;
163
165
  default:
164
- mView = new WebGPUSurfaceView(ctx, this, zOrderOnTop, mOpaque);
166
+ mView = new WebGPUSurfaceView(ctx, this, mZOrderOnTop, mZOrderMediaOverlay, opaque);
165
167
  break;
166
168
  }
167
169
  addView(mView);
@@ -188,7 +190,7 @@ public class WebGPUView extends ReactViewGroup implements WebGPUAPI {
188
190
  float density = getResources().getDisplayMetrics().density;
189
191
  float width = getWidth() / density;
190
192
  float height = getHeight() / density;
191
- boolean votesFrameRate = mKind == KIND_SURFACE_VIEW;
193
+ boolean votesFrameRate = mKind == BackingViewKind.SURFACE_VIEW;
192
194
  if (votesFrameRate) {
193
195
  mFrameRateVote.attach(surface);
194
196
  }
@@ -1,6 +1,7 @@
1
1
  package com.webgpu;
2
2
 
3
3
  import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
4
5
 
5
6
  import com.facebook.react.module.annotations.ReactModule;
6
7
  import com.facebook.react.uimanager.ThemedReactContext;
@@ -30,15 +31,15 @@ public class WebGPUViewManager extends WebGPUViewManagerSpec<WebGPUView> {
30
31
  }
31
32
 
32
33
  @Override
33
- @ReactProp(name = "opaque", defaultBoolean = true)
34
- public void setOpaque(WebGPUView view, boolean value) {
35
- view.setOpaque(value);
34
+ @ReactProp(name = "androidBackingView")
35
+ public void setAndroidBackingView(WebGPUView view, @Nullable String value) {
36
+ view.setBackingView(value);
36
37
  }
37
38
 
38
39
  @Override
39
- @ReactProp(name = "androidSurfaceType")
40
- public void setAndroidSurfaceType(WebGPUView view, String value) {
41
- view.setSurfaceType(value);
40
+ @ReactProp(name = "androidOpaque")
41
+ public void setAndroidOpaque(WebGPUView view, boolean value) {
42
+ view.setOpaque(value);
42
43
  }
43
44
 
44
45
  @Override
@@ -47,6 +48,12 @@ public class WebGPUViewManager extends WebGPUViewManagerSpec<WebGPUView> {
47
48
  view.setZOrderOnTop(value);
48
49
  }
49
50
 
51
+ @Override
52
+ @ReactProp(name = "androidZOrderMediaOverlay")
53
+ public void setAndroidZOrderMediaOverlay(WebGPUView view, boolean value) {
54
+ view.setZOrderMediaOverlay(value);
55
+ }
56
+
50
57
  @Override
51
58
  protected void onAfterUpdateTransaction(@NonNull WebGPUView view) {
52
59
  super.onAfterUpdateTransaction(view);
@@ -328,6 +328,11 @@ public:
328
328
  return; // Already installed on this runtime
329
329
  }
330
330
 
331
+ // Every wrapper is made by create(), which installs the prototype first,
332
+ // so the class is registered before any of its objects can be boxed,
333
+ // whether or not its constructor is ever installed as a global.
334
+ registerReconstructor();
335
+
331
336
  // Create prototype object
332
337
  jsi::Object prototype(runtime);
333
338
 
@@ -411,40 +416,10 @@ public:
411
416
  * Idempotent per runtime: once the global exists there, later calls return
412
417
  * without touching it, so the constructor object keeps its identity.
413
418
  *
414
- * Also registers this class with NativeObjectRegistry so that
415
- * BoxedWebGPUObject::unbox() can rebuild its objects on secondary runtimes.
419
+ * Not needed for objects to cross runtimes: installPrototype() registers
420
+ * the class with NativeObjectRegistry.
416
421
  */
417
422
  static void installConstructor(jsi::Runtime &runtime) {
418
- // Register the reconstructor used by BoxedWebGPUObject::unbox() to
419
- // rebuild this object (prototype + native state) on another runtime.
420
- static std::once_flag registryFlag;
421
- std::call_once(registryFlag, []() {
422
- NativeObjectRegistry::getInstance().registerClass(
423
- Derived::CLASS_NAME,
424
- [](jsi::Runtime &rt,
425
- std::shared_ptr<jsi::NativeState> state) -> jsi::Value {
426
- auto instance = std::dynamic_pointer_cast<Derived>(state);
427
- if (instance == nullptr) {
428
- throw jsi::JSError(rt, "Invalid boxed native object state");
429
- }
430
- // The constructor makes `instanceof` work on this runtime too
431
- // (a no-op once it is installed there).
432
- Derived::installConstructor(rt);
433
- // Unboxing hands back the wrapper cached for the target runtime,
434
- // creating it on first use. Keep the runtime the object was
435
- // originally created on: async native code (GPUDevice error/lost
436
- // events, GPUAdapter::requestDevice) delivers into the creation
437
- // runtime, and rebinding it to a worklet runtime would invoke
438
- // main-runtime jsi::Functions on the wrong runtime and thread.
439
- auto *originalRuntime = instance->getCreationRuntime();
440
- auto value = Derived::create(rt, instance);
441
- if (originalRuntime != nullptr) {
442
- instance->setCreationRuntime(originalRuntime);
443
- }
444
- return value;
445
- });
446
- });
447
-
448
423
  installPrototype(runtime);
449
424
 
450
425
  // Once per runtime. installWebGPU() runs this at the top of every worklet
@@ -481,6 +456,41 @@ public:
481
456
  runtime.global().setProperty(runtime, Derived::CLASS_NAME, std::move(ctor));
482
457
  }
483
458
 
459
+ /**
460
+ * Registers the reconstructor BoxedWebGPUObject::unbox() uses to rebuild
461
+ * this class's objects (prototype + native state) on another runtime.
462
+ * Once per process: the registry outlives every runtime.
463
+ */
464
+ static void registerReconstructor() {
465
+ static std::once_flag registryFlag;
466
+ std::call_once(registryFlag, []() {
467
+ NativeObjectRegistry::getInstance().registerClass(
468
+ Derived::CLASS_NAME,
469
+ [](jsi::Runtime &rt,
470
+ std::shared_ptr<jsi::NativeState> state) -> jsi::Value {
471
+ auto instance = std::dynamic_pointer_cast<Derived>(state);
472
+ if (instance == nullptr) {
473
+ throw jsi::JSError(rt, "Invalid boxed native object state");
474
+ }
475
+ // The constructor makes `instanceof` work on this runtime too
476
+ // (a no-op once it is installed there).
477
+ Derived::installConstructor(rt);
478
+ // Unboxing hands back the wrapper cached for the target runtime,
479
+ // creating it on first use. Keep the runtime the object was
480
+ // originally created on: async native code (GPUDevice error/lost
481
+ // events, GPUAdapter::requestDevice) delivers into the creation
482
+ // runtime, and rebinding it to a worklet runtime would invoke
483
+ // main-runtime jsi::Functions on the wrong runtime and thread.
484
+ auto *originalRuntime = instance->getCreationRuntime();
485
+ auto value = Derived::create(rt, instance);
486
+ if (originalRuntime != nullptr) {
487
+ instance->setCreationRuntime(originalRuntime);
488
+ }
489
+ return value;
490
+ });
491
+ });
492
+ }
493
+
484
494
  /**
485
495
  * Returns the JS wrapper of `instance` on `runtime`, creating it on first
486
496
  * use.
@@ -41,6 +41,7 @@
41
41
  #include "GPUTextureView.h"
42
42
  #include "GPUUncapturedErrorEvent.h"
43
43
  #include "GPUValidationError.h"
44
+ #include "ImageBitmap.h"
44
45
  #include "VideoFrame.h"
45
46
  #include "VideoPlayer.h"
46
47
 
@@ -78,11 +79,6 @@ RNWebGPUManager::RNWebGPUManager(
78
79
  std::make_shared<RNWebGPU>(gpu, _platformContext, _jsCallInvoker);
79
80
  _gpu = gpu->get();
80
81
 
81
- // RNWebGPU needs its brand registered in NativeObjectRegistry so the boxing
82
- // path can install the prototype on worklet runtimes. installConstructor
83
- // does that registration but also sets globalThis.RNWebGPU = ctor, so we
84
- // call it FIRST and then overwrite the global with the actual instance.
85
- RNWebGPU::installConstructor(*_jsRuntime);
86
82
  _jsRuntime->global().setProperty(*_jsRuntime, "RNWebGPU",
87
83
  RNWebGPU::create(*_jsRuntime, rnWebGPU));
88
84
 
@@ -144,6 +140,7 @@ void RNWebGPUManager::installConstructors(jsi::Runtime &runtime) {
144
140
  GPUSupportedLimits::installConstructor(runtime);
145
141
  GPUTexture::installConstructor(runtime);
146
142
  GPUTextureView::installConstructor(runtime);
143
+ ImageBitmap::installConstructor(runtime);
147
144
  VideoFrame::installConstructor(runtime);
148
145
  VideoPlayer::installConstructor(runtime);
149
146
  }
@@ -104,6 +104,7 @@ namespace rnwgpu {
104
104
  V(AdapterPropertiesWGPU, "adapter-properties-wgpu") \
105
105
  V(SharedBufferMemoryFromWindowsHandle, \
106
106
  "shared-buffer-memory-from-windows-handle") \
107
+ V(SharedBufferMemoryHostPointer, "shared-buffer-memory-host-pointer") \
107
108
  V(SharedTextureMemoryD3D12Resource, "shared-texture-memory-d3d12-resource") \
108
109
  V(ChromiumExperimentalSamplingResourceTable, \
109
110
  "chromium-experimental-sampling-resource-table") \
@@ -21,8 +21,8 @@ namespace jsi = facebook::jsi;
21
21
  class VideoFrame : public NativeObject<VideoFrame> {
22
22
  public:
23
23
  // JS-facing brand. installConstructor() exposes this as
24
- // globalThis[CLASS_NAME] and keys the NativeObjectRegistry / worklet
25
- // serializer off it, so it must NOT be "VideoFrame": that would install our
24
+ // globalThis[CLASS_NAME], and the NativeObjectRegistry / worklet serializer
25
+ // are keyed off it, so it must NOT be "VideoFrame": that would install our
26
26
  // constructor over the WebCodecs `VideoFrame` global and shadow it at
27
27
  // runtime. "NativeVideoFrame" matches the public TypeScript type (see
28
28
  // src/types.ts) and keeps the two namespaces distinct. The C++ class stays