react-native-wgpu 0.1.6 → 0.1.8

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 (63) hide show
  1. package/cpp/rnwgpu/api/GPUDevice.cpp +5 -3
  2. package/lib/commonjs/Canvas.js.map +1 -1
  3. package/lib/commonjs/Offscreen.js +121 -0
  4. package/lib/commonjs/Offscreen.js.map +1 -0
  5. package/lib/commonjs/index.js +12 -0
  6. package/lib/commonjs/index.js.map +1 -1
  7. package/lib/module/Canvas.js.map +1 -1
  8. package/lib/module/Offscreen.js +114 -0
  9. package/lib/module/Offscreen.js.map +1 -0
  10. package/lib/module/index.js +1 -0
  11. package/lib/module/index.js.map +1 -1
  12. package/lib/typescript/lib/commonjs/Offscreen.d.ts +31 -0
  13. package/lib/typescript/lib/commonjs/Offscreen.d.ts.map +1 -0
  14. package/lib/typescript/lib/module/Offscreen.d.ts +30 -0
  15. package/lib/typescript/lib/module/Offscreen.d.ts.map +1 -0
  16. package/lib/typescript/lib/module/index.d.ts +1 -0
  17. package/lib/typescript/src/Canvas.d.ts +3 -3
  18. package/lib/typescript/src/Canvas.d.ts.map +1 -1
  19. package/lib/typescript/src/Offscreen.d.ts +26 -0
  20. package/lib/typescript/src/Offscreen.d.ts.map +1 -0
  21. package/lib/typescript/src/__tests__/setup.d.ts +5 -4
  22. package/lib/typescript/src/__tests__/setup.d.ts.map +1 -1
  23. package/lib/typescript/src/index.d.ts +1 -0
  24. package/lib/typescript/src/index.d.ts.map +1 -1
  25. package/libs/android/arm64-v8a/libwebgpu_dawn.so +0 -0
  26. package/libs/android/armeabi-v7a/libwebgpu_dawn.so +0 -0
  27. package/libs/android/x86/libwebgpu_dawn.so +0 -0
  28. package/libs/android/x86_64/libwebgpu_dawn.so +0 -0
  29. package/libs/apple/arm64_iphoneos/libwebgpu_dawn.a +0 -0
  30. package/libs/apple/arm64_iphonesimulator/libwebgpu_dawn.a +0 -0
  31. package/libs/apple/arm64_xros/libwebgpu_dawn.a +0 -0
  32. package/libs/apple/arm64_xrsimulator/libwebgpu_dawn.a +0 -0
  33. package/libs/apple/{libwebgpu_dawn.a → iphonesimulator/libwebgpu_dawn.a} +0 -0
  34. package/libs/apple/libwebgpu_dawn.xcframework/Info.plist +45 -0
  35. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/libwebgpu_dawn.a +0 -0
  36. package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/libwebgpu_dawn.a +0 -0
  37. package/libs/apple/{libwebgpu_dawn_macosx.xcframework → libwebgpu_dawn.xcframework}/macos-arm64_x86_64/libwebgpu_dawn.a +0 -0
  38. package/libs/apple/{libwebgpu_dawn_visionos.xcframework → libwebgpu_dawn.xcframework}/xros-arm64/libwebgpu_dawn.a +0 -0
  39. package/libs/apple/{x86_64_xrsimulator → libwebgpu_dawn.xcframework/xros-arm64-simulator}/libwebgpu_dawn.a +0 -0
  40. package/libs/apple/universal_macosx/libwebgpu_dawn.a +0 -0
  41. package/libs/apple/x86_64_iphonesimulator/libwebgpu_dawn.a +0 -0
  42. package/package.json +3 -2
  43. package/react-native-wgpu.podspec +51 -0
  44. package/src/Canvas.tsx +4 -4
  45. package/src/Offscreen.ts +160 -0
  46. package/src/__tests__/ExternalTexture.spec.ts +4 -4
  47. package/src/__tests__/Texture.spec.ts +8 -2
  48. package/src/__tests__/demos/ABuffer.spec.ts +17 -12
  49. package/src/__tests__/demos/Blur.spec.ts +2 -1
  50. package/src/__tests__/demos/Cube.spec.ts +16 -12
  51. package/src/__tests__/demos/FractalCube.spec.ts +6 -5
  52. package/src/__tests__/demos/OcclusionQuery.spec.ts +3 -3
  53. package/src/__tests__/demos/RenderBundles.spec.ts +4 -3
  54. package/src/__tests__/demos/Triangle.spec.ts +27 -9
  55. package/src/__tests__/setup.ts +25 -10
  56. package/src/index.tsx +1 -0
  57. package/lib/typescript/src/__tests__/components/DrawingContext.d.ts +0 -12
  58. package/lib/typescript/src/__tests__/components/DrawingContext.d.ts.map +0 -1
  59. package/libs/apple/libwebgpu_dawn_macosx.xcframework/Info.plist +0 -28
  60. package/libs/apple/libwebgpu_dawn_visionos.a +0 -0
  61. package/libs/apple/libwebgpu_dawn_visionos.xcframework/Info.plist +0 -44
  62. package/libs/apple/libwebgpu_dawn_visionos.xcframework/xros-arm64_x86_64-simulator/libwebgpu_dawn_visionos.a +0 -0
  63. package/src/__tests__/components/DrawingContext.ts +0 -11
@@ -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>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-wgpu",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "React Native WebGPU",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -16,7 +16,8 @@
16
16
  "android/src/**",
17
17
  "cpp/**/*.{h,cpp}",
18
18
  "ios/**",
19
- "libs/**"
19
+ "libs/**",
20
+ "*.podspec"
20
21
  ],
21
22
  "scripts": {
22
23
  "test": "jest -i",
@@ -0,0 +1,51 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
5
+
6
+ Pod::Spec.new do |s|
7
+ s.name = "react-native-wgpu"
8
+ s.version = package["version"]
9
+ s.summary = package["description"]
10
+ s.homepage = package["homepage"]
11
+ s.license = package["license"]
12
+ s.authors = package["author"]
13
+
14
+ s.platforms = { :ios => min_ios_version_supported, :visionos => "1.0" }
15
+ s.source = { :git => "https://github.com/wcandillon/react-native-webgpu.git", :tag => "#{s.version}" }
16
+
17
+ s.source_files = [
18
+ "ios/**/*.{h,c,cc,cpp,m,mm,swift}",
19
+ "cpp/**/*.{h,cpp}"
20
+ ]
21
+
22
+ s.vendored_frameworks = 'libs/apple/libwebgpu_dawn.xcframework'
23
+
24
+ s.pod_target_xcconfig = {
25
+ 'HEADER_SEARCH_PATHS' => '$(PODS_TARGET_SRCROOT)/cpp',
26
+ }
27
+
28
+ # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
29
+ # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
30
+ if respond_to?(:install_modules_dependencies, true)
31
+ install_modules_dependencies(s)
32
+ else
33
+ s.dependency "React-Core"
34
+
35
+ # Don't install the dependencies when we run `pod install` in the old architecture.
36
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
37
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
38
+ s.pod_target_xcconfig = {
39
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
40
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
41
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
42
+ }
43
+ s.dependency "React-RCTFabric"
44
+ s.dependency "React-Codegen"
45
+ s.dependency "RCT-Folly"
46
+ s.dependency "RCTRequired"
47
+ s.dependency "RCTTypeSafety"
48
+ s.dependency "ReactCommon/turbomodule/core"
49
+ end
50
+ end
51
+ end
package/src/Canvas.tsx CHANGED
@@ -15,7 +15,7 @@ declare global {
15
15
  // eslint-disable-next-line no-var
16
16
  var RNWebGPU: {
17
17
  gpu: GPU;
18
- MakeWebGPUCanvasContext: (nativeCanvas: NativeCanvas) => CanvasContext;
18
+ MakeWebGPUCanvasContext: (nativeCanvas: NativeCanvas) => RNCanvasContext;
19
19
  DecodeToUTF8: (buffer: NodeJS.ArrayBufferView | ArrayBuffer) => string;
20
20
  createImageBitmap: typeof createImageBitmap;
21
21
  };
@@ -34,12 +34,12 @@ export interface NativeCanvas {
34
34
  global.__WebGPUContextRegistry = {};
35
35
  const WebGPUContextRegistry = global.__WebGPUContextRegistry;
36
36
 
37
- type CanvasContext = GPUCanvasContext & {
37
+ export type RNCanvasContext = GPUCanvasContext & {
38
38
  present: () => void;
39
39
  };
40
40
 
41
41
  export interface CanvasRef {
42
- getContext(contextName: "webgpu"): CanvasContext | null;
42
+ getContext(contextName: "webgpu"): RNCanvasContext | null;
43
43
  getNativeSurface: () => NativeCanvas;
44
44
  }
45
45
 
@@ -51,7 +51,7 @@ export const Canvas = forwardRef<CanvasRef, ViewProps>((props, ref) => {
51
51
  WebGPUNativeModule.createSurfaceContext(contextId);
52
52
  return WebGPUContextRegistry[contextId];
53
53
  },
54
- getContext(contextName: "webgpu"): CanvasContext | null {
54
+ getContext(contextName: "webgpu"): RNCanvasContext | null {
55
55
  if (contextName !== "webgpu") {
56
56
  throw new Error(`[WebGPU] Unsupported context: ${contextName}`);
57
57
  }
@@ -0,0 +1,160 @@
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"): GPUCanvasContext | null;
37
+ getContext(
38
+ contextId: unknown,
39
+ _options?: any,
40
+ ): OffscreenRenderingContext | GPUCanvasContext | 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
+ getDevice() {
119
+ if (!this.device) {
120
+ throw new Error("Device is not configured.");
121
+ }
122
+ return this.device;
123
+ }
124
+
125
+ getTexture() {
126
+ if (!this.texture) {
127
+ throw new Error("Texture is not configured");
128
+ }
129
+ return this.texture;
130
+ }
131
+
132
+ configure(config: GPUCanvasConfiguration) {
133
+ // Configure the canvas context with the device and format
134
+ this.device = config.device;
135
+ this.texture = config.device.createTexture({
136
+ size: [this.canvas.width, this.canvas.height],
137
+ format: this.textureFormat,
138
+ usage:
139
+ GPUTextureUsage.RENDER_ATTACHMENT |
140
+ GPUTextureUsage.COPY_SRC |
141
+ GPUTextureUsage.TEXTURE_BINDING,
142
+ });
143
+ return undefined;
144
+ }
145
+
146
+ unconfigure() {
147
+ // Unconfigure the canvas context
148
+ if (this.texture) {
149
+ this.texture.destroy();
150
+ }
151
+ return undefined;
152
+ }
153
+
154
+ getCurrentTexture(): GPUTexture {
155
+ if (!this.texture) {
156
+ throw new Error("Texture is not configured");
157
+ }
158
+ return this.texture;
159
+ }
160
+ }
@@ -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 ctx.getImageData();
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 ctx.getImageData();
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
- ({ device, shaders: { triangleVertWGSL, redFragWGSL }, gpu, ctx }) => {
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 ctx.getImageData();
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: (1 + ctx.width * sliceHeight) * Uint32Array.BYTES_PER_ELEMENT,
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: (1 + ctx.width * sliceHeight) * Uint32Array.BYTES_PER_ELEMENT,
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 ctx.getImageData();
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 ctx.getImageData();
391
+ return canvas.getImageData();
391
392
  },
392
393
  { blurWGSL: blur, fullscreenTexturedQuadWGSL: fullscreenTexturedQuad },
393
394
  );
@@ -84,6 +84,7 @@ describe("Cube", () => {
84
84
  vec3,
85
85
  basicVertWGSL,
86
86
  vertexPositionColorWGSL,
87
+ canvas,
87
88
  }) => {
88
89
  const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.
89
90
  const cubePositionOffset = 0;
@@ -156,7 +157,7 @@ describe("Cube", () => {
156
157
  });
157
158
 
158
159
  const depthTexture = device.createTexture({
159
- size: [ctx.width, ctx.height],
160
+ size: [ctx.canvas.width, ctx.canvas.height],
160
161
  format: "depth24plus",
161
162
  usage: GPUTextureUsage.RENDER_ATTACHMENT,
162
163
  });
@@ -196,7 +197,7 @@ describe("Cube", () => {
196
197
  },
197
198
  };
198
199
 
199
- const aspect = ctx.width / ctx.height;
200
+ const aspect = ctx.canvas.width / ctx.canvas.height;
200
201
  const projectionMatrix = mat4.perspective(
201
202
  (2 * Math.PI) / 5,
202
203
  aspect,
@@ -243,7 +244,7 @@ describe("Cube", () => {
243
244
  passEncoder.draw(cubeVertexCount);
244
245
  passEncoder.end();
245
246
  device.queue.submit([commandEncoder.finish()]);
246
- return ctx.getImageData();
247
+ return canvas.getImageData();
247
248
  },
248
249
  {
249
250
  basicVertWGSL: basicVert,
@@ -264,6 +265,7 @@ describe("Cube", () => {
264
265
  vec3,
265
266
  basicVertWGSL,
266
267
  vertexPositionColorWGSL,
268
+ canvas,
267
269
  }) => {
268
270
  const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.
269
271
  const cubePositionOffset = 0;
@@ -334,7 +336,7 @@ describe("Cube", () => {
334
336
  });
335
337
 
336
338
  const depthTexture = device.createTexture({
337
- size: [ctx.width, ctx.height],
339
+ size: [ctx.canvas.width, ctx.canvas.height],
338
340
  format: "depth24plus",
339
341
  usage: GPUTextureUsage.RENDER_ATTACHMENT,
340
342
  });
@@ -395,7 +397,7 @@ describe("Cube", () => {
395
397
  },
396
398
  };
397
399
 
398
- const aspect = ctx.width / ctx.height;
400
+ const aspect = ctx.canvas.width / ctx.canvas.height;
399
401
  const projectionMatrix = mat4.perspective(
400
402
  (2 * Math.PI) / 5,
401
403
  aspect,
@@ -475,7 +477,7 @@ describe("Cube", () => {
475
477
  passEncoder.end();
476
478
  device.queue.submit([commandEncoder.finish()]);
477
479
 
478
- return ctx.getImageData();
480
+ return canvas.getImageData();
479
481
  },
480
482
  {
481
483
  basicVertWGSL: basicVert,
@@ -496,6 +498,7 @@ describe("Cube", () => {
496
498
  vec3,
497
499
  basicVertWGSL,
498
500
  sampleTextureMixColorWGSL,
501
+ canvas,
499
502
  }) => {
500
503
  const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.
501
504
  const cubePositionOffset = 0;
@@ -567,7 +570,7 @@ describe("Cube", () => {
567
570
  });
568
571
 
569
572
  const depthTexture = device.createTexture({
570
- size: [ctx.width, ctx.height],
573
+ size: [ctx.canvas.width, ctx.canvas.height],
571
574
  format: "depth24plus",
572
575
  usage: GPUTextureUsage.RENDER_ATTACHMENT,
573
576
  });
@@ -638,7 +641,7 @@ describe("Cube", () => {
638
641
  },
639
642
  };
640
643
 
641
- const aspect = ctx.width / ctx.height;
644
+ const aspect = ctx.canvas.width / ctx.canvas.height;
642
645
  const projectionMatrix = mat4.perspective(
643
646
  (2 * Math.PI) / 5,
644
647
  aspect,
@@ -686,7 +689,7 @@ describe("Cube", () => {
686
689
  passEncoder.end();
687
690
  device.queue.submit([commandEncoder.finish()]);
688
691
 
689
- return ctx.getImageData();
692
+ return canvas.getImageData();
690
693
  },
691
694
  {
692
695
  basicVertWGSL: basicVert,
@@ -708,6 +711,7 @@ describe("Cube", () => {
708
711
  vec3,
709
712
  vertexPositionColorWGSL,
710
713
  instancedVertWGSL,
714
+ canvas,
711
715
  }) => {
712
716
  const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.
713
717
  const cubePositionOffset = 0;
@@ -778,7 +782,7 @@ describe("Cube", () => {
778
782
  });
779
783
 
780
784
  const depthTexture = device.createTexture({
781
- size: [ctx.width, ctx.height],
785
+ size: [ctx.canvas.width, ctx.canvas.height],
782
786
  format: "depth24plus",
783
787
  usage: GPUTextureUsage.RENDER_ATTACHMENT,
784
788
  });
@@ -809,7 +813,7 @@ describe("Cube", () => {
809
813
  ],
810
814
  });
811
815
 
812
- const aspect = ctx.width / ctx.height;
816
+ const aspect = ctx.canvas.width / ctx.canvas.height;
813
817
  const projectionMatrix = mat4.perspective(
814
818
  (2 * Math.PI) / 5,
815
819
  aspect,
@@ -912,7 +916,7 @@ describe("Cube", () => {
912
916
  passEncoder.draw(cubeVertexCount, numInstances, 0, 0);
913
917
  passEncoder.end();
914
918
  device.queue.submit([commandEncoder.finish()]);
915
- return ctx.getImageData();
919
+ return canvas.getImageData();
916
920
  },
917
921
  {
918
922
  vertexPositionColorWGSL: vertexPositionColor,