diff --git a/sample/a-buffer/main.ts b/sample/a-buffer/main.ts index bd768489..9354b234 100644 --- a/sample/a-buffer/main.ts +++ b/sample/a-buffer/main.ts @@ -1,7 +1,10 @@ import { mat4, vec3 } from 'wgpu-matrix'; import { GUI } from 'dat.gui'; -import { quitIfWebGPUNotAvailable, quitIfLimitLessThan } from '../util'; +import { + quitIfWebGPUNotAvailableOrMissingFeatures, + quitIfLimitLessThan, +} from '../util'; import { mesh } from '../../meshes/teapot'; import opaqueWGSL from './opaque.wgsl'; @@ -21,7 +24,7 @@ quitIfLimitLessThan(adapter, 'maxStorageBuffersInFragmentStage', 2, limits); const device = await adapter?.requestDevice({ requiredLimits: limits, }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); diff --git a/sample/animometer/main.ts b/sample/animometer/main.ts index 56769f80..94c408c5 100644 --- a/sample/animometer/main.ts +++ b/sample/animometer/main.ts @@ -1,13 +1,13 @@ import { GUI } from 'dat.gui'; import animometerWGSL from './animometer.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const perfDisplayContainer = document.createElement('div'); perfDisplayContainer.style.color = 'white'; diff --git a/sample/bitonicSort/utils.ts b/sample/bitonicSort/utils.ts index 03a33f56..fb6b8488 100644 --- a/sample/bitonicSort/utils.ts +++ b/sample/bitonicSort/utils.ts @@ -2,7 +2,7 @@ import type { GUI } from 'dat.gui'; import fullscreenTexturedQuad from '../../shaders/fullscreenTexturedQuad.wgsl'; import { quitIfAdapterNotAvailable, - quitIfWebGPUNotAvailable, + quitIfWebGPUNotAvailableOrMissingFeatures, quitIfLimitLessThan, } from '../util'; @@ -131,7 +131,7 @@ export const SampleInitFactoryWebGPU = async ( requiredFeatures: features, requiredLimits: limits, }); - quitIfWebGPUNotAvailable(adapter, device); + quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); const devicePixelRatio = window.devicePixelRatio; diff --git a/sample/blending/main.ts b/sample/blending/main.ts index 975b4162..7444cb30 100644 --- a/sample/blending/main.ts +++ b/sample/blending/main.ts @@ -1,13 +1,13 @@ import { mat4 } from 'wgpu-matrix'; import { GUI } from 'dat.gui'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; import texturedQuadWGSL from './texturedQuad.wgsl'; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); // creates a CSS hsl string from 3 normalized numbers (0 to 1) const hsl = (hue: number, saturation: number, lightness: number) => diff --git a/sample/cameras/main.ts b/sample/cameras/main.ts index 0c32f115..44685ea2 100644 --- a/sample/cameras/main.ts +++ b/sample/cameras/main.ts @@ -10,7 +10,7 @@ import { import cubeWGSL from './cube.wgsl'; import { ArcballCamera, WASDCamera } from './camera'; import { createInputHandler } from './input'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; @@ -44,7 +44,7 @@ const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); const devicePixelRatio = window.devicePixelRatio; diff --git a/sample/computeBoids/main.ts b/sample/computeBoids/main.ts index a757e8dd..24c01098 100644 --- a/sample/computeBoids/main.ts +++ b/sample/computeBoids/main.ts @@ -1,4 +1,7 @@ -import { quitIfAdapterNotAvailable, quitIfWebGPUNotAvailable } from '../util'; +import { + quitIfAdapterNotAvailable, + quitIfWebGPUNotAvailableOrMissingFeatures, +} from '../util'; import spriteWGSL from './sprite.wgsl'; import updateSpritesWGSL from './updateSprites.wgsl'; import { GUI } from 'dat.gui'; @@ -13,7 +16,7 @@ const hasTimestampQuery = adapter.features.has('timestamp-query'); const device = await adapter.requestDevice({ requiredFeatures: hasTimestampQuery ? ['timestamp-query'] : [], }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const perfDisplayContainer = document.createElement('div'); perfDisplayContainer.style.color = 'white'; diff --git a/sample/cornell/main.ts b/sample/cornell/main.ts index a74e4c13..36cf1687 100644 --- a/sample/cornell/main.ts +++ b/sample/cornell/main.ts @@ -7,7 +7,7 @@ import Tonemapper from './tonemapper'; import Raytracer from './raytracer'; import { quitIfAdapterNotAvailable, - quitIfWebGPUNotAvailable, + quitIfWebGPUNotAvailableOrMissingFeatures, quitIfLimitLessThan, } from '../util'; @@ -38,7 +38,7 @@ const device = await adapter?.requestDevice({ requiredFeatures: features, requiredLimits: limits, }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const params: { renderer: 'rasterizer' | 'raytracer'; diff --git a/sample/cubemap/main.ts b/sample/cubemap/main.ts index 57b3fe9b..32515192 100644 --- a/sample/cubemap/main.ts +++ b/sample/cubemap/main.ts @@ -10,14 +10,14 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import sampleCubemapWGSL from './sampleCubemap.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/deferredRendering/main.ts b/sample/deferredRendering/main.ts index 4f0e3469..dcf162a1 100644 --- a/sample/deferredRendering/main.ts +++ b/sample/deferredRendering/main.ts @@ -8,7 +8,10 @@ import fragmentWriteGBuffers from './fragmentWriteGBuffers.wgsl'; import vertexTextureQuad from './vertexTextureQuad.wgsl'; import fragmentGBuffersDebugView from './fragmentGBuffersDebugView.wgsl'; import fragmentDeferredRendering from './fragmentDeferredRendering.wgsl'; -import { quitIfWebGPUNotAvailable, quitIfLimitLessThan } from '../util'; +import { + quitIfWebGPUNotAvailableOrMissingFeatures, + quitIfLimitLessThan, +} from '../util'; const kMaxNumLights = 1024; const lightExtentMin = vec3.fromValues(-50, -30, -50); @@ -23,7 +26,7 @@ quitIfLimitLessThan(adapter, 'maxStorageBuffersInFragmentStage', 1, limits); const device = await adapter?.requestDevice({ requiredLimits: limits, }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/fractalCube/main.ts b/sample/fractalCube/main.ts index 1e1c16bc..a8f0987e 100644 --- a/sample/fractalCube/main.ts +++ b/sample/fractalCube/main.ts @@ -10,14 +10,14 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import sampleSelfWGSL from './sampleSelf.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/gameOfLife/main.ts b/sample/gameOfLife/main.ts index 5876bb5a..e12bddb6 100644 --- a/sample/gameOfLife/main.ts +++ b/sample/gameOfLife/main.ts @@ -2,14 +2,14 @@ import { GUI } from 'dat.gui'; import computeWGSL from './compute.wgsl'; import vertWGSL from './vert.wgsl'; import fragWGSL from './frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); const devicePixelRatio = window.devicePixelRatio; diff --git a/sample/generateMipmap/main.ts b/sample/generateMipmap/main.ts index df437fb2..5f2545ca 100644 --- a/sample/generateMipmap/main.ts +++ b/sample/generateMipmap/main.ts @@ -1,6 +1,6 @@ import { mat4 } from 'wgpu-matrix'; import { generateMips } from './generateMipmap'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; import { makeCanvasImage } from './makeCanvasImage'; import { cubeVertexArray, @@ -23,7 +23,7 @@ const device = await adapter.requestDevice({ ? ['core-features-and-limits'] : [], }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const canvas = document.querySelector('canvas') as HTMLCanvasElement; const context = canvas.getContext('webgpu'); diff --git a/sample/helloTriangle/main.ts b/sample/helloTriangle/main.ts index 0730c4bb..11b16450 100644 --- a/sample/helloTriangle/main.ts +++ b/sample/helloTriangle/main.ts @@ -1,13 +1,13 @@ import triangleVertWGSL from '../../shaders/triangle.vert.wgsl'; import redFragWGSL from '../../shaders/red.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/helloTriangleMSAA/main.ts b/sample/helloTriangleMSAA/main.ts index f59e34d0..6d7a138e 100644 --- a/sample/helloTriangleMSAA/main.ts +++ b/sample/helloTriangleMSAA/main.ts @@ -1,13 +1,13 @@ import triangleVertWGSL from '../../shaders/triangle.vert.wgsl'; import redFragWGSL from '../../shaders/red.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/imageBlur/main.ts b/sample/imageBlur/main.ts index 19ce3e42..241b0d4a 100644 --- a/sample/imageBlur/main.ts +++ b/sample/imageBlur/main.ts @@ -1,7 +1,7 @@ import { GUI } from 'dat.gui'; import blurWGSL from './blur.wgsl'; import fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; // Contants from the blur.wgsl shader. const tileDim = 128; @@ -12,7 +12,7 @@ const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/instancedCube/main.ts b/sample/instancedCube/main.ts index 6c8b3238..812416a9 100644 --- a/sample/instancedCube/main.ts +++ b/sample/instancedCube/main.ts @@ -10,14 +10,14 @@ import { import instancedVertWGSL from './instanced.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/multipleCanvases/main.ts b/sample/multipleCanvases/main.ts index 8e2ccec9..715ec21a 100644 --- a/sample/multipleCanvases/main.ts +++ b/sample/multipleCanvases/main.ts @@ -1,6 +1,6 @@ import { mat4, mat3 } from 'wgpu-matrix'; import { modelData } from './models'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; type TypedArrayView = Float32Array | Uint32Array; @@ -50,7 +50,7 @@ const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(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 7ade2b11..ae7e8e25 100644 --- a/sample/normalMap/main.ts +++ b/sample/normalMap/main.ts @@ -8,7 +8,7 @@ import { create3DRenderPipeline, createTextureFromImage, } from './utils'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const MAT4X4_BYTES = 64; enum TextureAtlas { @@ -22,7 +22,7 @@ const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); const devicePixelRatio = window.devicePixelRatio; canvas.width = canvas.clientWidth * devicePixelRatio; diff --git a/sample/occlusionQuery/main.ts b/sample/occlusionQuery/main.ts index cf25c152..81a9b1d0 100644 --- a/sample/occlusionQuery/main.ts +++ b/sample/occlusionQuery/main.ts @@ -1,7 +1,7 @@ import { GUI } from 'dat.gui'; import { mat4 } from 'wgpu-matrix'; import solidColorLitWGSL from './solidColorLit.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const settings = { animate: true, @@ -35,7 +35,7 @@ const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const canvas = document.querySelector('canvas') as HTMLCanvasElement; const context = canvas.getContext('webgpu'); diff --git a/sample/particles/main.ts b/sample/particles/main.ts index 17135cb4..21b6c79e 100644 --- a/sample/particles/main.ts +++ b/sample/particles/main.ts @@ -3,7 +3,7 @@ import { GUI } from 'dat.gui'; import particleWGSL from './particle.wgsl'; import probabilityMapWGSL from './probabilityMap.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const numParticles = 50000; const particlePositionOffset = 0; @@ -21,7 +21,7 @@ const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/points/main.ts b/sample/points/main.ts index fc48775b..24932591 100644 --- a/sample/points/main.ts +++ b/sample/points/main.ts @@ -5,7 +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'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; // See: https://www.google.com/search?q=fibonacci+sphere function createFibonacciSphereVertices({ @@ -33,7 +33,7 @@ const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); // Get a WebGPU context from the canvas and configure it const canvas = document.querySelector('canvas') as HTMLCanvasElement; diff --git a/sample/primitivePicking/main.ts b/sample/primitivePicking/main.ts index 8966f24f..35ff2a47 100644 --- a/sample/primitivePicking/main.ts +++ b/sample/primitivePicking/main.ts @@ -7,7 +7,10 @@ import vertexForwardRendering from './vertexForwardRendering.wgsl'; import fragmentForwardRendering from './fragmentForwardRendering.wgsl'; import vertexTextureQuad from './vertexTextureQuad.wgsl'; import fragmentPrimitivesDebugView from './fragmentPrimitivesDebugView.wgsl'; -import { quitIfWebGPUNotAvailable, quitIfFeaturesNotAvailable } from '../util'; +import { + quitIfWebGPUNotAvailableOrMissingFeatures, + quitIfFeaturesNotAvailable, +} from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ @@ -20,7 +23,7 @@ quitIfFeaturesNotAvailable(adapter, requiredFeatures); const device = await adapter.requestDevice({ requiredFeatures, }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu') as GPUCanvasContext; diff --git a/sample/renderBundles/main.ts b/sample/renderBundles/main.ts index cc53b10c..46e9596f 100644 --- a/sample/renderBundles/main.ts +++ b/sample/renderBundles/main.ts @@ -4,7 +4,7 @@ import { createSphereMesh, SphereLayout } from '../../meshes/sphere'; import Stats from 'stats.js'; import meshWGSL from './mesh.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; interface Renderable { vertices: GPUBuffer; @@ -18,7 +18,7 @@ const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const settings = { useRenderBundles: true, diff --git a/sample/resizeCanvas/main.ts b/sample/resizeCanvas/main.ts index 50fa33c6..aefb59cf 100644 --- a/sample/resizeCanvas/main.ts +++ b/sample/resizeCanvas/main.ts @@ -1,13 +1,13 @@ import triangleVertWGSL from '../../shaders/triangle.vert.wgsl'; import redFragWGSL from '../../shaders/red.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/resizeObserverHDDPI/main.ts b/sample/resizeObserverHDDPI/main.ts index ba1cd462..6d0f447c 100644 --- a/sample/resizeObserverHDDPI/main.ts +++ b/sample/resizeObserverHDDPI/main.ts @@ -1,13 +1,13 @@ import { GUI } from 'dat.gui'; import checkerWGSL from './checker.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/reversedZ/main.ts b/sample/reversedZ/main.ts index 89d03b8a..e79fbc65 100644 --- a/sample/reversedZ/main.ts +++ b/sample/reversedZ/main.ts @@ -8,7 +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'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; // Two planes close to each other for depth precision test const geometryVertexSize = 4 * 8; // Byte size of one geometry vertex. @@ -70,7 +70,7 @@ const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/rotatingCube/main.ts b/sample/rotatingCube/main.ts index a990d9ad..a13b3a4f 100644 --- a/sample/rotatingCube/main.ts +++ b/sample/rotatingCube/main.ts @@ -10,14 +10,14 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/samplerParameters/main.ts b/sample/samplerParameters/main.ts index 301ec7c3..0cf3553b 100644 --- a/sample/samplerParameters/main.ts +++ b/sample/samplerParameters/main.ts @@ -3,7 +3,10 @@ import { GUI } from 'dat.gui'; import texturedSquareWGSL from './texturedSquare.wgsl'; import showTextureWGSL from './showTexture.wgsl'; -import { quitIfWebGPUNotAvailable, quitIfLimitLessThan } from '../util'; +import { + quitIfWebGPUNotAvailableOrMissingFeatures, + quitIfLimitLessThan, +} from '../util'; const kMatrices: Readonly = new Float32Array([ // Row 1: Scale by 2 @@ -36,7 +39,7 @@ quitIfLimitLessThan(adapter, 'maxStorageBuffersInVertexStage', 1, limits); const device = await adapter?.requestDevice({ requiredLimits: limits, }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); // // GUI controls diff --git a/sample/shadowMapping/main.ts b/sample/shadowMapping/main.ts index 38bda515..edff255b 100644 --- a/sample/shadowMapping/main.ts +++ b/sample/shadowMapping/main.ts @@ -4,7 +4,7 @@ import { mesh } from '../../meshes/stanfordDragon'; import vertexShadowWGSL from './vertexShadow.wgsl'; import vertexWGSL from './vertex.wgsl'; import fragmentWGSL from './fragment.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const shadowDepthTextureSize = 1024; @@ -13,7 +13,7 @@ const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/skinnedMesh/main.ts b/sample/skinnedMesh/main.ts index fba179e8..6dd76e28 100644 --- a/sample/skinnedMesh/main.ts +++ b/sample/skinnedMesh/main.ts @@ -9,7 +9,10 @@ import { createSkinnedGridRenderPipeline, } from './gridUtils'; import { gridIndices } from './gridData'; -import { quitIfWebGPUNotAvailable, quitIfLimitLessThan } from '../util'; +import { + quitIfWebGPUNotAvailableOrMissingFeatures, + quitIfLimitLessThan, +} from '../util'; const MAT4X4_BYTES = 64; @@ -103,7 +106,7 @@ quitIfLimitLessThan(adapter, 'maxStorageBuffersInVertexStage', 2, limits); const device = await adapter?.requestDevice({ requiredLimits: limits, }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/stencilMask/main.ts b/sample/stencilMask/main.ts index 14e76f92..434e2e10 100644 --- a/sample/stencilMask/main.ts +++ b/sample/stencilMask/main.ts @@ -11,13 +11,13 @@ import { reorientInPlace, VertexData, } from '../../meshes/primitives'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); // Get a WebGPU context from the canvas and configure it const canvas = document.querySelector('canvas') as HTMLCanvasElement; diff --git a/sample/textRenderingMsdf/main.ts b/sample/textRenderingMsdf/main.ts index f641d6b1..2f2691b5 100644 --- a/sample/textRenderingMsdf/main.ts +++ b/sample/textRenderingMsdf/main.ts @@ -11,7 +11,10 @@ import { MsdfTextRenderer } from './msdfText'; import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; -import { quitIfWebGPUNotAvailable, quitIfLimitLessThan } from '../util'; +import { + quitIfWebGPUNotAvailableOrMissingFeatures, + quitIfLimitLessThan, +} from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ @@ -23,7 +26,7 @@ quitIfLimitLessThan(adapter, 'maxStorageBuffersInVertexStage', 2, limits); const device = await adapter?.requestDevice({ requiredLimits: limits, }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/texturedCube/main.ts b/sample/texturedCube/main.ts index 63315e37..f24d8e17 100644 --- a/sample/texturedCube/main.ts +++ b/sample/texturedCube/main.ts @@ -10,14 +10,14 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import sampleTextureMixColorWGSL from './sampleTextureMixColor.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/timestampQuery/main.ts b/sample/timestampQuery/main.ts index f4234149..c1424a78 100644 --- a/sample/timestampQuery/main.ts +++ b/sample/timestampQuery/main.ts @@ -10,7 +10,7 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import fragmentWGSL from '../../shaders/black.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; import PerfCounter from './PerfCounter'; import TimestampQueryManager from './TimestampQueryManager'; @@ -29,7 +29,7 @@ const device = await adapter?.requestDevice({ // We request a device that has support for timestamp queries requiredFeatures: supportsTimestampQueries ? ['timestamp-query'] : [], }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); // GPU-side timer and the CPU-side counter where we accumulate statistics: // NB: Look for 'timestampQueryManager' in this file to locate parts of this diff --git a/sample/transparentCanvas/main.ts b/sample/transparentCanvas/main.ts index b2ac4ca7..f26d76c3 100644 --- a/sample/transparentCanvas/main.ts +++ b/sample/transparentCanvas/main.ts @@ -10,14 +10,14 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/twoCubes/main.ts b/sample/twoCubes/main.ts index 2b1e62dc..25b852b2 100644 --- a/sample/twoCubes/main.ts +++ b/sample/twoCubes/main.ts @@ -10,14 +10,14 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); diff --git a/sample/util.ts b/sample/util.ts index 5a392278..10522835 100644 --- a/sample/util.ts +++ b/sample/util.ts @@ -60,11 +60,99 @@ export function quitIfFeaturesNotAvailable( } } +function supportsDirectBufferBinding(device: GPUDevice): boolean { + const buffer = device.createBuffer({ + size: 16, + usage: GPUBufferUsage.UNIFORM, + }); + const layout = device.createBindGroupLayout({ + entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: {} }], + }); + + try { + device.createBindGroup({ + layout, + entries: [{ binding: 0, resource: buffer }], + }); + return true; + } catch { + return false; + } finally { + buffer.destroy(); + } +} + +function supportsDirectTextureBinding(device: GPUDevice): boolean { + const texture = device.createTexture({ + size: [1], + usage: GPUTextureUsage.TEXTURE_BINDING, + format: 'rgba8unorm', + }); + const layout = device.createBindGroupLayout({ + entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, texture: {} }], + }); + + try { + device.createBindGroup({ + layout, + entries: [{ binding: 0, resource: texture }], + }); + return true; + } catch { + return false; + } finally { + texture.destroy(); + } +} + +function supportsDirectTextureAttachments(device: GPUDevice): boolean { + const texture = device.createTexture({ + size: [1], + usage: GPUTextureUsage.RENDER_ATTACHMENT, + format: 'rgba8unorm', + sampleCount: 4, + }); + const resolveTarget = device.createTexture({ + size: [1], + usage: GPUTextureUsage.RENDER_ATTACHMENT, + format: 'rgba8unorm', + }); + const depthTexture = device.createTexture({ + size: [1], + usage: GPUTextureUsage.RENDER_ATTACHMENT, + format: 'depth16unorm', + sampleCount: 4, + }); + const encoder = device.createCommandEncoder(); + try { + const pass = encoder.beginRenderPass({ + colorAttachments: [ + { view: texture, resolveTarget, loadOp: 'load', storeOp: 'store' }, + ], + depthStencilAttachment: { + view: depthTexture, + depthLoadOp: 'load', + depthStoreOp: 'store', + }, + }); + pass.end(); + return true; + } catch (e) { + console.error(e); + return false; + } finally { + encoder.finish(); + texture.destroy(); + resolveTarget.destroy(); + } +} + /** * 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. + * or if/when the device is lost or has an uncaptured error. Also checks + * for direct buffer binding, direct texture binding, and direct texture attachment binding. */ -export function quitIfWebGPUNotAvailable( +export function quitIfWebGPUNotAvailableOrMissingFeatures( adapter: GPUAdapter | null, device: GPUDevice | null ): asserts device { @@ -80,6 +168,16 @@ export function quitIfWebGPUNotAvailable( device.addEventListener('uncapturederror', (ev) => { fail(`Uncaptured error:\n${ev.error.message}`); }); + + if ( + !supportsDirectBufferBinding(device) || + !supportsDirectTextureBinding(device) || + !supportsDirectTextureAttachments(device) + ) { + fail( + 'Core features of WebGPU are unavailable. Please update your browser to a newer version.' + ); + } } /** Fail by showing a console error, and dialog box if possible. */ diff --git a/sample/videoUploading/main.ts b/sample/videoUploading/main.ts index 92858ca5..b017690c 100644 --- a/sample/videoUploading/main.ts +++ b/sample/videoUploading/main.ts @@ -3,13 +3,13 @@ import { mat3, mat4 } from 'wgpu-matrix'; import fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl'; import sampleExternalTextureWGSL from './sampleExternalTexture.frag.wgsl'; import sampleExternalTextureAsPanoramaWGSL from './sampleExternalTextureAsPanorama.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const adapter = await navigator.gpu?.requestAdapter({ featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const videos = { 'giraffe (2d)': { diff --git a/sample/volumeRenderingTexture3D/main.ts b/sample/volumeRenderingTexture3D/main.ts index c379632d..ce8ee0d0 100644 --- a/sample/volumeRenderingTexture3D/main.ts +++ b/sample/volumeRenderingTexture3D/main.ts @@ -1,7 +1,7 @@ import { mat4 } from 'wgpu-matrix'; import { GUI } from 'dat.gui'; import volumeWGSL from './volume.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } from '../util'; const canvas = document.querySelector('canvas') as HTMLCanvasElement; const status = document.getElementById('status') as HTMLDivElement; @@ -74,7 +74,7 @@ if (adapter?.features.has('texture-compression-astc-sliced-3d')) { } const device = await adapter?.requestDevice({ requiredFeatures }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); const sampleCount = 4; diff --git a/sample/wireframe/main.ts b/sample/wireframe/main.ts index d0dd8089..f30ba642 100644 --- a/sample/wireframe/main.ts +++ b/sample/wireframe/main.ts @@ -4,7 +4,10 @@ import { modelData } from './models'; import { randElement, randColor } from './utils'; import solidColorLitWGSL from './solidColorLit.wgsl'; import wireframeWGSL from './wireframe.wgsl'; -import { quitIfWebGPUNotAvailable, quitIfLimitLessThan } from '../util'; +import { + quitIfWebGPUNotAvailableOrMissingFeatures, + quitIfLimitLessThan, +} from '../util'; const settings = { barycentricCoordinatesBased: false, @@ -69,7 +72,7 @@ quitIfLimitLessThan(adapter, 'maxStorageBuffersInVertexStage', 2, limits); const device = await adapter?.requestDevice({ requiredLimits: limits, }); -quitIfWebGPUNotAvailable(adapter, device); +quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const canvas = document.querySelector('canvas') as HTMLCanvasElement; const context = canvas.getContext('webgpu'); diff --git a/sample/worker/worker.ts b/sample/worker/worker.ts index 0be8298a..a543022c 100644 --- a/sample/worker/worker.ts +++ b/sample/worker/worker.ts @@ -10,7 +10,7 @@ import { import basicVertWGSL from '../../shaders/basic.vert.wgsl'; import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl'; -import { quitIfWebGPUNotAvailable } from '../util'; +import { quitIfWebGPUNotAvailableOrMissingFeatures } 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 @@ -39,7 +39,7 @@ async function init(canvas) { featureLevel: 'compatibility', }); const device = await adapter?.requestDevice(); - quitIfWebGPUNotAvailable(adapter, device); + quitIfWebGPUNotAvailableOrMissingFeatures(adapter, device); const context = canvas.getContext('webgpu'); const presentationFormat = navigator.gpu.getPreferredCanvasFormat();