react-native-webgpu 0.6.0 → 0.6.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.
- package/android/cpp/cpp-adapter.cpp +35 -13
- package/android/src/main/java/com/webgpu/WebGPUAHBView.java +2 -2
- package/android/src/main/java/com/webgpu/WebGPUAPI.java +7 -2
- package/android/src/main/java/com/webgpu/WebGPUSurfaceView.java +3 -1
- package/android/src/main/java/com/webgpu/WebGPUTextureView.java +11 -7
- package/android/src/main/java/com/webgpu/WebGPUView.java +10 -7
- package/android/src/main/java/com/webgpu/WebGPUViewManager.java +6 -0
- package/apple/MetalView.mm +33 -8
- package/cpp/rnwgpu/RNWebGPUManager.cpp +14 -1
- package/cpp/rnwgpu/RNWebGPUManager.h +9 -0
- package/cpp/rnwgpu/SurfaceRegistry.h +469 -131
- package/cpp/rnwgpu/api/GPUAdapter.cpp +10 -3
- package/cpp/rnwgpu/api/GPUAdapter.h +5 -4
- package/cpp/rnwgpu/api/GPUBuffer.cpp +12 -2
- package/cpp/rnwgpu/api/GPUBuffer.h +3 -2
- package/cpp/rnwgpu/api/GPUCanvasContext.cpp +33 -19
- package/cpp/rnwgpu/api/GPUCanvasContext.h +3 -1
- package/cpp/rnwgpu/api/GPUDevice.cpp +32 -17
- package/cpp/rnwgpu/api/GPUDevice.h +9 -7
- package/cpp/rnwgpu/api/GPUQueue.cpp +6 -2
- package/cpp/rnwgpu/api/GPUQueue.h +3 -3
- package/cpp/rnwgpu/api/GPUShaderModule.cpp +7 -2
- package/cpp/rnwgpu/api/GPUShaderModule.h +3 -3
- package/cpp/rnwgpu/api/RNWebGPU.h +22 -1
- package/cpp/rnwgpu/async/RuntimeContext.h +9 -2
- package/lib/commonjs/Canvas.js +10 -0
- package/lib/commonjs/Canvas.js.map +1 -1
- package/lib/commonjs/WebPolyfillGPUModule.js +2 -0
- package/lib/commonjs/WebPolyfillGPUModule.js.map +1 -1
- package/lib/module/Canvas.js +11 -1
- package/lib/module/Canvas.js.map +1 -1
- package/lib/module/WebPolyfillGPUModule.js +2 -0
- package/lib/module/WebPolyfillGPUModule.js.map +1 -1
- package/lib/typescript/lib/commonjs/Canvas.d.ts.map +1 -1
- package/lib/typescript/lib/module/Canvas.d.ts.map +1 -1
- package/lib/typescript/src/Canvas.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +2 -6
- package/src/Canvas.tsx +11 -1
- package/src/WebPolyfillGPUModule.ts +2 -0
- package/src/index.tsx +3 -0
- package/android/src/main/java/com/webgpu/WebGPUBaseView.java +0 -61
|
@@ -25,8 +25,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUModule_initializeNative(
|
|
|
25
25
|
auto jsCallInvoker{
|
|
26
26
|
facebook::jni::alias_ref<facebook::react::CallInvokerHolder::javaobject>{
|
|
27
27
|
reinterpret_cast<facebook::react::CallInvokerHolder::javaobject>(
|
|
28
|
-
jsCallInvokerHolder)} -> cthis()
|
|
29
|
-
->getCallInvoker()};
|
|
28
|
+
jsCallInvokerHolder)} -> cthis()->getCallInvoker()};
|
|
30
29
|
auto platformContext =
|
|
31
30
|
std::make_shared<rnwgpu::AndroidPlatformContext>(globalBlobModule);
|
|
32
31
|
manager = std::make_shared<rnwgpu::RNWebGPUManager>(runtime, jsCallInvoker,
|
|
@@ -37,35 +36,58 @@ extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUView_onSurfaceChanged(
|
|
|
37
36
|
JNIEnv *env, jobject thiz, jobject surface, jint contextId, jfloat width,
|
|
38
37
|
jfloat height) {
|
|
39
38
|
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
40
|
-
registry.getSurfaceInfo(contextId)
|
|
41
|
-
|
|
39
|
+
if (auto info = registry.getSurfaceInfo(contextId)) {
|
|
40
|
+
info->resize(static_cast<int>(width), static_cast<int>(height));
|
|
41
|
+
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUView_onSurfaceCreate(
|
|
45
45
|
JNIEnv *env, jobject thiz, jobject jSurface, jint contextId, jfloat width,
|
|
46
46
|
jfloat height) {
|
|
47
|
+
if (manager == nullptr) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// ANativeWindow_fromSurface acquires a reference; SurfaceInfo releases it
|
|
51
|
+
// (via the releaser below) once it is done with the window.
|
|
47
52
|
auto window = ANativeWindow_fromSurface(env, jSurface);
|
|
48
|
-
|
|
53
|
+
if (window == nullptr) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
49
56
|
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
50
57
|
auto gpu = manager->_gpu;
|
|
51
58
|
auto surface = manager->_platformContext->makeSurface(
|
|
52
59
|
gpu, window, static_cast<int>(width), static_cast<int>(height));
|
|
53
|
-
registry
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
// Find-or-create + attach runs atomically under the registry lock so a
|
|
61
|
+
// concurrent destroyContext cannot orphan this surface.
|
|
62
|
+
auto info = registry.attachSurface(
|
|
63
|
+
contextId, gpu, static_cast<int>(width), static_cast<int>(height), window,
|
|
64
|
+
surface, [](void *nativeSurface) {
|
|
65
|
+
ANativeWindow_release(static_cast<ANativeWindow *>(nativeSurface));
|
|
66
|
+
});
|
|
67
|
+
// The attach is adopted at the next frame boundary by the rendering thread;
|
|
68
|
+
// schedule a flush so contexts that are not currently rendering still pick
|
|
69
|
+
// it up (and present their last offscreen frame).
|
|
70
|
+
manager->flushPendingSurfaceTransition(info);
|
|
57
71
|
}
|
|
58
72
|
|
|
59
73
|
extern "C" JNIEXPORT void JNICALL
|
|
60
74
|
Java_com_webgpu_WebGPUView_switchToOffscreenSurface(JNIEnv *env, jobject thiz,
|
|
61
75
|
jint contextId) {
|
|
62
76
|
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
63
|
-
auto
|
|
64
|
-
|
|
77
|
+
if (auto info = registry.getSurfaceInfo(contextId)) {
|
|
78
|
+
info->switchToOffscreen();
|
|
79
|
+
}
|
|
65
80
|
}
|
|
66
81
|
|
|
67
|
-
extern "C" JNIEXPORT void JNICALL
|
|
82
|
+
extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUView_onViewDestroyed(
|
|
68
83
|
JNIEnv *env, jobject thiz, jint contextId) {
|
|
84
|
+
// The view dies with its Canvas (contextIds are never reused), so view
|
|
85
|
+
// teardown retires the registry entry. The JS-side cleanup
|
|
86
|
+
// (RNWebGPU.destroyContext) only handles entries that never had a native
|
|
87
|
+
// surface; see RNWebGPU::destroyContext for the ownership split.
|
|
69
88
|
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
89
|
+
if (auto info = registry.getSurfaceInfo(contextId)) {
|
|
90
|
+
info->detachSurface();
|
|
91
|
+
}
|
|
70
92
|
registry.removeSurfaceInfo(contextId);
|
|
71
|
-
}
|
|
93
|
+
}
|
|
@@ -254,9 +254,9 @@ public class WebGPUAHBView extends View implements ImageReader.OnImageAvailableL
|
|
|
254
254
|
protected void onDetachedFromWindow() {
|
|
255
255
|
super.onDetachedFromWindow();
|
|
256
256
|
|
|
257
|
-
//
|
|
257
|
+
// Detach: rendering falls back to the offscreen texture until reattach.
|
|
258
258
|
if (mSurfaceCreated) {
|
|
259
|
-
mApi.
|
|
259
|
+
mApi.surfaceOffscreen();
|
|
260
260
|
mSurfaceCreated = false;
|
|
261
261
|
}
|
|
262
262
|
|
|
@@ -4,6 +4,13 @@ import android.view.Surface;
|
|
|
4
4
|
|
|
5
5
|
import com.facebook.proguard.annotations.DoNotStrip;
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Surface lifecycle events a WebGPU child view reports. The registry entry
|
|
9
|
+
* itself is owned by the JS Canvas component (created lazily, removed via
|
|
10
|
+
* RNWebGPU.destroyContext on unmount); views only attach and detach surfaces.
|
|
11
|
+
* A detached context keeps rendering into an offscreen texture whose content
|
|
12
|
+
* is blitted onto the next attached surface.
|
|
13
|
+
*/
|
|
7
14
|
public interface WebGPUAPI {
|
|
8
15
|
|
|
9
16
|
void surfaceCreated(
|
|
@@ -14,7 +21,5 @@ public interface WebGPUAPI {
|
|
|
14
21
|
Surface surface
|
|
15
22
|
);
|
|
16
23
|
|
|
17
|
-
void surfaceDestroyed();
|
|
18
|
-
|
|
19
24
|
void surfaceOffscreen();
|
|
20
25
|
}
|
|
@@ -21,7 +21,9 @@ public class WebGPUSurfaceView extends SurfaceView implements SurfaceHolder.Call
|
|
|
21
21
|
@Override
|
|
22
22
|
protected void onDetachedFromWindow() {
|
|
23
23
|
super.onDetachedFromWindow();
|
|
24
|
-
|
|
24
|
+
// surfaceDestroyed() normally fires during detach as well; going offscreen
|
|
25
|
+
// is idempotent, so this is just a safety net for paths where it does not.
|
|
26
|
+
mApi.surfaceOffscreen();
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
@Override
|
|
@@ -7,12 +7,11 @@ import android.view.Surface;
|
|
|
7
7
|
import android.view.TextureView;
|
|
8
8
|
import androidx.annotation.NonNull;
|
|
9
9
|
|
|
10
|
-
import org.w3c.dom.Text;
|
|
11
|
-
|
|
12
10
|
@SuppressLint("ViewConstructor")
|
|
13
11
|
public class WebGPUTextureView extends TextureView implements TextureView.SurfaceTextureListener {
|
|
14
12
|
|
|
15
13
|
WebGPUAPI mApi;
|
|
14
|
+
private Surface mSurface;
|
|
16
15
|
|
|
17
16
|
public WebGPUTextureView(Context context, WebGPUAPI api) {
|
|
18
17
|
super(context);
|
|
@@ -23,19 +22,24 @@ public class WebGPUTextureView extends TextureView implements TextureView.Surfac
|
|
|
23
22
|
|
|
24
23
|
@Override
|
|
25
24
|
public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int width, int height) {
|
|
26
|
-
|
|
27
|
-
mApi.surfaceCreated(
|
|
25
|
+
mSurface = new Surface(surfaceTexture);
|
|
26
|
+
mApi.surfaceCreated(mSurface);
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
@Override
|
|
31
30
|
public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surfaceTexture, int width, int height) {
|
|
32
|
-
|
|
33
|
-
mApi.surfaceChanged(surface);
|
|
31
|
+
mApi.surfaceChanged(mSurface);
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
@Override
|
|
37
35
|
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
|
|
38
|
-
|
|
36
|
+
// Detach first (synchronous through JNI) so the native side has dropped
|
|
37
|
+
// its window reference before we release ours.
|
|
38
|
+
mApi.surfaceOffscreen();
|
|
39
|
+
if (mSurface != null) {
|
|
40
|
+
mSurface.release();
|
|
41
|
+
mSurface = null;
|
|
42
|
+
}
|
|
39
43
|
return true;
|
|
40
44
|
}
|
|
41
45
|
|
|
@@ -73,16 +73,19 @@ public class WebGPUView extends ReactViewGroup implements WebGPUAPI {
|
|
|
73
73
|
onSurfaceChanged(surface, mContextId, width, height);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
@Override
|
|
77
|
-
public void surfaceDestroyed() {
|
|
78
|
-
onSurfaceDestroy(mContextId);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
76
|
@Override
|
|
82
77
|
public void surfaceOffscreen() {
|
|
83
78
|
switchToOffscreenSurface(mContextId);
|
|
84
79
|
}
|
|
85
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Called from WebGPUViewManager.onDropViewInstance when React removes this
|
|
83
|
+
* view: the view dies with its Canvas, so it retires the registry entry.
|
|
84
|
+
*/
|
|
85
|
+
public void destroy() {
|
|
86
|
+
onViewDestroyed(mContextId);
|
|
87
|
+
}
|
|
88
|
+
|
|
86
89
|
@DoNotStrip
|
|
87
90
|
private native void onSurfaceCreate(
|
|
88
91
|
Surface surface,
|
|
@@ -100,9 +103,9 @@ public class WebGPUView extends ReactViewGroup implements WebGPUAPI {
|
|
|
100
103
|
);
|
|
101
104
|
|
|
102
105
|
@DoNotStrip
|
|
103
|
-
private native void
|
|
106
|
+
private native void switchToOffscreenSurface(int contextId);
|
|
104
107
|
|
|
105
108
|
@DoNotStrip
|
|
106
|
-
private native void
|
|
109
|
+
private native void onViewDestroyed(int contextId);
|
|
107
110
|
|
|
108
111
|
}
|
|
@@ -24,6 +24,12 @@ public class WebGPUViewManager extends WebGPUViewManagerSpec<WebGPUView> {
|
|
|
24
24
|
return new WebGPUView(context);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
@Override
|
|
28
|
+
public void onDropViewInstance(@NonNull WebGPUView view) {
|
|
29
|
+
super.onDropViewInstance(view);
|
|
30
|
+
view.destroy();
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
@Override
|
|
28
34
|
@ReactProp(name = "transparent")
|
|
29
35
|
public void setTransparent(WebGPUView view, boolean value) {
|
package/apple/MetalView.mm
CHANGED
|
@@ -23,27 +23,52 @@
|
|
|
23
23
|
- (void)configure {
|
|
24
24
|
auto size = self.frame.size;
|
|
25
25
|
std::shared_ptr<rnwgpu::RNWebGPUManager> manager = [WebGPUModule getManager];
|
|
26
|
-
|
|
26
|
+
if (manager == nullptr) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Retain the layer for as long as SurfaceInfo holds the pointer: the
|
|
30
|
+
// latched attach (and the flush lambda that adopts it) can outlive this
|
|
31
|
+
// view, e.g. across a dev reload where the registry is cleared before
|
|
32
|
+
// dealloc runs. Balanced by the releaser below.
|
|
33
|
+
void *nativeSurface = (void *)CFBridgingRetain(self.layer);
|
|
27
34
|
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
28
35
|
auto gpu = manager->_gpu;
|
|
29
36
|
auto surface = manager->_platformContext->makeSurface(
|
|
30
37
|
gpu, nativeSurface, size.width, size.height);
|
|
31
|
-
registry
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
// Find-or-create + attach runs atomically under the registry lock so a
|
|
39
|
+
// concurrent destroyContext cannot orphan this surface.
|
|
40
|
+
auto info = registry.attachSurface(
|
|
41
|
+
[_contextId intValue], gpu, size.width, size.height, nativeSurface,
|
|
42
|
+
surface, [](void *layer) {
|
|
43
|
+
// The releaser can run on the rendering thread; CALayer teardown
|
|
44
|
+
// belongs on the main thread.
|
|
45
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
46
|
+
CFBridgingRelease(layer);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
// The attach is adopted at the next frame boundary by the rendering thread;
|
|
50
|
+
// schedule a flush so contexts that are not currently rendering still pick
|
|
51
|
+
// it up (and present their last offscreen frame).
|
|
52
|
+
manager->flushPendingSurfaceTransition(info);
|
|
35
53
|
}
|
|
36
54
|
|
|
37
55
|
- (void)update {
|
|
38
56
|
auto size = self.frame.size;
|
|
39
57
|
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
40
|
-
registry.getSurfaceInfo([_contextId intValue])
|
|
41
|
-
|
|
58
|
+
if (auto info = registry.getSurfaceInfo([_contextId intValue])) {
|
|
59
|
+
info->resize(size.width, size.height);
|
|
60
|
+
}
|
|
42
61
|
}
|
|
43
62
|
|
|
44
63
|
- (void)dealloc {
|
|
64
|
+
// The view dies with its Canvas (contextIds are never reused), so view
|
|
65
|
+
// teardown retires the registry entry. The JS-side cleanup
|
|
66
|
+
// (RNWebGPU.destroyContext) only handles entries that never had a native
|
|
67
|
+
// surface; see RNWebGPU::destroyContext for the ownership split.
|
|
45
68
|
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
46
|
-
|
|
69
|
+
if (auto info = registry.getSurfaceInfo([_contextId intValue])) {
|
|
70
|
+
info->detachSurface();
|
|
71
|
+
}
|
|
47
72
|
registry.removeSurfaceInfo([_contextId intValue]);
|
|
48
73
|
}
|
|
49
74
|
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
#include "GPURenderPassEncoder.h"
|
|
32
32
|
#include "GPURenderPipeline.h"
|
|
33
33
|
#include "GPUSampler.h"
|
|
34
|
+
#include "GPUShaderModule.h"
|
|
34
35
|
#include "GPUSharedFence.h"
|
|
35
36
|
#include "GPUSharedTextureMemory.h"
|
|
36
|
-
#include "GPUShaderModule.h"
|
|
37
37
|
#include "GPUSupportedLimits.h"
|
|
38
38
|
#include "GPUTexture.h"
|
|
39
39
|
#include "GPUTextureView.h"
|
|
@@ -237,7 +237,20 @@ void RNWebGPUManager::installWebGPUWorkletHelpers(jsi::Runtime &runtime) {
|
|
|
237
237
|
runtime.global().setProperty(runtime, "__webgpuBox", std::move(boxFunc));
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
+
void RNWebGPUManager::flushPendingSurfaceTransition(
|
|
241
|
+
std::shared_ptr<SurfaceInfo> info) {
|
|
242
|
+
if (info == nullptr || _jsCallInvoker == nullptr) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
_jsCallInvoker->invokeAsync(
|
|
246
|
+
[info = std::move(info)] { info->applyPendingAttach(); });
|
|
247
|
+
}
|
|
248
|
+
|
|
240
249
|
RNWebGPUManager::~RNWebGPUManager() {
|
|
250
|
+
// Drop all canvas registry entries: after a reload the JS side restarts its
|
|
251
|
+
// contextId counter, and stale entries would alias new canvases onto dead
|
|
252
|
+
// surfaces.
|
|
253
|
+
SurfaceRegistry::getInstance().clear();
|
|
241
254
|
_jsRuntime = nullptr;
|
|
242
255
|
_jsCallInvoker = nullptr;
|
|
243
256
|
}
|
|
@@ -34,6 +34,15 @@ public:
|
|
|
34
34
|
*/
|
|
35
35
|
static void installWebGPUWorkletHelpers(jsi::Runtime &runtime);
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Applies a surface attach latched by the platform UI thread (see
|
|
39
|
+
* SurfaceInfo::applyPendingAttach) from the JS thread. Surface attaches are
|
|
40
|
+
* normally adopted at the next frame boundary by whichever thread renders;
|
|
41
|
+
* this flush covers contexts that are not actively rendering (static
|
|
42
|
+
* content), so the last offscreen frame still makes it on screen.
|
|
43
|
+
*/
|
|
44
|
+
void flushPendingSurfaceTransition(std::shared_ptr<SurfaceInfo> info);
|
|
45
|
+
|
|
37
46
|
private:
|
|
38
47
|
jsi::Runtime *_jsRuntime;
|
|
39
48
|
std::shared_ptr<facebook::react::CallInvoker> _jsCallInvoker;
|