diff --git a/sample/a-buffer/main.ts b/sample/a-buffer/main.ts index f4713ffa..b9d24337 100644 --- a/sample/a-buffer/main.ts +++ b/sample/a-buffer/main.ts @@ -1,6 +1,7 @@ import { mat4, vec3 } from 'wgpu-matrix'; import { GUI } from 'dat.gui'; +import { quitIfWebGPUNotAvailable } from '../util'; import { mesh } from '../../meshes/teapot'; import opaqueWGSL from './opaque.wgsl'; @@ -12,8 +13,9 @@ function roundUp(n: number, k: number): number { } const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); diff --git a/sample/animometer/main.ts b/sample/animometer/main.ts index 72e814e5..7ea1f6b8 100644 --- a/sample/animometer/main.ts +++ b/sample/animometer/main.ts @@ -1,9 +1,11 @@ import { GUI } from 'dat.gui'; import animometerWGSL from './animometer.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const perfDisplayContainer = document.createElement('div'); perfDisplayContainer.style.color = 'white'; diff --git a/sample/bitonicSort/utils.ts b/sample/bitonicSort/utils.ts index 371401d9..6a749183 100644 --- a/sample/bitonicSort/utils.ts +++ b/sample/bitonicSort/utils.ts @@ -1,5 +1,6 @@ import type { GUI } from 'dat.gui'; import fullscreenTexturedQuad from '../../shaders/fullscreenTexturedQuad.wgsl'; +import { quitIfAdapterNotAvailable, quitIfWebGPUNotAvailable } from '../util'; type BindGroupBindingLayout = | GPUBufferBindingLayout @@ -111,7 +112,9 @@ export const SampleInitFactoryWebGPU = async ( callback: SampleInitCallback3D ): Promise => { const init = async ({ canvas, gui, stats }) => { - const adapter = await navigator.gpu.requestAdapter(); + const adapter = await navigator.gpu?.requestAdapter(); + quitIfAdapterNotAvailable(adapter); + const timestampQueryAvailable = adapter.features.has('timestamp-query'); let device: GPUDevice; if (timestampQueryAvailable) { @@ -121,6 +124,8 @@ export const SampleInitFactoryWebGPU = async ( } else { device = await adapter.requestDevice(); } + quitIfWebGPUNotAvailable(adapter, device); + const context = canvas.getContext('webgpu') as GPUCanvasContext; const devicePixelRatio = window.devicePixelRatio; canvas.width = canvas.clientWidth * devicePixelRatio; diff --git a/sample/cameras/main.ts b/sample/cameras/main.ts index 648cb61a..42154f17 100644 --- a/sample/cameras/main.ts +++ b/sample/cameras/main.ts @@ -10,6 +10,7 @@ import { import cubeWGSL from './cube.wgsl'; import { ArcballCamera, WASDCamera } from './camera'; import { createInputHandler } from './input'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; @@ -39,8 +40,9 @@ gui.add(params, 'type', ['arcball', 'WASD']).onChange(() => { oldCameraType = newCameraType; }); -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; const devicePixelRatio = window.devicePixelRatio; diff --git a/sample/computeBoids/main.ts b/sample/computeBoids/main.ts index 8a2ea996..dade757e 100644 --- a/sample/computeBoids/main.ts +++ b/sample/computeBoids/main.ts @@ -1,14 +1,17 @@ +import { quitIfAdapterNotAvailable, quitIfWebGPUNotAvailable } from '../util'; import spriteWGSL from './sprite.wgsl'; import updateSpritesWGSL from './updateSprites.wgsl'; import { GUI } from 'dat.gui'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); +const adapter = await navigator.gpu?.requestAdapter(); +quitIfAdapterNotAvailable(adapter); const hasTimestampQuery = adapter.features.has('timestamp-query'); const device = await adapter.requestDevice({ requiredFeatures: hasTimestampQuery ? ['timestamp-query'] : [], }); +quitIfWebGPUNotAvailable(adapter, device); const perfDisplayContainer = document.createElement('div'); perfDisplayContainer.style.color = 'white'; diff --git a/sample/cornell/main.ts b/sample/cornell/main.ts index 38a1bcba..66b5e7c3 100644 --- a/sample/cornell/main.ts +++ b/sample/cornell/main.ts @@ -5,13 +5,16 @@ import Radiosity from './radiosity'; import Rasterizer from './rasterizer'; import Tonemapper from './tonemapper'; import Raytracer from './raytracer'; +import { quitIfAdapterNotAvailable, quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); const requiredFeatures: GPUFeatureName[] = presentationFormat === 'bgra8unorm' ? ['bgra8unorm-storage'] : []; -const adapter = await navigator.gpu.requestAdapter(); +const adapter = await navigator.gpu?.requestAdapter(); +quitIfAdapterNotAvailable(adapter); + for (const feature of requiredFeatures) { if (!adapter.features.has(feature)) { throw new Error( @@ -19,7 +22,8 @@ for (const feature of requiredFeatures) { ); } } -const device = await adapter.requestDevice({ requiredFeatures }); +const device = await adapter?.requestDevice({ requiredFeatures }); +quitIfWebGPUNotAvailable(adapter, device); const params: { renderer: 'rasterizer' | 'raytracer'; diff --git a/sample/cubemap/main.ts b/sample/cubemap/main.ts index 7a423ff2..9613ccbc 100644 --- a/sample/cubemap/main.ts +++ b/sample/cubemap/main.ts @@ -10,10 +10,12 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import sampleCubemapWGSL from './sampleCubemap.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/deferredRendering/main.ts b/sample/deferredRendering/main.ts index e5d95621..29314194 100644 --- a/sample/deferredRendering/main.ts +++ b/sample/deferredRendering/main.ts @@ -8,14 +8,16 @@ import fragmentWriteGBuffers from './fragmentWriteGBuffers.wgsl'; import vertexTextureQuad from './vertexTextureQuad.wgsl'; import fragmentGBuffersDebugView from './fragmentGBuffersDebugView.wgsl'; import fragmentDeferredRendering from './fragmentDeferredRendering.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const kMaxNumLights = 1024; const lightExtentMin = vec3.fromValues(-50, -30, -50); const lightExtentMax = vec3.fromValues(50, 50, 50); const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/fractalCube/main.ts b/sample/fractalCube/main.ts index 35c4fa66..196fe424 100644 --- a/sample/fractalCube/main.ts +++ b/sample/fractalCube/main.ts @@ -10,10 +10,12 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import sampleSelfWGSL from './sampleSelf.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/gameOfLife/main.ts b/sample/gameOfLife/main.ts index 3d5589ad..24133039 100644 --- a/sample/gameOfLife/main.ts +++ b/sample/gameOfLife/main.ts @@ -2,10 +2,12 @@ import { GUI } from 'dat.gui'; import computeWGSL from './compute.wgsl'; import vertWGSL from './vert.wgsl'; import fragWGSL from './frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; const devicePixelRatio = window.devicePixelRatio; diff --git a/sample/helloTriangle/main.ts b/sample/helloTriangle/main.ts index ab7248f3..ac7f6792 100644 --- a/sample/helloTriangle/main.ts +++ b/sample/helloTriangle/main.ts @@ -1,9 +1,11 @@ import triangleVertWGSL from '../../shaders/triangle.vert.wgsl'; import redFragWGSL from '../../shaders/red.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/helloTriangleMSAA/main.ts b/sample/helloTriangleMSAA/main.ts index ad34cea5..4f5636d2 100644 --- a/sample/helloTriangleMSAA/main.ts +++ b/sample/helloTriangleMSAA/main.ts @@ -1,9 +1,11 @@ import triangleVertWGSL from '../../shaders/triangle.vert.wgsl'; import redFragWGSL from '../../shaders/red.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/imageBlur/main.ts b/sample/imageBlur/main.ts index b1bab78f..d661dfc6 100644 --- a/sample/imageBlur/main.ts +++ b/sample/imageBlur/main.ts @@ -1,14 +1,16 @@ import { GUI } from 'dat.gui'; import blurWGSL from './blur.wgsl'; import fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; // Contants from the blur.wgsl shader. const tileDim = 128; const batch = [4, 4]; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/instancedCube/main.ts b/sample/instancedCube/main.ts index 87265398..40fc2116 100644 --- a/sample/instancedCube/main.ts +++ b/sample/instancedCube/main.ts @@ -10,10 +10,12 @@ import { import instancedVertWGSL from './instanced.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/multipleCanvases/main.ts b/sample/multipleCanvases/main.ts index a514b6ee..8b3501be 100644 --- a/sample/multipleCanvases/main.ts +++ b/sample/multipleCanvases/main.ts @@ -1,5 +1,6 @@ import { mat4, mat3 } from 'wgpu-matrix'; import { modelData } from './models'; +import { quitIfWebGPUNotAvailable } from '../util'; type TypedArrayView = Float32Array | Uint32Array; @@ -45,8 +46,9 @@ function createVertexAndIndexBuffer( }; } -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const models = Object.values(modelData).map((data) => createVertexAndIndexBuffer(device, data) diff --git a/sample/normalMap/main.ts b/sample/normalMap/main.ts index fe4f8189..101396db 100644 --- a/sample/normalMap/main.ts +++ b/sample/normalMap/main.ts @@ -8,6 +8,7 @@ import { create3DRenderPipeline, createTextureFromImage, } from './utils'; +import { quitIfWebGPUNotAvailable } from '../util'; const MAT4X4_BYTES = 64; enum TextureAtlas { @@ -17,8 +18,9 @@ enum TextureAtlas { } const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; const devicePixelRatio = window.devicePixelRatio; canvas.width = canvas.clientWidth * devicePixelRatio; diff --git a/sample/occlusionQuery/main.ts b/sample/occlusionQuery/main.ts index e5dbc73a..309d1b46 100644 --- a/sample/occlusionQuery/main.ts +++ b/sample/occlusionQuery/main.ts @@ -1,6 +1,7 @@ import { GUI } from 'dat.gui'; import { mat4 } from 'wgpu-matrix'; import solidColorLitWGSL from './solidColorLit.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const settings = { animate: true, @@ -30,8 +31,10 @@ export type TypedArrayConstructor = const info = document.querySelector('#info'); -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); + const canvas = document.querySelector('canvas') as HTMLCanvasElement; const context = canvas.getContext('webgpu') as GPUCanvasContext; const devicePixelRatio = window.devicePixelRatio; diff --git a/sample/particles/main.ts b/sample/particles/main.ts index e718fd91..404a2963 100644 --- a/sample/particles/main.ts +++ b/sample/particles/main.ts @@ -3,6 +3,7 @@ import { GUI } from 'dat.gui'; import particleWGSL from './particle.wgsl'; import probabilityMapWGSL from './probabilityMap.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const numParticles = 50000; const particlePositionOffset = 0; @@ -16,8 +17,9 @@ const particleInstanceByteSize = 0; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/points/main.ts b/sample/points/main.ts index 6926af7d..3d0b4349 100644 --- a/sample/points/main.ts +++ b/sample/points/main.ts @@ -5,6 +5,7 @@ import distanceSizedPointsVertWGSL from './distance-sized-points.vert.wgsl'; import fixedSizePointsVertWGSL from './fixed-size-points.vert.wgsl'; import orangeFragWGSL from './orange.frag.wgsl'; import texturedFragWGSL from './textured.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; // See: https://www.google.com/search?q=fibonacci+sphere function createFibonacciSphereVertices({ @@ -30,6 +31,7 @@ function createFibonacciSphereVertices({ const adapter = await navigator.gpu?.requestAdapter(); const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); // Get a WebGPU context from the canvas and configure it const canvas = document.querySelector('canvas') as HTMLCanvasElement; diff --git a/sample/renderBundles/main.ts b/sample/renderBundles/main.ts index 2d50bcfb..2b0a8137 100644 --- a/sample/renderBundles/main.ts +++ b/sample/renderBundles/main.ts @@ -4,6 +4,7 @@ import { createSphereMesh, SphereLayout } from '../../meshes/sphere'; import Stats from 'stats.js'; import meshWGSL from './mesh.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; interface Renderable { vertices: GPUBuffer; @@ -13,8 +14,9 @@ interface Renderable { } const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const settings = { useRenderBundles: true, diff --git a/sample/resizeCanvas/main.ts b/sample/resizeCanvas/main.ts index bf73f901..eba9e9a7 100644 --- a/sample/resizeCanvas/main.ts +++ b/sample/resizeCanvas/main.ts @@ -1,9 +1,11 @@ import triangleVertWGSL from '../../shaders/triangle.vert.wgsl'; import redFragWGSL from '../../shaders/red.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/resizeObserverHDDPI/main.ts b/sample/resizeObserverHDDPI/main.ts index fac614d0..e8e989e8 100644 --- a/sample/resizeObserverHDDPI/main.ts +++ b/sample/resizeObserverHDDPI/main.ts @@ -1,9 +1,11 @@ import { GUI } from 'dat.gui'; import checkerWGSL from './checker.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/reversedZ/main.ts b/sample/reversedZ/main.ts index bda1c2d7..b887fabc 100644 --- a/sample/reversedZ/main.ts +++ b/sample/reversedZ/main.ts @@ -8,6 +8,7 @@ import vertexTextureQuadWGSL from './vertexTextureQuad.wgsl'; import fragmentTextureQuadWGSL from './fragmentTextureQuad.wgsl'; import vertexPrecisionErrorPassWGSL from './vertexPrecisionErrorPass.wgsl'; import fragmentPrecisionErrorPassWGSL from './fragmentPrecisionErrorPass.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; // Two planes close to each other for depth precision test const geometryVertexSize = 4 * 8; // Byte size of one geometry vertex. @@ -65,8 +66,9 @@ const depthClearValues = { }; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/rotatingCube/main.ts b/sample/rotatingCube/main.ts index 5dd83191..a29deaca 100644 --- a/sample/rotatingCube/main.ts +++ b/sample/rotatingCube/main.ts @@ -10,10 +10,12 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/samplerParameters/main.ts b/sample/samplerParameters/main.ts index 4917ecad..26e1507f 100644 --- a/sample/samplerParameters/main.ts +++ b/sample/samplerParameters/main.ts @@ -3,6 +3,7 @@ import { GUI } from 'dat.gui'; import texturedSquareWGSL from './texturedSquare.wgsl'; import showTextureWGSL from './showTexture.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const kMatrices: Readonly = new Float32Array([ // Row 1: Scale by 2 @@ -27,8 +28,9 @@ const kMatrices: Readonly = new Float32Array([ ]); const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); // // GUI controls diff --git a/sample/shadowMapping/main.ts b/sample/shadowMapping/main.ts index fd94c6d2..2cfa0776 100644 --- a/sample/shadowMapping/main.ts +++ b/sample/shadowMapping/main.ts @@ -4,12 +4,14 @@ import { mesh } from '../../meshes/stanfordDragon'; import vertexShadowWGSL from './vertexShadow.wgsl'; import vertexWGSL from './vertex.wgsl'; import fragmentWGSL from './fragment.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const shadowDepthTextureSize = 1024; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/skinnedMesh/main.ts b/sample/skinnedMesh/main.ts index 8203889e..290d1b0c 100644 --- a/sample/skinnedMesh/main.ts +++ b/sample/skinnedMesh/main.ts @@ -9,6 +9,7 @@ import { createSkinnedGridRenderPipeline, } from './gridUtils'; import { gridIndices } from './gridData'; +import { quitIfWebGPUNotAvailable } from '../util'; const MAT4X4_BYTES = 64; @@ -94,8 +95,9 @@ const getRotation = (mat: Mat4): Quat => { //Normal setup const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/textRenderingMsdf/main.ts b/sample/textRenderingMsdf/main.ts index 0e13daab..cf684861 100644 --- a/sample/textRenderingMsdf/main.ts +++ b/sample/textRenderingMsdf/main.ts @@ -11,10 +11,12 @@ import { MsdfTextRenderer } from './msdfText'; import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/texturedCube/main.ts b/sample/texturedCube/main.ts index 73442116..1c8c9f86 100644 --- a/sample/texturedCube/main.ts +++ b/sample/texturedCube/main.ts @@ -10,10 +10,12 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import sampleTextureMixColorWGSL from './sampleTextureMixColor.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/twoCubes/main.ts b/sample/twoCubes/main.ts index 4a9f4374..9968ba67 100644 --- a/sample/twoCubes/main.ts +++ b/sample/twoCubes/main.ts @@ -10,10 +10,12 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/util.ts b/sample/util.ts new file mode 100644 index 00000000..b16a4aac --- /dev/null +++ b/sample/util.ts @@ -0,0 +1,82 @@ +/** Shows an error dialog if getting an adapter wasn't successful. */ +export function quitIfAdapterNotAvailable( + adapter: GPUAdapter | null +): asserts adapter { + if (!('gpu' in navigator)) { + fail('navigator.gpu is not defined - WebGPU not available in this browser'); + } + + if (!adapter) { + fail("requestAdapter returned null - this sample can't run on this system"); + } +} + +/** + * Shows an error dialog if getting a adapter or device wasn't successful, + * or if/when the device is lost or has an uncaptured error. + */ +export function quitIfWebGPUNotAvailable( + adapter: GPUAdapter | null, + device: GPUDevice | null +): asserts device { + if (!device) { + quitIfAdapterNotAvailable(adapter); + fail('Unable to get a device for an unknown reason'); + } + + device.lost.then((reason) => { + fail(`Device lost ("${reason.reason}"):\n${reason.message}`); + }); + device.onuncapturederror = (ev) => { + fail(`Uncaptured error:\n${ev.error.message}`); + }; +} + +/** Fail by showing a console error, and dialog box if possible. */ +const fail = (() => { + type ErrorOutput = { show(msg: string): void }; + + function createErrorOutput() { + if (typeof document === 'undefined') { + // Not implemented in workers. + return { + show(msg: string) { + console.error(msg); + }, + }; + } + + const dialogBox = document.createElement('dialog'); + dialogBox.close(); + document.body.append(dialogBox); + + const dialogText = document.createElement('pre'); + dialogText.style.whiteSpace = 'pre-wrap'; + dialogBox.append(dialogText); + + const closeBtn = document.createElement('button'); + closeBtn.textContent = 'OK'; + closeBtn.onclick = () => dialogBox.close(); + dialogBox.append(closeBtn); + + return { + show(msg: string) { + // Don't overwrite the dialog message while it's still open + // (show the first error, not the most recent error). + if (!dialogBox.open) { + dialogText.textContent = msg; + dialogBox.showModal(); + } + }, + }; + } + + let output: ErrorOutput | undefined; + + return (message: string) => { + if (!output) output = createErrorOutput(); + + output.show(message); + throw new Error(message); + }; +})(); diff --git a/sample/videoUploading/main.ts b/sample/videoUploading/main.ts index 35283202..93d5ddb8 100644 --- a/sample/videoUploading/main.ts +++ b/sample/videoUploading/main.ts @@ -1,6 +1,11 @@ import { GUI } from 'dat.gui'; import fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl'; import sampleExternalTextureWGSL from '../../shaders/sampleExternalTexture.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; + +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); // Set video element const video = document.createElement('video'); @@ -10,9 +15,6 @@ video.muted = true; video.src = '../../assets/video/pano.webm'; await video.play(); -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); - const canvas = document.querySelector('canvas') as HTMLCanvasElement; const context = canvas.getContext('webgpu') as GPUCanvasContext; const devicePixelRatio = window.devicePixelRatio; diff --git a/sample/videoUploading/video.ts b/sample/videoUploading/video.ts index 3c79d578..22481556 100644 --- a/sample/videoUploading/video.ts +++ b/sample/videoUploading/video.ts @@ -1,6 +1,7 @@ import { GUI } from 'dat.gui'; import fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl'; import sampleExternalTextureWGSL from '../../shaders/sampleExternalTexture.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; export default async function ({ useVideoFrame }: { useVideoFrame: boolean }) { // Set video element @@ -11,8 +12,9 @@ export default async function ({ useVideoFrame }: { useVideoFrame: boolean }) { video.src = '../../assets/video/pano.webm'; await video.play(); - const adapter = await navigator.gpu.requestAdapter(); - const device = await adapter.requestDevice(); + const adapter = await navigator.gpu?.requestAdapter(); + const device = await adapter?.requestDevice(); + quitIfWebGPUNotAvailable(adapter, device); const canvas = document.querySelector('canvas') as HTMLCanvasElement; const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/volumeRenderingTexture3D/main.ts b/sample/volumeRenderingTexture3D/main.ts index 3b36ec74..941a91c8 100644 --- a/sample/volumeRenderingTexture3D/main.ts +++ b/sample/volumeRenderingTexture3D/main.ts @@ -1,6 +1,7 @@ import { mat4 } from 'wgpu-matrix'; import { GUI } from 'dat.gui'; import volumeWGSL from './volume.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; @@ -17,8 +18,9 @@ gui.add(params, 'rotateCamera', true); gui.add(params, 'near', 2.0, 7.0); gui.add(params, 'far', 2.0, 7.0); -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; const sampleCount = 4; diff --git a/sample/wireframe/main.ts b/sample/wireframe/main.ts index d64611ec..1a6b58cb 100644 --- a/sample/wireframe/main.ts +++ b/sample/wireframe/main.ts @@ -4,6 +4,7 @@ import { modelData } from './models'; import { randElement, randColor } from './utils'; import solidColorLitWGSL from './solidColorLit.wgsl'; import wireframeWGSL from './wireframe.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; const settings = { barycentricCoordinatesBased: false, @@ -60,8 +61,10 @@ function createVertexAndIndexBuffer( }; } -const adapter = await navigator.gpu.requestAdapter(); -const device = await adapter.requestDevice(); +const adapter = await navigator.gpu?.requestAdapter(); +const device = await adapter?.requestDevice(); +quitIfWebGPUNotAvailable(adapter, device); + const canvas = document.querySelector('canvas') as HTMLCanvasElement; const context = canvas.getContext('webgpu') as GPUCanvasContext; const devicePixelRatio = window.devicePixelRatio; diff --git a/sample/worker/worker.ts b/sample/worker/worker.ts index 4a3e52f9..d8e9ab89 100644 --- a/sample/worker/worker.ts +++ b/sample/worker/worker.ts @@ -10,6 +10,7 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; +import { quitIfWebGPUNotAvailable } from '../util'; // The worker process can instantiate a WebGPU device immediately, but it still needs an // OffscreenCanvas to be able to display anything. Here we listen for an 'init' message from the @@ -34,8 +35,9 @@ self.addEventListener('message', (ev) => { // to the init() method for all the other samples. The remainder of this file is largely identical // to the rotatingCube sample. async function init(canvas) { - const adapter = await navigator.gpu.requestAdapter(); - const device = await adapter.requestDevice(); + const adapter = await navigator.gpu?.requestAdapter(); + const device = await adapter?.requestDevice(); + quitIfWebGPUNotAvailable(adapter, device); const context = canvas.getContext('webgpu'); const presentationFormat = navigator.gpu.getPreferredCanvasFormat();