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.
- package/android/cpp/cpp-adapter.cpp +13 -35
- package/android/src/main/java/com/webgpu/WebGPUModule.java +0 -37
- package/android/src/main/java/com/webgpu/WebGPUView.java +0 -1
- package/android/src/main/java/com/webgpu/WebGPUViewPackage.java +1 -1
- package/cpp/rnwgpu/RNWebGPUManager.h +2 -2
- package/cpp/rnwgpu/SurfaceRegistry.h +148 -13
- package/cpp/rnwgpu/api/Canvas.h +15 -15
- package/cpp/rnwgpu/api/GPUCanvasContext.cpp +81 -23
- package/cpp/rnwgpu/api/GPUCanvasContext.h +16 -7
- package/cpp/rnwgpu/api/GPUDevice.cpp +6 -3
- package/cpp/rnwgpu/api/OffscreenSurface.h +49 -0
- package/cpp/rnwgpu/api/RNWebGPU.h +21 -10
- package/ios/MetalView.mm +11 -0
- package/ios/SurfaceUtils.h +2 -0
- package/ios/SurfaceUtils.mm +16 -4
- package/ios/WebGPUModule.mm +8 -25
- package/ios/WebGPUView.mm +9 -6
- package/lib/commonjs/Canvas.js +79 -18
- package/lib/commonjs/Canvas.js.map +1 -1
- package/lib/commonjs/Offscreen.js +124 -0
- package/lib/commonjs/Offscreen.js.map +1 -0
- package/lib/commonjs/index.js +12 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils.js +26 -15
- package/lib/commonjs/utils.js.map +1 -1
- package/lib/module/Canvas.js +80 -19
- package/lib/module/Canvas.js.map +1 -1
- package/lib/module/Offscreen.js +117 -0
- package/lib/module/Offscreen.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils.js +25 -15
- package/lib/module/utils.js.map +1 -1
- package/lib/typescript/lib/commonjs/Offscreen.d.ts +32 -0
- package/lib/typescript/lib/commonjs/Offscreen.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/utils.d.ts +5 -1
- package/lib/typescript/lib/commonjs/utils.d.ts.map +1 -1
- package/lib/typescript/lib/module/Canvas.d.ts.map +1 -1
- package/lib/typescript/lib/module/Offscreen.d.ts +31 -0
- package/lib/typescript/lib/module/Offscreen.d.ts.map +1 -0
- package/lib/typescript/lib/module/index.d.ts +1 -0
- package/lib/typescript/lib/module/utils.d.ts +5 -1
- package/lib/typescript/lib/module/utils.d.ts.map +1 -1
- package/lib/typescript/src/Canvas.d.ts +6 -4
- package/lib/typescript/src/Canvas.d.ts.map +1 -1
- package/lib/typescript/src/Offscreen.d.ts +41 -0
- package/lib/typescript/src/Offscreen.d.ts.map +1 -0
- package/lib/typescript/src/__tests__/setup.d.ts +5 -4
- package/lib/typescript/src/__tests__/setup.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/lib/typescript/src/utils.d.ts +6 -3
- package/lib/typescript/src/utils.d.ts.map +1 -1
- package/libs/android/arm64-v8a/libwebgpu_dawn.so +0 -0
- package/libs/android/armeabi-v7a/libwebgpu_dawn.so +0 -0
- package/libs/android/x86/libwebgpu_dawn.so +0 -0
- package/libs/android/x86_64/libwebgpu_dawn.so +0 -0
- package/libs/apple/arm64_iphoneos/libwebgpu_dawn.a +0 -0
- package/libs/apple/arm64_iphonesimulator/libwebgpu_dawn.a +0 -0
- package/libs/apple/arm64_xros/libwebgpu_dawn.a +0 -0
- package/libs/apple/arm64_xrsimulator/libwebgpu_dawn.a +0 -0
- package/libs/apple/{libwebgpu_dawn.a → iphonesimulator/libwebgpu_dawn.a} +0 -0
- package/libs/apple/libwebgpu_dawn.xcframework/Info.plist +45 -0
- package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/libwebgpu_dawn.a +0 -0
- package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/libwebgpu_dawn.a +0 -0
- package/libs/apple/{libwebgpu_dawn_macosx.xcframework → libwebgpu_dawn.xcframework}/macos-arm64_x86_64/libwebgpu_dawn.a +0 -0
- package/libs/apple/{libwebgpu_dawn_visionos.xcframework → libwebgpu_dawn.xcframework}/xros-arm64/libwebgpu_dawn.a +0 -0
- package/libs/apple/{x86_64_xrsimulator → libwebgpu_dawn.xcframework/xros-arm64-simulator}/libwebgpu_dawn.a +0 -0
- package/libs/apple/universal_macosx/libwebgpu_dawn.a +0 -0
- package/libs/apple/x86_64_iphonesimulator/libwebgpu_dawn.a +0 -0
- package/package.json +1 -1
- package/react-native-wgpu.podspec +2 -8
- package/src/Canvas.tsx +101 -37
- package/src/Offscreen.ts +164 -0
- package/src/__tests__/ExternalTexture.spec.ts +4 -4
- package/src/__tests__/Texture.spec.ts +8 -2
- package/src/__tests__/demos/ABuffer.spec.ts +17 -12
- package/src/__tests__/demos/Blur.spec.ts +2 -1
- package/src/__tests__/demos/Cube.spec.ts +16 -12
- package/src/__tests__/demos/FractalCube.spec.ts +6 -5
- package/src/__tests__/demos/OcclusionQuery.spec.ts +3 -3
- package/src/__tests__/demos/RenderBundles.spec.ts +4 -3
- package/src/__tests__/demos/Triangle.spec.ts +27 -9
- package/src/__tests__/setup.ts +25 -10
- package/src/index.tsx +1 -0
- package/src/utils.ts +28 -18
- package/lib/typescript/src/__tests__/components/DrawingContext.d.ts +0 -12
- package/lib/typescript/src/__tests__/components/DrawingContext.d.ts.map +0 -1
- package/libs/apple/libwebgpu_dawn_macosx.xcframework/Info.plist +0 -28
- package/libs/apple/libwebgpu_dawn_visionos.a +0 -0
- package/libs/apple/libwebgpu_dawn_visionos.xcframework/Info.plist +0 -44
- package/libs/apple/libwebgpu_dawn_visionos.xcframework/xros-arm64_x86_64-simulator/libwebgpu_dawn_visionos.a +0 -0
- package/src/__tests__/components/DrawingContext.ts +0 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAGA,cAAc,UAAU,CAAC;AACzB,cAAc,6BAA6B,CAAC;AAC5C,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAGA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { CanvasRef } from "./Canvas";
|
|
1
|
+
import type { RNCanvasContext, CanvasRef } from "./Canvas";
|
|
3
2
|
type Unsubscribe = () => void;
|
|
4
3
|
export declare const warnIfNotHardwareAccelerated: (adapter: GPUAdapter) => void;
|
|
5
|
-
export declare const
|
|
4
|
+
export declare const useGPUContext: () => {
|
|
5
|
+
ref: import("react").RefObject<CanvasRef>;
|
|
6
|
+
context: RNCanvasContext | null;
|
|
7
|
+
};
|
|
8
|
+
export declare const useCanvasEffect: (effect: () => void | Unsubscribe | Promise<Unsubscribe | void> | Promise<void>) => import("react").RefObject<CanvasRef>;
|
|
6
9
|
export {};
|
|
7
10
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE3D,KAAK,WAAW,GAAG,MAAM,IAAI,CAAC;AAE9B,eAAO,MAAM,4BAA4B,YAAa,UAAU,SAM/D,CAAC;AAEF,eAAO,MAAM,aAAa;;;CAOzB,CAAC;AAEF,eAAO,MAAM,eAAe,WAClB,MACJ,IAAI,GACJ,WAAW,GACX,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,GAC3B,OAAO,CAAC,IAAI,CAAC,yCAuBlB,CAAC"}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -4,6 +4,36 @@
|
|
|
4
4
|
<dict>
|
|
5
5
|
<key>AvailableLibraries</key>
|
|
6
6
|
<array>
|
|
7
|
+
<dict>
|
|
8
|
+
<key>BinaryPath</key>
|
|
9
|
+
<string>libwebgpu_dawn.a</string>
|
|
10
|
+
<key>LibraryIdentifier</key>
|
|
11
|
+
<string>xros-arm64</string>
|
|
12
|
+
<key>LibraryPath</key>
|
|
13
|
+
<string>libwebgpu_dawn.a</string>
|
|
14
|
+
<key>SupportedArchitectures</key>
|
|
15
|
+
<array>
|
|
16
|
+
<string>arm64</string>
|
|
17
|
+
</array>
|
|
18
|
+
<key>SupportedPlatform</key>
|
|
19
|
+
<string>xros</string>
|
|
20
|
+
</dict>
|
|
21
|
+
<dict>
|
|
22
|
+
<key>BinaryPath</key>
|
|
23
|
+
<string>libwebgpu_dawn.a</string>
|
|
24
|
+
<key>LibraryIdentifier</key>
|
|
25
|
+
<string>xros-arm64-simulator</string>
|
|
26
|
+
<key>LibraryPath</key>
|
|
27
|
+
<string>libwebgpu_dawn.a</string>
|
|
28
|
+
<key>SupportedArchitectures</key>
|
|
29
|
+
<array>
|
|
30
|
+
<string>arm64</string>
|
|
31
|
+
</array>
|
|
32
|
+
<key>SupportedPlatform</key>
|
|
33
|
+
<string>xros</string>
|
|
34
|
+
<key>SupportedPlatformVariant</key>
|
|
35
|
+
<string>simulator</string>
|
|
36
|
+
</dict>
|
|
7
37
|
<dict>
|
|
8
38
|
<key>BinaryPath</key>
|
|
9
39
|
<string>libwebgpu_dawn.a</string>
|
|
@@ -35,6 +65,21 @@
|
|
|
35
65
|
<key>SupportedPlatform</key>
|
|
36
66
|
<string>ios</string>
|
|
37
67
|
</dict>
|
|
68
|
+
<dict>
|
|
69
|
+
<key>BinaryPath</key>
|
|
70
|
+
<string>libwebgpu_dawn.a</string>
|
|
71
|
+
<key>LibraryIdentifier</key>
|
|
72
|
+
<string>macos-arm64_x86_64</string>
|
|
73
|
+
<key>LibraryPath</key>
|
|
74
|
+
<string>libwebgpu_dawn.a</string>
|
|
75
|
+
<key>SupportedArchitectures</key>
|
|
76
|
+
<array>
|
|
77
|
+
<string>arm64</string>
|
|
78
|
+
<string>x86_64</string>
|
|
79
|
+
</array>
|
|
80
|
+
<key>SupportedPlatform</key>
|
|
81
|
+
<string>macos</string>
|
|
82
|
+
</dict>
|
|
38
83
|
</array>
|
|
39
84
|
<key>CFBundlePackageType</key>
|
|
40
85
|
<string>XFWK</string>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -15,17 +15,11 @@ Pod::Spec.new do |s|
|
|
|
15
15
|
s.source = { :git => "https://github.com/wcandillon/react-native-webgpu.git", :tag => "#{s.version}" }
|
|
16
16
|
|
|
17
17
|
s.source_files = [
|
|
18
|
-
"ios/**/*.{h,c,cc,cpp,m,mm,swift}",
|
|
18
|
+
"ios/**/*.{h,c,cc,cpp,m,mm,swift}",
|
|
19
19
|
"cpp/**/*.{h,cpp}"
|
|
20
20
|
]
|
|
21
21
|
|
|
22
|
-
s.
|
|
23
|
-
'libs/apple/libwebgpu_dawn.xcframework',
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
s.visionos.vendored_frameworks = [
|
|
27
|
-
'libs/apple/libwebgpu_dawn_visionos.xcframework',
|
|
28
|
-
]
|
|
22
|
+
s.vendored_frameworks = 'libs/apple/libwebgpu_dawn.xcframework'
|
|
29
23
|
|
|
30
24
|
s.pod_target_xcconfig = {
|
|
31
25
|
'HEADER_SEARCH_PATHS' => '$(PODS_TARGET_SRCROOT)/cpp',
|
package/src/Canvas.tsx
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import type { ViewProps } from "react-native";
|
|
2
|
-
import {
|
|
1
|
+
import type { ViewProps, LayoutChangeEvent } from "react-native";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import {
|
|
4
|
+
forwardRef,
|
|
5
|
+
useEffect,
|
|
6
|
+
useImperativeHandle,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
useLayoutEffect,
|
|
10
|
+
useCallback,
|
|
11
|
+
} from "react";
|
|
12
|
+
import type { RefObject } from "react";
|
|
3
13
|
|
|
4
14
|
import WebGPUNativeView from "./WebGPUViewNativeComponent";
|
|
5
|
-
import WebGPUNativeModule from "./NativeWebGPUModule";
|
|
6
15
|
|
|
7
16
|
let CONTEXT_COUNTER = 1;
|
|
8
17
|
function generateContextId() {
|
|
@@ -10,12 +19,16 @@ function generateContextId() {
|
|
|
10
19
|
}
|
|
11
20
|
|
|
12
21
|
declare global {
|
|
13
|
-
// eslint-disable-next-line no-var
|
|
14
|
-
var __WebGPUContextRegistry: Record<number, NativeCanvas>;
|
|
15
22
|
// eslint-disable-next-line no-var
|
|
16
23
|
var RNWebGPU: {
|
|
17
24
|
gpu: GPU;
|
|
18
|
-
|
|
25
|
+
fabric: boolean;
|
|
26
|
+
getNativeSurface: (contextId: number) => NativeCanvas;
|
|
27
|
+
MakeWebGPUCanvasContext: (
|
|
28
|
+
contextId: number,
|
|
29
|
+
width: number,
|
|
30
|
+
height: number,
|
|
31
|
+
) => RNCanvasContext;
|
|
19
32
|
DecodeToUTF8: (buffer: NodeJS.ArrayBufferView | ArrayBuffer) => string;
|
|
20
33
|
createImageBitmap: typeof createImageBitmap;
|
|
21
34
|
};
|
|
@@ -31,45 +44,96 @@ export interface NativeCanvas {
|
|
|
31
44
|
clientHeight: number;
|
|
32
45
|
}
|
|
33
46
|
|
|
34
|
-
|
|
35
|
-
const WebGPUContextRegistry = global.__WebGPUContextRegistry;
|
|
36
|
-
|
|
37
|
-
type CanvasContext = GPUCanvasContext & {
|
|
47
|
+
export type RNCanvasContext = GPUCanvasContext & {
|
|
38
48
|
present: () => void;
|
|
39
49
|
};
|
|
40
50
|
|
|
41
51
|
export interface CanvasRef {
|
|
42
|
-
getContext(contextName: "webgpu"):
|
|
52
|
+
getContext(contextName: "webgpu"): RNCanvasContext | null;
|
|
43
53
|
getNativeSurface: () => NativeCanvas;
|
|
54
|
+
whenReady: (callback: () => void) => void;
|
|
44
55
|
}
|
|
45
56
|
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
interface Size {
|
|
58
|
+
width: number;
|
|
59
|
+
height: number;
|
|
60
|
+
}
|
|
48
61
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
const useSizeFabric = (ref: RefObject<View>) => {
|
|
63
|
+
const [size, setSize] = useState<null | Size>(null);
|
|
64
|
+
useLayoutEffect(() => {
|
|
65
|
+
if (!ref.current) {
|
|
66
|
+
throw new Error("Canvas ref is null");
|
|
67
|
+
}
|
|
68
|
+
ref.current.measureInWindow((_x, _y, width, height) => {
|
|
69
|
+
setSize({ width, height });
|
|
70
|
+
});
|
|
71
|
+
}, [ref]);
|
|
72
|
+
return { size, onLayout: undefined };
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const useSizePaper = (_ref: RefObject<View>) => {
|
|
76
|
+
const [size, setSize] = useState<null | Size>(null);
|
|
77
|
+
const onLayout = useCallback<(event: LayoutChangeEvent) => void>(
|
|
78
|
+
({
|
|
79
|
+
nativeEvent: {
|
|
80
|
+
layout: { width, height },
|
|
81
|
+
},
|
|
82
|
+
}) => {
|
|
83
|
+
if (size === null) {
|
|
84
|
+
setSize({ width, height });
|
|
62
85
|
}
|
|
63
|
-
const ctx = RNWebGPU.MakeWebGPUCanvasContext(nativeSurface);
|
|
64
|
-
return ctx;
|
|
65
86
|
},
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
delete WebGPUContextRegistry[contextId];
|
|
71
|
-
};
|
|
72
|
-
}, [contextId]);
|
|
87
|
+
[size],
|
|
88
|
+
);
|
|
89
|
+
return { size, onLayout };
|
|
90
|
+
};
|
|
73
91
|
|
|
74
|
-
|
|
75
|
-
})
|
|
92
|
+
export const Canvas = forwardRef<CanvasRef, ViewProps>(
|
|
93
|
+
({ onLayout: _onLayout, ...props }, ref) => {
|
|
94
|
+
const viewRef = useRef(null);
|
|
95
|
+
const FABRIC = RNWebGPU.fabric;
|
|
96
|
+
const useSize = FABRIC ? useSizeFabric : useSizePaper;
|
|
97
|
+
const [contextId, _] = useState(() => generateContextId());
|
|
98
|
+
const cb = useRef<() => void>();
|
|
99
|
+
const { size, onLayout } = useSize(viewRef);
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (size && cb.current) {
|
|
102
|
+
cb.current();
|
|
103
|
+
}
|
|
104
|
+
}, [size]);
|
|
105
|
+
useImperativeHandle(ref, () => ({
|
|
106
|
+
getNativeSurface: () => {
|
|
107
|
+
if (size === null) {
|
|
108
|
+
throw new Error("[WebGPU] Canvas size is not available yet");
|
|
109
|
+
}
|
|
110
|
+
return RNWebGPU.getNativeSurface(contextId);
|
|
111
|
+
},
|
|
112
|
+
whenReady(callback: () => void) {
|
|
113
|
+
if (size === null) {
|
|
114
|
+
cb.current = callback;
|
|
115
|
+
} else {
|
|
116
|
+
callback();
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
getContext(contextName: "webgpu"): RNCanvasContext | null {
|
|
120
|
+
if (contextName !== "webgpu") {
|
|
121
|
+
throw new Error(`[WebGPU] Unsupported context: ${contextName}`);
|
|
122
|
+
}
|
|
123
|
+
if (size === null) {
|
|
124
|
+
throw new Error("[WebGPU] Canvas size is not available yet");
|
|
125
|
+
}
|
|
126
|
+
return RNWebGPU.MakeWebGPUCanvasContext(
|
|
127
|
+
contextId,
|
|
128
|
+
size.width,
|
|
129
|
+
size.height,
|
|
130
|
+
);
|
|
131
|
+
},
|
|
132
|
+
}));
|
|
133
|
+
return (
|
|
134
|
+
<View ref={viewRef} onLayout={onLayout} {...props}>
|
|
135
|
+
<WebGPUNativeView style={{ flex: 1 }} contextId={contextId} />
|
|
136
|
+
</View>
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
);
|
package/src/Offscreen.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
export class GPUOffscreenCanvas implements OffscreenCanvas {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
oncontextlost: ((this: OffscreenCanvas, ev: Event) => any) | null = null;
|
|
6
|
+
oncontextrestored: ((this: OffscreenCanvas, ev: Event) => any) | null = null;
|
|
7
|
+
|
|
8
|
+
private context: GPUOffscreenCanvasContext;
|
|
9
|
+
|
|
10
|
+
constructor(width: number, height: number) {
|
|
11
|
+
this.width = width;
|
|
12
|
+
this.height = height;
|
|
13
|
+
this.context = new GPUOffscreenCanvasContext(this);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
convertToBlob(_options?: ImageEncodeOptions): Promise<Blob> {
|
|
17
|
+
// Implementation for converting the canvas content to a Blob
|
|
18
|
+
throw new Error("Method not implemented.");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Overloaded method signatures
|
|
22
|
+
getContext(
|
|
23
|
+
contextId: "2d",
|
|
24
|
+
options?: any,
|
|
25
|
+
): OffscreenCanvasRenderingContext2D | null;
|
|
26
|
+
getContext(
|
|
27
|
+
contextId: "bitmaprenderer",
|
|
28
|
+
options?: any,
|
|
29
|
+
): ImageBitmapRenderingContext | null;
|
|
30
|
+
getContext(contextId: "webgl", options?: any): WebGLRenderingContext | null;
|
|
31
|
+
getContext(contextId: "webgl2", options?: any): WebGL2RenderingContext | null;
|
|
32
|
+
getContext(
|
|
33
|
+
contextId: OffscreenRenderingContextId,
|
|
34
|
+
options?: any,
|
|
35
|
+
): OffscreenRenderingContext | null;
|
|
36
|
+
getContext(contextId: "webgpu"): GPUOffscreenCanvasContext | null;
|
|
37
|
+
getContext(
|
|
38
|
+
contextId: unknown,
|
|
39
|
+
_options?: any,
|
|
40
|
+
): OffscreenRenderingContext | GPUOffscreenCanvasContext | null {
|
|
41
|
+
if (contextId === "webgpu") {
|
|
42
|
+
return this.context;
|
|
43
|
+
}
|
|
44
|
+
// Implement other context types if necessary
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
transferToImageBitmap(): ImageBitmap {
|
|
49
|
+
// Implementation for transferring the canvas content to an ImageBitmap
|
|
50
|
+
throw new Error("Method not implemented.");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
addEventListener<K extends keyof OffscreenCanvasEventMap>(
|
|
54
|
+
_type: K,
|
|
55
|
+
_listener: (this: OffscreenCanvas, ev: OffscreenCanvasEventMap[K]) => any,
|
|
56
|
+
_options?: boolean | AddEventListenerOptions,
|
|
57
|
+
): void {
|
|
58
|
+
// Event listener implementation
|
|
59
|
+
throw new Error("Method not implemented.");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
removeEventListener<K extends keyof OffscreenCanvasEventMap>(
|
|
63
|
+
_type: K,
|
|
64
|
+
_listener: (this: OffscreenCanvas, ev: OffscreenCanvasEventMap[K]) => any,
|
|
65
|
+
_options?: boolean | EventListenerOptions,
|
|
66
|
+
): void {
|
|
67
|
+
// Remove event listener implementation
|
|
68
|
+
throw new Error("Method not implemented.");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
dispatchEvent(_event: Event): boolean {
|
|
72
|
+
// Event dispatch implementation
|
|
73
|
+
throw new Error("Method not implemented.");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getImageData() {
|
|
77
|
+
const device = this.context.getDevice();
|
|
78
|
+
const texture = this.context.getTexture();
|
|
79
|
+
const commandEncoder = device.createCommandEncoder();
|
|
80
|
+
const bytesPerRow = this.width * 4;
|
|
81
|
+
const buffer = device.createBuffer({
|
|
82
|
+
size: bytesPerRow * this.height,
|
|
83
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
|
|
84
|
+
});
|
|
85
|
+
commandEncoder.copyTextureToBuffer(
|
|
86
|
+
{ texture: texture },
|
|
87
|
+
{ buffer: buffer, bytesPerRow },
|
|
88
|
+
[this.width, this.height],
|
|
89
|
+
);
|
|
90
|
+
device.queue.submit([commandEncoder.finish()]);
|
|
91
|
+
|
|
92
|
+
return buffer.mapAsync(GPUMapMode.READ).then(() => {
|
|
93
|
+
const arrayBuffer = buffer.getMappedRange();
|
|
94
|
+
const uint8Array = new Uint8Array(arrayBuffer);
|
|
95
|
+
const data = Array.from(uint8Array);
|
|
96
|
+
buffer.unmap();
|
|
97
|
+
return {
|
|
98
|
+
data,
|
|
99
|
+
width: this.width,
|
|
100
|
+
height: this.height,
|
|
101
|
+
format: navigator.gpu.getPreferredCanvasFormat(),
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
class GPUOffscreenCanvasContext implements GPUCanvasContext {
|
|
108
|
+
__brand = "GPUCanvasContext" as const;
|
|
109
|
+
|
|
110
|
+
private textureFormat: GPUTextureFormat;
|
|
111
|
+
private texture: GPUTexture | null = null;
|
|
112
|
+
private device: GPUDevice | null = null;
|
|
113
|
+
|
|
114
|
+
constructor(public readonly canvas: OffscreenCanvas) {
|
|
115
|
+
this.textureFormat = navigator.gpu.getPreferredCanvasFormat();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
present() {
|
|
119
|
+
// Do nothing
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getDevice() {
|
|
123
|
+
if (!this.device) {
|
|
124
|
+
throw new Error("Device is not configured.");
|
|
125
|
+
}
|
|
126
|
+
return this.device;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
getTexture() {
|
|
130
|
+
if (!this.texture) {
|
|
131
|
+
throw new Error("Texture is not configured");
|
|
132
|
+
}
|
|
133
|
+
return this.texture;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
configure(config: GPUCanvasConfiguration) {
|
|
137
|
+
// Configure the canvas context with the device and format
|
|
138
|
+
this.device = config.device;
|
|
139
|
+
this.texture = config.device.createTexture({
|
|
140
|
+
size: [this.canvas.width, this.canvas.height],
|
|
141
|
+
format: this.textureFormat,
|
|
142
|
+
usage:
|
|
143
|
+
GPUTextureUsage.RENDER_ATTACHMENT |
|
|
144
|
+
GPUTextureUsage.COPY_SRC |
|
|
145
|
+
GPUTextureUsage.TEXTURE_BINDING,
|
|
146
|
+
});
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
unconfigure() {
|
|
151
|
+
// Unconfigure the canvas context
|
|
152
|
+
if (this.texture) {
|
|
153
|
+
this.texture.destroy();
|
|
154
|
+
}
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
getCurrentTexture(): GPUTexture {
|
|
159
|
+
if (!this.texture) {
|
|
160
|
+
throw new Error("Texture is not configured");
|
|
161
|
+
}
|
|
162
|
+
return this.texture;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -3,7 +3,7 @@ import { checkImage, client, encodeImage } from "./setup";
|
|
|
3
3
|
describe("External Textures", () => {
|
|
4
4
|
it("Simple (1)", async () => {
|
|
5
5
|
const result = await client.eval(
|
|
6
|
-
({ gpu, device, ctx, urls: { fTexture } }) => {
|
|
6
|
+
({ gpu, device, ctx, canvas, urls: { fTexture } }) => {
|
|
7
7
|
const module = device.createShaderModule({
|
|
8
8
|
label: "our hardcoded textured quad shaders",
|
|
9
9
|
code: /* wgsl */ `
|
|
@@ -131,7 +131,7 @@ describe("External Textures", () => {
|
|
|
131
131
|
device.queue.submit([commandBuffer]);
|
|
132
132
|
}
|
|
133
133
|
render();
|
|
134
|
-
return
|
|
134
|
+
return canvas.getImageData();
|
|
135
135
|
});
|
|
136
136
|
});
|
|
137
137
|
});
|
|
@@ -143,7 +143,7 @@ describe("External Textures", () => {
|
|
|
143
143
|
});
|
|
144
144
|
it("Simple (2)", async () => {
|
|
145
145
|
const result = await client.eval(
|
|
146
|
-
({ gpu, device, ctx, urls: { fTexture } }) => {
|
|
146
|
+
({ gpu, device, ctx, canvas, urls: { fTexture } }) => {
|
|
147
147
|
const module = device.createShaderModule({
|
|
148
148
|
label: "our hardcoded textured quad shaders",
|
|
149
149
|
code: /* wgsl */ `
|
|
@@ -271,7 +271,7 @@ describe("External Textures", () => {
|
|
|
271
271
|
device.queue.submit([commandBuffer]);
|
|
272
272
|
}
|
|
273
273
|
render();
|
|
274
|
-
return
|
|
274
|
+
return canvas.getImageData();
|
|
275
275
|
});
|
|
276
276
|
});
|
|
277
277
|
});
|
|
@@ -138,7 +138,13 @@ describe("Texture", () => {
|
|
|
138
138
|
});
|
|
139
139
|
it("Create texture and reads it", async () => {
|
|
140
140
|
const result = await client.eval(
|
|
141
|
-
({
|
|
141
|
+
({
|
|
142
|
+
device,
|
|
143
|
+
shaders: { triangleVertWGSL, redFragWGSL },
|
|
144
|
+
gpu,
|
|
145
|
+
ctx,
|
|
146
|
+
canvas,
|
|
147
|
+
}) => {
|
|
142
148
|
const pipeline = device.createRenderPipeline({
|
|
143
149
|
layout: "auto",
|
|
144
150
|
vertex: {
|
|
@@ -182,7 +188,7 @@ describe("Texture", () => {
|
|
|
182
188
|
passEncoder.end();
|
|
183
189
|
|
|
184
190
|
device.queue.submit([commandEncoder.finish()]);
|
|
185
|
-
return
|
|
191
|
+
return canvas.getImageData();
|
|
186
192
|
},
|
|
187
193
|
);
|
|
188
194
|
const image = encodeImage(result);
|
|
@@ -248,6 +248,7 @@ describe("A Buffer", () => {
|
|
|
248
248
|
translucentWGSL,
|
|
249
249
|
mat4,
|
|
250
250
|
vec3,
|
|
251
|
+
canvas,
|
|
251
252
|
}) => {
|
|
252
253
|
const presentationFormat = gpu.getPreferredCanvasFormat();
|
|
253
254
|
const settings = {
|
|
@@ -579,7 +580,7 @@ describe("A Buffer", () => {
|
|
|
579
580
|
}
|
|
580
581
|
|
|
581
582
|
const depthTexture = device.createTexture({
|
|
582
|
-
size: [ctx.width, ctx.height],
|
|
583
|
+
size: [ctx.canvas.width, ctx.canvas.height],
|
|
583
584
|
format: "depth24plus",
|
|
584
585
|
usage:
|
|
585
586
|
GPUTextureUsage.RENDER_ATTACHMENT |
|
|
@@ -605,12 +606,12 @@ describe("A Buffer", () => {
|
|
|
605
606
|
// We want to keep the linked-list buffer size under the maxStorageBufferBindingSize.
|
|
606
607
|
// Split the frame into enough slices to meet that constraint.
|
|
607
608
|
const bytesPerline =
|
|
608
|
-
ctx.width * averageLayersPerFragment * linkedListElementSize;
|
|
609
|
+
ctx.canvas.width * averageLayersPerFragment * linkedListElementSize;
|
|
609
610
|
const maxLinesSupported = Math.floor(
|
|
610
611
|
device.limits.maxStorageBufferBindingSize / bytesPerline,
|
|
611
612
|
);
|
|
612
|
-
const numSlices = Math.ceil(ctx.height / maxLinesSupported);
|
|
613
|
-
const sliceHeight = Math.ceil(ctx.height / numSlices);
|
|
613
|
+
const numSlices = Math.ceil(ctx.canvas.height / maxLinesSupported);
|
|
614
|
+
const sliceHeight = Math.ceil(ctx.canvas.height / numSlices);
|
|
614
615
|
const linkedListBufferSize = sliceHeight * bytesPerline;
|
|
615
616
|
|
|
616
617
|
const linkedListBuffer = device.createBuffer({
|
|
@@ -645,13 +646,17 @@ describe("A Buffer", () => {
|
|
|
645
646
|
// * numFragments : u32
|
|
646
647
|
// * data : array<u32>
|
|
647
648
|
const headsBuffer = device.createBuffer({
|
|
648
|
-
size:
|
|
649
|
+
size:
|
|
650
|
+
(1 + ctx.canvas.width * sliceHeight) *
|
|
651
|
+
Uint32Array.BYTES_PER_ELEMENT,
|
|
649
652
|
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
|
|
650
653
|
label: "headsBuffer",
|
|
651
654
|
});
|
|
652
655
|
|
|
653
656
|
const headsInitBuffer = device.createBuffer({
|
|
654
|
-
size:
|
|
657
|
+
size:
|
|
658
|
+
(1 + ctx.canvas.width * sliceHeight) *
|
|
659
|
+
Uint32Array.BYTES_PER_ELEMENT,
|
|
655
660
|
usage: GPUBufferUsage.COPY_SRC,
|
|
656
661
|
mappedAtCreation: true,
|
|
657
662
|
label: "headsInitBuffer",
|
|
@@ -745,7 +750,7 @@ describe("A Buffer", () => {
|
|
|
745
750
|
|
|
746
751
|
// Rotates the camera around the origin based on time.
|
|
747
752
|
function getCameraViewProjMatrix() {
|
|
748
|
-
const aspect = ctx.width / ctx.height;
|
|
753
|
+
const aspect = ctx.canvas.width / ctx.canvas.height;
|
|
749
754
|
|
|
750
755
|
const projectionMatrix = mat4.perspective(
|
|
751
756
|
(2 * Math.PI) / 5,
|
|
@@ -776,8 +781,8 @@ describe("A Buffer", () => {
|
|
|
776
781
|
|
|
777
782
|
new Float32Array(buffer).set(getCameraViewProjMatrix());
|
|
778
783
|
new Uint32Array(buffer, 16 * Float32Array.BYTES_PER_ELEMENT).set([
|
|
779
|
-
averageLayersPerFragment * ctx.width * sliceHeight,
|
|
780
|
-
ctx.width,
|
|
784
|
+
averageLayersPerFragment * ctx.canvas.width * sliceHeight,
|
|
785
|
+
ctx.canvas.width,
|
|
781
786
|
]);
|
|
782
787
|
|
|
783
788
|
device.queue.writeBuffer(uniformBuffer, 0, buffer);
|
|
@@ -810,9 +815,9 @@ describe("A Buffer", () => {
|
|
|
810
815
|
|
|
811
816
|
const scissorX = 0;
|
|
812
817
|
const scissorY = slice * sliceHeight;
|
|
813
|
-
const scissorWidth = ctx.width;
|
|
818
|
+
const scissorWidth = ctx.canvas.width;
|
|
814
819
|
const scissorHeight =
|
|
815
|
-
Math.min((slice + 1) * sliceHeight, ctx.height) -
|
|
820
|
+
Math.min((slice + 1) * sliceHeight, ctx.canvas.height) -
|
|
816
821
|
slice * sliceHeight;
|
|
817
822
|
|
|
818
823
|
// Draw the translucent objects
|
|
@@ -870,7 +875,7 @@ describe("A Buffer", () => {
|
|
|
870
875
|
|
|
871
876
|
doDraw();
|
|
872
877
|
|
|
873
|
-
return
|
|
878
|
+
return canvas.getImageData();
|
|
874
879
|
},
|
|
875
880
|
{
|
|
876
881
|
mesh: teapotMesh,
|
|
@@ -133,6 +133,7 @@ describe("Blur", () => {
|
|
|
133
133
|
assets: { di3D: imageBitmap },
|
|
134
134
|
fullscreenTexturedQuadWGSL,
|
|
135
135
|
blurWGSL,
|
|
136
|
+
canvas,
|
|
136
137
|
}) => {
|
|
137
138
|
const tileDim = 128;
|
|
138
139
|
const batch = [4, 4];
|
|
@@ -387,7 +388,7 @@ describe("Blur", () => {
|
|
|
387
388
|
device.queue.submit([commandEncoder.finish()]);
|
|
388
389
|
}
|
|
389
390
|
frame();
|
|
390
|
-
return
|
|
391
|
+
return canvas.getImageData();
|
|
391
392
|
},
|
|
392
393
|
{ blurWGSL: blur, fullscreenTexturedQuadWGSL: fullscreenTexturedQuad },
|
|
393
394
|
);
|