react-native-wgpu 0.1.7 → 0.1.9

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 (93) hide show
  1. package/android/cpp/cpp-adapter.cpp +13 -35
  2. package/android/src/main/java/com/webgpu/WebGPUModule.java +0 -37
  3. package/android/src/main/java/com/webgpu/WebGPUView.java +0 -1
  4. package/android/src/main/java/com/webgpu/WebGPUViewPackage.java +1 -1
  5. package/cpp/rnwgpu/RNWebGPUManager.h +2 -2
  6. package/cpp/rnwgpu/SurfaceRegistry.h +148 -13
  7. package/cpp/rnwgpu/api/Canvas.h +15 -15
  8. package/cpp/rnwgpu/api/GPUCanvasContext.cpp +81 -23
  9. package/cpp/rnwgpu/api/GPUCanvasContext.h +16 -7
  10. package/cpp/rnwgpu/api/GPUDevice.cpp +6 -3
  11. package/cpp/rnwgpu/api/OffscreenSurface.h +49 -0
  12. package/cpp/rnwgpu/api/RNWebGPU.h +21 -10
  13. package/ios/MetalView.mm +11 -0
  14. package/ios/SurfaceUtils.h +2 -0
  15. package/ios/SurfaceUtils.mm +16 -4
  16. package/ios/WebGPUModule.mm +8 -25
  17. package/ios/WebGPUView.mm +9 -6
  18. package/lib/commonjs/Canvas.js +79 -18
  19. package/lib/commonjs/Canvas.js.map +1 -1
  20. package/lib/commonjs/Offscreen.js +124 -0
  21. package/lib/commonjs/Offscreen.js.map +1 -0
  22. package/lib/commonjs/index.js +12 -0
  23. package/lib/commonjs/index.js.map +1 -1
  24. package/lib/commonjs/utils.js +26 -15
  25. package/lib/commonjs/utils.js.map +1 -1
  26. package/lib/module/Canvas.js +80 -19
  27. package/lib/module/Canvas.js.map +1 -1
  28. package/lib/module/Offscreen.js +117 -0
  29. package/lib/module/Offscreen.js.map +1 -0
  30. package/lib/module/index.js +1 -0
  31. package/lib/module/index.js.map +1 -1
  32. package/lib/module/utils.js +25 -15
  33. package/lib/module/utils.js.map +1 -1
  34. package/lib/typescript/lib/commonjs/Offscreen.d.ts +32 -0
  35. package/lib/typescript/lib/commonjs/Offscreen.d.ts.map +1 -0
  36. package/lib/typescript/lib/commonjs/utils.d.ts +5 -1
  37. package/lib/typescript/lib/commonjs/utils.d.ts.map +1 -1
  38. package/lib/typescript/lib/module/Canvas.d.ts.map +1 -1
  39. package/lib/typescript/lib/module/Offscreen.d.ts +31 -0
  40. package/lib/typescript/lib/module/Offscreen.d.ts.map +1 -0
  41. package/lib/typescript/lib/module/index.d.ts +1 -0
  42. package/lib/typescript/lib/module/utils.d.ts +5 -1
  43. package/lib/typescript/lib/module/utils.d.ts.map +1 -1
  44. package/lib/typescript/src/Canvas.d.ts +6 -4
  45. package/lib/typescript/src/Canvas.d.ts.map +1 -1
  46. package/lib/typescript/src/Offscreen.d.ts +41 -0
  47. package/lib/typescript/src/Offscreen.d.ts.map +1 -0
  48. package/lib/typescript/src/__tests__/setup.d.ts +5 -4
  49. package/lib/typescript/src/__tests__/setup.d.ts.map +1 -1
  50. package/lib/typescript/src/index.d.ts +1 -0
  51. package/lib/typescript/src/index.d.ts.map +1 -1
  52. package/lib/typescript/src/utils.d.ts +6 -3
  53. package/lib/typescript/src/utils.d.ts.map +1 -1
  54. package/libs/android/arm64-v8a/libwebgpu_dawn.so +0 -0
  55. package/libs/android/armeabi-v7a/libwebgpu_dawn.so +0 -0
  56. package/libs/android/x86/libwebgpu_dawn.so +0 -0
  57. package/libs/android/x86_64/libwebgpu_dawn.so +0 -0
  58. package/libs/apple/arm64_iphoneos/libwebgpu_dawn.a +0 -0
  59. package/libs/apple/arm64_iphonesimulator/libwebgpu_dawn.a +0 -0
  60. package/libs/apple/arm64_xros/libwebgpu_dawn.a +0 -0
  61. package/libs/apple/arm64_xrsimulator/libwebgpu_dawn.a +0 -0
  62. package/libs/apple/{libwebgpu_dawn.a → iphonesimulator/libwebgpu_dawn.a} +0 -0
  63. package/libs/apple/libwebgpu_dawn.xcframework/Info.plist +45 -0
  64. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/libwebgpu_dawn.a +0 -0
  65. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/libwebgpu_dawn.a +0 -0
  66. package/libs/apple/{libwebgpu_dawn_macosx.xcframework → libwebgpu_dawn.xcframework}/macos-arm64_x86_64/libwebgpu_dawn.a +0 -0
  67. package/libs/apple/{libwebgpu_dawn_visionos.xcframework → libwebgpu_dawn.xcframework}/xros-arm64/libwebgpu_dawn.a +0 -0
  68. package/libs/apple/{x86_64_xrsimulator → libwebgpu_dawn.xcframework/xros-arm64-simulator}/libwebgpu_dawn.a +0 -0
  69. package/libs/apple/universal_macosx/libwebgpu_dawn.a +0 -0
  70. package/libs/apple/x86_64_iphonesimulator/libwebgpu_dawn.a +0 -0
  71. package/package.json +1 -1
  72. package/react-native-wgpu.podspec +2 -8
  73. package/src/Canvas.tsx +101 -37
  74. package/src/Offscreen.ts +164 -0
  75. package/src/__tests__/ExternalTexture.spec.ts +4 -4
  76. package/src/__tests__/Texture.spec.ts +8 -2
  77. package/src/__tests__/demos/ABuffer.spec.ts +17 -12
  78. package/src/__tests__/demos/Blur.spec.ts +2 -1
  79. package/src/__tests__/demos/Cube.spec.ts +16 -12
  80. package/src/__tests__/demos/FractalCube.spec.ts +6 -5
  81. package/src/__tests__/demos/OcclusionQuery.spec.ts +3 -3
  82. package/src/__tests__/demos/RenderBundles.spec.ts +4 -3
  83. package/src/__tests__/demos/Triangle.spec.ts +27 -9
  84. package/src/__tests__/setup.ts +25 -10
  85. package/src/index.tsx +1 -0
  86. package/src/utils.ts +28 -18
  87. package/lib/typescript/src/__tests__/components/DrawingContext.d.ts +0 -12
  88. package/lib/typescript/src/__tests__/components/DrawingContext.d.ts.map +0 -1
  89. package/libs/apple/libwebgpu_dawn_macosx.xcframework/Info.plist +0 -28
  90. package/libs/apple/libwebgpu_dawn_visionos.a +0 -0
  91. package/libs/apple/libwebgpu_dawn_visionos.xcframework/Info.plist +0 -44
  92. package/libs/apple/libwebgpu_dawn_visionos.xcframework/xros-arm64_x86_64-simulator/libwebgpu_dawn_visionos.a +0 -0
  93. package/src/__tests__/components/DrawingContext.ts +0 -11
@@ -27,52 +27,30 @@ extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUModule_initializeNative(
27
27
  platformContext);
28
28
  }
29
29
 
30
- extern "C" JNIEXPORT void JNICALL
31
- Java_com_webgpu_WebGPUModule_createSurfaceContext(JNIEnv *env, jobject thiz,
32
- jlong jsRuntime,
33
- jint contextId) {
34
- auto canvas = manager->surfacesRegistry.getSurface(contextId);
35
- if (canvas == nullptr) {
36
- throw std::runtime_error("Surface haven't configured yet");
37
- }
38
-
39
- auto runtime = reinterpret_cast<facebook::jsi::Runtime *>(jsRuntime);
40
- auto webGPUContextRegistry = runtime->global().getPropertyAsObject(
41
- *runtime, "__WebGPUContextRegistry");
42
- if (webGPUContextRegistry.hasProperty(*runtime,
43
- std::to_string(contextId).c_str())) {
44
- // Context already exists, just update width/height
45
- auto prop =
46
- webGPUContextRegistry
47
- .getPropertyAsObject(*runtime, std::to_string(contextId).c_str())
48
- .asHostObject<rnwgpu::Canvas>(*runtime);
49
- prop->setWidth(canvas->getWidth());
50
- prop->setHeight(canvas->getHeight());
51
- return;
52
- }
53
- webGPUContextRegistry.setProperty(
54
- *runtime, std::to_string(contextId).c_str(),
55
- facebook::jsi::Object::createFromHostObject(*runtime, canvas));
56
- }
57
-
58
30
  extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUView_onSurfaceChanged(
59
31
  JNIEnv *env, jobject thiz, jobject surface, jint contextId, jfloat width,
60
32
  jfloat height) {
61
- manager->surfacesRegistry.updateSurface(contextId, width, height);
33
+ auto &registry = rnwgpu::SurfaceRegistry::getInstance();
34
+ auto info = registry.getSurface(contextId);
35
+ registry.setSize(contextId, static_cast<int>(width),
36
+ static_cast<int>(height));
62
37
  }
63
38
 
64
39
  extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUView_onSurfaceCreate(
65
- JNIEnv *env, jobject thiz, jobject surface, jint contextId, jfloat width,
40
+ JNIEnv *env, jobject thiz, jobject jSurface, jint contextId, jfloat width,
66
41
  jfloat height) {
67
- auto window = ANativeWindow_fromSurface(env, surface);
42
+ auto window = ANativeWindow_fromSurface(env, jSurface);
68
43
  // ANativeWindow_acquire(window);
69
- manager->surfacesRegistry.addSurface(contextId, window, width, height);
44
+ auto &registry = rnwgpu::SurfaceRegistry::getInstance();
45
+ registry.createSurface(contextId, window, static_cast<int>(width),
46
+ static_cast<int>(height), manager->_platformContext);
70
47
  }
71
48
 
72
49
  extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUView_onSurfaceDestroy(
73
50
  JNIEnv *env, jobject thiz, jint contextId) {
74
- auto canvas = manager->surfacesRegistry.getSurface(contextId);
51
+ auto &registry = rnwgpu::SurfaceRegistry::getInstance();
52
+ auto canvas = registry.getSurface(contextId);
75
53
  ANativeWindow_release(
76
- reinterpret_cast<ANativeWindow *>(canvas->getSurface()));
77
- manager->surfacesRegistry.removeSurface(contextId);
54
+ reinterpret_cast<ANativeWindow *>(canvas.nativeSurface));
55
+ registry.removeSurface(contextId);
78
56
  }
@@ -24,9 +24,6 @@ public class WebGPUModule extends NativeWebGPUModuleSpec {
24
24
  System.loadLibrary("react-native-wgpu"); // Load the C++ library
25
25
  }
26
26
 
27
- private final Object mContextLock = new Object();
28
- private final Set<Integer> mSurfaceContextsIds = new HashSet<>();
29
-
30
27
  public WebGPUModule(ReactApplicationContext reactContext) {
31
28
  super(reactContext);
32
29
  // Initialize the C++ module
@@ -50,38 +47,4 @@ public class WebGPUModule extends NativeWebGPUModuleSpec {
50
47
  @OptIn(markerClass = FrameworkAPI.class)
51
48
  @DoNotStrip
52
49
  private native void initializeNative(long jsRuntime, CallInvokerHolderImpl jsInvoker, BlobModule blobModule);
53
-
54
- @ReactMethod(isBlockingSynchronousMethod = true)
55
- public boolean createSurfaceContext(double contextId) {
56
- waitForNativeSurface((int)contextId);
57
-
58
- ReactApplicationContext context = getReactApplicationContext();
59
- JavaScriptContextHolder jsContext = context.getJavaScriptContextHolder();
60
- createSurfaceContext(jsContext.get(), (int)contextId);
61
- return true;
62
- }
63
-
64
- @DoNotStrip
65
- private native void createSurfaceContext(long jsRuntime, int contextId);
66
-
67
- private void waitForNativeSurface(Integer contextId) {
68
- synchronized (mContextLock) {
69
- while (!mSurfaceContextsIds.contains(contextId)) {
70
- try {
71
- mContextLock.wait();
72
- } catch (InterruptedException e) {
73
- Log.e("RNWebGPU", "Unable to create a context");
74
- return;
75
- }
76
- }
77
- }
78
- }
79
-
80
- protected void onSurfaceCreated(Integer contextId) {
81
- synchronized (mContextLock) {
82
- mSurfaceContextsIds.add(contextId);
83
- mContextLock.notifyAll();
84
- }
85
- }
86
-
87
50
  }
@@ -41,7 +41,6 @@ public class WebGPUView extends SurfaceView implements SurfaceHolder.Callback {
41
41
  float width = getWidth() / density;
42
42
  float height = getHeight() / density;
43
43
  onSurfaceCreate(holder.getSurface(), mContextId, width, height);
44
- mModule.onSurfaceCreated(mContextId);
45
44
  }
46
45
 
47
46
  @Override
@@ -21,6 +21,6 @@ public class WebGPUViewPackage implements ReactPackage {
21
21
 
22
22
  @Override
23
23
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
24
- return Arrays.asList(new WebGPUModule(reactContext));
24
+ return List.of(new WebGPUModule(reactContext));
25
25
  }
26
26
  }
@@ -27,11 +27,11 @@ public:
27
27
  std::shared_ptr<PlatformContext> platformContext);
28
28
  ~RNWebGPUManager();
29
29
 
30
- SurfaceRegistry surfacesRegistry;
31
-
32
30
  private:
33
31
  jsi::Runtime *_jsRuntime;
34
32
  std::shared_ptr<facebook::react::CallInvoker> _jsCallInvoker;
33
+
34
+ public:
35
35
  std::shared_ptr<PlatformContext> _platformContext;
36
36
  };
37
37
 
@@ -1,33 +1,168 @@
1
1
  #pragma once
2
2
 
3
3
  #include <memory>
4
+ #include <shared_mutex>
4
5
  #include <unordered_map>
5
6
 
6
7
  #include "webgpu/webgpu_cpp.h"
7
8
 
8
- #include "Canvas.h"
9
-
10
9
  namespace rnwgpu {
11
10
 
11
+ struct ISize {
12
+ int width;
13
+ int height;
14
+ };
15
+
16
+ struct SurfaceInfo {
17
+ void *nativeSurface = nullptr;
18
+ wgpu::Surface surface;
19
+ int width;
20
+ int height;
21
+ wgpu::Texture texture;
22
+ wgpu::Instance gpu;
23
+ wgpu::SurfaceConfiguration config;
24
+
25
+ void flushTextureToSurface() {
26
+ // 1.a flush texture to the onscreen surface
27
+ if (texture) {
28
+ wgpu::CommandEncoderDescriptor encoderDesc;
29
+ auto device = config.device;
30
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder(&encoderDesc);
31
+
32
+ wgpu::ImageCopyTexture sourceTexture = {};
33
+ sourceTexture.texture = texture;
34
+
35
+ wgpu::ImageCopyTexture destinationTexture = {};
36
+ wgpu::SurfaceTexture surfaceTexture;
37
+ surface.GetCurrentTexture(&surfaceTexture);
38
+ destinationTexture.texture = surfaceTexture.texture;
39
+
40
+ wgpu::Extent3D size = {sourceTexture.texture.GetWidth(),
41
+ sourceTexture.texture.GetHeight(),
42
+ sourceTexture.texture.GetDepthOrArrayLayers()};
43
+
44
+ encoder.CopyTextureToTexture(&sourceTexture, &destinationTexture, &size);
45
+
46
+ wgpu::CommandBuffer commands = encoder.Finish();
47
+ wgpu::Queue queue = device.GetQueue();
48
+ queue.Submit(1, &commands);
49
+ texture = nullptr;
50
+ }
51
+ }
52
+ };
53
+
12
54
  class SurfaceRegistry {
13
- std::unordered_map<int, std::shared_ptr<Canvas>> _registry;
55
+ private:
56
+ std::unordered_map<int, SurfaceInfo> _registry;
57
+ mutable std::shared_mutex _mutex;
58
+
59
+ // Private constructor to prevent instantiation
60
+ SurfaceRegistry() {}
61
+
62
+ void updateSurface(const int contextId, SurfaceInfo &info) {
63
+ auto it = _registry.find(contextId);
64
+ if (it != _registry.end()) {
65
+ it->second = info;
66
+ }
67
+ }
68
+
69
+ // bool hasOnScreenSurface(const int contextId) const {
70
+ // std::shared_lock<std::shared_mutex> lock(_mutex);
71
+ // auto it = _registry.find(contextId);
72
+ // if (it != _registry.end()) {
73
+ // return it->second.nativeSurface != nullptr;
74
+ // }
75
+ // return false;
76
+ // }
77
+
78
+ bool hasSurfaceInfo(const int contextId) const {
79
+ return _registry.find(contextId) != _registry.end();
80
+ }
14
81
 
15
82
  public:
16
- void addSurface(const int contextId, void *surface, float width,
17
- float height) {
18
- _registry[contextId] = std::make_shared<Canvas>(surface, width, height);
83
+ // Delete copy constructor and assignment operator
84
+ SurfaceRegistry(const SurfaceRegistry &) = delete;
85
+ SurfaceRegistry &operator=(const SurfaceRegistry &) = delete;
86
+
87
+ // Static method to get the singleton instance
88
+ static SurfaceRegistry &getInstance() {
89
+ static SurfaceRegistry instance;
90
+ return instance;
91
+ }
92
+
93
+ void removeSurface(const int contextId) {
94
+ std::unique_lock<std::shared_mutex> lock(_mutex);
95
+ _registry.erase(contextId);
19
96
  }
20
97
 
21
- std::shared_ptr<Canvas> getSurface(const int contextId) {
22
- return _registry[contextId];
98
+ std::optional<SurfaceInfo> getSurfaceMaybe(const int contextId) {
99
+ std::unique_lock<std::shared_mutex> lock(_mutex);
100
+ auto it = _registry.find(contextId);
101
+ if (it != _registry.end()) {
102
+ return it->second;
103
+ }
104
+ return std::nullopt;
23
105
  }
24
106
 
25
- void removeSurface(const int contextId) { _registry.erase(contextId); }
107
+ SurfaceInfo getSurface(const int contextId) const {
108
+ auto it = _registry.find(contextId);
109
+ if (it != _registry.end()) {
110
+ return it->second;
111
+ }
112
+ throw std::out_of_range("Surface not found");
113
+ }
114
+
115
+ void setSize(const int contextId, int width, int height) {
116
+ std::unique_lock<std::shared_mutex> lock(_mutex);
117
+ auto it = _registry.find(contextId);
118
+ if (it != _registry.end()) {
119
+ it->second.width = width;
120
+ it->second.height = height;
121
+ }
122
+ }
123
+
124
+ void
125
+ configureOffscreenSurface(const int contextId, wgpu::Instance gpu,
126
+ wgpu::Texture texture,
127
+ wgpu::SurfaceConfiguration surfaceConfiguration) {
128
+ SurfaceInfo info;
129
+ info.width = surfaceConfiguration.width;
130
+ info.height = surfaceConfiguration.height;
131
+ info.texture = texture;
132
+ info.gpu = gpu;
133
+ info.config = surfaceConfiguration;
134
+ std::unique_lock<std::shared_mutex> lock(_mutex);
135
+ _registry[contextId] = info;
136
+ }
26
137
 
27
- void updateSurface(const int contextId, float width, float height) {
28
- if (_registry.find(contextId) != _registry.end()) {
29
- _registry[contextId]->setClientWidth(width);
30
- _registry[contextId]->setClientHeight(height);
138
+ void createSurface(const int contextId, void *nativeSurface, int width,
139
+ int height,
140
+ std::shared_ptr<PlatformContext> platformContext) {
141
+ std::unique_lock<std::shared_mutex> lock(_mutex);
142
+ // 1. The scene has already be drawn offscreen
143
+ if (hasSurfaceInfo(contextId)) {
144
+ auto info = getSurface(contextId);
145
+ auto surface =
146
+ platformContext->makeSurface(info.gpu, nativeSurface, width, height);
147
+ info.config.usage = info.config.usage | wgpu::TextureUsage::CopyDst;
148
+ surface.Configure(&info.config);
149
+ info.nativeSurface = nativeSurface;
150
+ info.surface = surface;
151
+ info.width = width;
152
+ info.height = height;
153
+ info.flushTextureToSurface();
154
+ surface.Present();
155
+ updateSurface(contextId, info);
156
+ } else {
157
+ // 2. The scene has not been drawn offscreen yet, we will draw onscreen
158
+ // directly
159
+ rnwgpu::SurfaceInfo info;
160
+ info.nativeSurface = nativeSurface;
161
+ info.surface =
162
+ platformContext->makeSurface(info.gpu, nativeSurface, width, height);
163
+ info.width = width;
164
+ info.height = height;
165
+ _registry[contextId] = info;
31
166
  }
32
167
  }
33
168
  };
@@ -15,24 +15,24 @@ namespace m = margelo;
15
15
 
16
16
  class Canvas : public m::HybridObject {
17
17
  public:
18
- explicit Canvas(void* surface, const float width, const float height)
18
+ explicit Canvas(void *surface, const int width, const int height)
19
19
  : HybridObject("Canvas"), _surface(surface), _width(width),
20
20
  _height(height), _clientWidth(width), _clientHeight(height) {}
21
21
 
22
- float getWidth() { return _width; }
23
- float getHeight() { return _height; }
22
+ int getWidth() { return _width; }
23
+ int getHeight() { return _height; }
24
24
 
25
- void setWidth(const float width) { _width = width; }
26
- void setHeight(const float height) { _height = height; }
25
+ void setWidth(const int width) { _width = width; }
26
+ void setHeight(const int height) { _height = height; }
27
27
 
28
- float getClientWidth() { return _clientWidth; }
29
- float getClientHeight() { return _clientHeight; }
28
+ int getClientWidth() { return _clientWidth; }
29
+ int getClientHeight() { return _clientHeight; }
30
30
 
31
- void setClientWidth(const float width) { _clientWidth = width; }
31
+ void setClientWidth(const int width) { _clientWidth = width; }
32
32
 
33
- void setClientHeight(const float height) { _clientHeight = height; }
33
+ void setClientHeight(const int height) { _clientHeight = height; }
34
34
 
35
- void* getSurface() { return _surface; }
35
+ void *getSurface() { return _surface; }
36
36
 
37
37
  void loadHybridMethods() override {
38
38
  registerHybridGetter("surface", &Canvas::getSurface, this);
@@ -45,11 +45,11 @@ public:
45
45
  }
46
46
 
47
47
  private:
48
- void* _surface;
49
- float _width;
50
- float _height;
51
- float _clientWidth;
52
- float _clientHeight;
48
+ void *_surface;
49
+ int _width;
50
+ int _height;
51
+ int _clientWidth;
52
+ int _clientHeight;
53
53
  };
54
54
 
55
55
  } // namespace rnwgpu
@@ -23,41 +23,99 @@ void GPUCanvasContext::configure(
23
23
  if (!conv(surfaceConfiguration.usage, configuration->usage)) {
24
24
  throw std::runtime_error("Error with SurfaceConfiguration");
25
25
  }
26
- surfaceConfiguration.width = _canvas->getWidth();
27
- surfaceConfiguration.height = _canvas->getHeight();
28
- _instance.Configure(&surfaceConfiguration);
29
- _lastConfig = configuration;
30
- _width = _canvas->getWidth();
31
- _height = _canvas->getHeight();
26
+ auto width = _canvas->getWidth();
27
+ auto height = _canvas->getHeight();
28
+ surfaceConfiguration.width = width;
29
+ surfaceConfiguration.height = height;
30
+ _surfaceConfiguration = surfaceConfiguration;
31
+ // Are we onscreen now?
32
+ auto &registry = rnwgpu::SurfaceRegistry::getInstance();
33
+ auto infoVal = registry.getSurfaceMaybe(_contextId);
34
+ if (infoVal.has_value()) {
35
+ auto info = infoVal.value();
36
+ if (info.surface) {
37
+ _instance = info.surface;
38
+ _offscreenSurface = nullptr;
39
+ }
40
+ }
41
+
42
+ if (_instance) {
43
+ _instance.Configure(&surfaceConfiguration);
44
+ } else {
45
+ _offscreenSurface->configure(_surfaceConfiguration);
46
+ // Add texture to the surface registry, when the native surface is
47
+ // available, we will copy its content there This only makes sense if the on
48
+ // screen native surface is not available yet
49
+ registry.configureOffscreenSurface(_contextId, _gpu->get(),
50
+ _offscreenSurface->getCurrentTexture(),
51
+ _surfaceConfiguration);
52
+ }
32
53
  }
33
54
 
34
55
  void GPUCanvasContext::unconfigure() {
35
- _lastConfig = nullptr;
36
- _width = _canvas->getWidth();
37
- _height = _canvas->getHeight();
38
- _instance.Unconfigure();
56
+ if (_instance) {
57
+ _instance.Unconfigure();
58
+ } else if (_offscreenSurface) {
59
+ _offscreenSurface = nullptr;
60
+ }
39
61
  }
40
62
 
41
63
  std::shared_ptr<GPUTexture> GPUCanvasContext::getCurrentTexture() {
42
- // we need to reconfigure if the size of the canvas has changed
43
- if (_width != _canvas->getWidth() || _height != _canvas->getHeight()) {
44
- configure(_lastConfig);
45
- }
46
- wgpu::SurfaceTexture surfaceTexture;
47
- _instance.GetCurrentTexture(&surfaceTexture);
48
- auto texture = surfaceTexture.texture;
49
- if (texture == nullptr) {
50
- throw std::runtime_error("Couldn't get current texture");
51
- }
52
- // Default canvas texture label is ""
53
- return std::make_shared<GPUTexture>(texture, "");
64
+ auto width = _canvas->getWidth();
65
+ auto height = _canvas->getHeight();
66
+
67
+ auto prevWidth = _surfaceConfiguration.width;
68
+ auto prevHeight = _surfaceConfiguration.height;
69
+ auto sizeHasChanged = prevWidth != width || prevHeight != height;
70
+ _surfaceConfiguration.width = width;
71
+ _surfaceConfiguration.height = height;
72
+ // Get onscreen texture
73
+ if (_instance) {
74
+ // Did the surface resize?
75
+ if (sizeHasChanged) {
76
+ _instance.Configure(&_surfaceConfiguration);
77
+ }
78
+ // Get onscreen texture
79
+ wgpu::SurfaceTexture surfaceTexture;
80
+ _instance.GetCurrentTexture(&surfaceTexture);
81
+ auto texture = surfaceTexture.texture;
82
+ if (texture == nullptr) {
83
+ throw std::runtime_error("Couldn't get current texture");
84
+ }
85
+ return std::make_shared<GPUTexture>(texture, "");
86
+ } else {
87
+ // Did the surface resize?
88
+ if (sizeHasChanged) {
89
+ _offscreenSurface->configure(_surfaceConfiguration);
90
+ }
91
+ // Get offscreen texture
92
+ auto tex = _offscreenSurface->getCurrentTexture();
93
+ return std::make_shared<GPUTexture>(tex, "");
94
+ }
54
95
  }
55
96
 
56
97
  void GPUCanvasContext::present() {
57
98
  #ifdef __APPLE__
58
99
  dawn::native::metal::WaitForCommandsToBeScheduled(_device.Get());
59
100
  #endif
60
- _instance.Present();
101
+ auto &registry = rnwgpu::SurfaceRegistry::getInstance();
102
+ auto infoVal = registry.getSurfaceMaybe(_contextId);
103
+ if (infoVal.has_value()) {
104
+ auto info = infoVal.value();
105
+ // We are starting a new frame, this is a good time to update the client
106
+ _canvas->setClientWidth(info.width);
107
+ _canvas->setClientHeight(info.height);
108
+ if (_offscreenSurface) {
109
+ // Are we onscreen now?
110
+ if (info.surface) {
111
+ _instance = info.surface;
112
+ _offscreenSurface = nullptr;
113
+ }
114
+ }
115
+ }
116
+ if (_instance) {
117
+ _instance.Present();
118
+ }
61
119
  }
62
120
 
63
121
  } // namespace rnwgpu
@@ -12,8 +12,10 @@
12
12
  #include "AsyncRunner.h"
13
13
 
14
14
  #include "Canvas.h"
15
+ #include "GPU.h"
15
16
  #include "GPUCanvasConfiguration.h"
16
17
  #include "GPUTexture.h"
18
+ #include "OffscreenSurface.h"
17
19
  #include "SurfaceRegistry.h"
18
20
 
19
21
  #ifdef __APPLE__
@@ -38,9 +40,13 @@ namespace m = margelo;
38
40
 
39
41
  class GPUCanvasContext : public m::HybridObject {
40
42
  public:
41
- explicit GPUCanvasContext(wgpu::Surface instance,
42
- std::shared_ptr<Canvas> canvas)
43
- : HybridObject("GPUCanvasContext"), _instance(instance), _canvas(canvas) {
43
+ // TODO: platformContext no necessary here
44
+ GPUCanvasContext(std::shared_ptr<GPU> gpu, int contextId, int width,
45
+ int height)
46
+ : HybridObject("GPUCanvasContext"), _contextId(contextId),
47
+ _gpu(std::move(gpu)) {
48
+ _canvas = std::make_shared<Canvas>(nullptr, width, height);
49
+ _offscreenSurface = std::make_shared<OffscreenSurface>(_canvas);
44
50
  }
45
51
 
46
52
  public:
@@ -65,12 +71,15 @@ public:
65
71
  void present();
66
72
 
67
73
  private:
68
- wgpu::Surface _instance;
74
+ std::shared_ptr<OffscreenSurface> _offscreenSurface;
75
+ wgpu::Surface _instance = nullptr;
69
76
  wgpu::Device _device;
70
77
  std::shared_ptr<Canvas> _canvas;
71
- std::shared_ptr<GPUCanvasConfiguration> _lastConfig;
72
- float _width;
73
- float _height;
78
+ int _contextId;
79
+
80
+ std::shared_ptr<GPU> _gpu;
81
+ // TODO: do we need this or can it be stored in the surface registry?
82
+ wgpu::SurfaceConfiguration _surfaceConfiguration;
74
83
  };
75
84
 
76
85
  } // namespace rnwgpu
@@ -69,14 +69,17 @@ std::shared_ptr<GPUShaderModule> GPUDevice::createShaderModule(
69
69
  std::shared_ptr<GPUShaderModuleDescriptor> descriptor) {
70
70
  wgpu::ShaderModuleWGSLDescriptor wgsl_desc{};
71
71
  wgpu::ShaderModuleDescriptor sm_desc{};
72
- wgsl_desc.code = descriptor->code.c_str();
73
- sm_desc.label = descriptor->label.value_or("").c_str();
72
+ Convertor conv;
73
+ if (!conv(wgsl_desc.code, descriptor->code) ||
74
+ !conv(sm_desc.label, descriptor->label)) {
75
+ return {};
76
+ }
74
77
  sm_desc.nextInChain = &wgsl_desc;
75
78
  if (descriptor->code.find('\0') != std::string::npos) {
76
79
  return std::make_shared<GPUShaderModule>(
77
80
  _instance.CreateErrorShaderModule(
78
81
  &sm_desc, "The WGSL shader contains an illegal character '\\0'"),
79
- _async, descriptor->label.value_or(""));
82
+ _async, sm_desc.label);
80
83
  }
81
84
  auto module = _instance.CreateShaderModule(&sm_desc);
82
85
  return std::make_shared<GPUShaderModule>(module, _async,
@@ -0,0 +1,49 @@
1
+ #pragma once
2
+
3
+ #include "webgpu/webgpu_cpp.h"
4
+
5
+ #include "Canvas.h"
6
+
7
+ namespace rnwgpu {
8
+
9
+ class OffscreenSurface {
10
+ public:
11
+ explicit OffscreenSurface(std::shared_ptr<Canvas> canvas)
12
+ : _canvas(std::move(canvas)) {
13
+ #if defined(__ANDROID__)
14
+ _textureFormat = wgpu::TextureFormat::RGBA8Unorm;
15
+ #else
16
+ _textureFormat = wgpu::TextureFormat::BGRA8Unorm;
17
+ #endif // defined(__ANDROID__)
18
+ }
19
+
20
+ void configure(const wgpu::SurfaceConfiguration &config) {
21
+ // Configure the canvas context with the device and format
22
+ _device = config.device;
23
+
24
+ wgpu::TextureDescriptor textureDesc;
25
+ textureDesc.size.width = _canvas->getWidth();
26
+ textureDesc.size.height = _canvas->getHeight();
27
+ textureDesc.format = _textureFormat;
28
+ textureDesc.usage = wgpu::TextureUsage::RenderAttachment |
29
+ wgpu::TextureUsage::CopySrc |
30
+ wgpu::TextureUsage::TextureBinding;
31
+
32
+ _texture = _device.CreateTexture(&textureDesc);
33
+ }
34
+
35
+ wgpu::Texture getCurrentTexture() {
36
+ if (!_texture) {
37
+ throw std::runtime_error("Texture is not configured");
38
+ }
39
+ return _texture;
40
+ }
41
+
42
+ private:
43
+ wgpu::TextureFormat _textureFormat;
44
+ wgpu::Texture _texture = nullptr;
45
+ wgpu::Device _device;
46
+ std::shared_ptr<Canvas> _canvas;
47
+ };
48
+
49
+ } // namespace rnwgpu