Skip to content

Commit a20bac4

Browse files
committed
Add checks for direct buffer, texture, attachment support
Firefox and Chrome have supported this for 3-4 months or more. Safari started supporting it in 2025-12 as of Tahoe 26.2. We're planning to switch the samples to use this new more convenient method but want to be able to tell users on older browsers to update their browsers.
1 parent 22cebbf commit a20bac4

File tree

1 file changed

+99
-1
lines changed

1 file changed

+99
-1
lines changed

sample/util.ts

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,97 @@ export function quitIfFeaturesNotAvailable(
6060
}
6161
}
6262

63+
function supportsDirectBufferBinding(device: GPUDevice): boolean {
64+
const buffer = device.createBuffer({
65+
size: 16,
66+
usage: GPUBufferUsage.UNIFORM,
67+
});
68+
const layout = device.createBindGroupLayout({
69+
entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: {} }],
70+
});
71+
72+
try {
73+
device.createBindGroup({
74+
layout,
75+
entries: [{ binding: 0, resource: buffer }],
76+
});
77+
return true;
78+
} catch {
79+
return false;
80+
} finally {
81+
buffer.destroy();
82+
}
83+
}
84+
85+
function supportsDirectTextureBinding(device: GPUDevice): boolean {
86+
const texture = device.createTexture({
87+
size: [1],
88+
usage: GPUTextureUsage.TEXTURE_BINDING,
89+
format: 'rgba8unorm',
90+
});
91+
const layout = device.createBindGroupLayout({
92+
entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, texture: {} }],
93+
});
94+
95+
try {
96+
device.createBindGroup({
97+
layout,
98+
entries: [{ binding: 0, resource: texture }],
99+
});
100+
return true;
101+
} catch {
102+
return false;
103+
} finally {
104+
texture.destroy();
105+
}
106+
}
107+
108+
function supportsDirectTextureAttachments(device: GPUDevice): boolean {
109+
const texture = device.createTexture({
110+
size: [1],
111+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
112+
format: 'rgba8unorm',
113+
sampleCount: 4,
114+
});
115+
const resolveTarget = device.createTexture({
116+
size: [1],
117+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
118+
format: 'rgba8unorm',
119+
});
120+
const depthTexture = device.createTexture({
121+
size: [1],
122+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
123+
format: 'depth16unorm',
124+
sampleCount: 4,
125+
});
126+
const encoder = device.createCommandEncoder();
127+
try {
128+
const pass = encoder.beginRenderPass({
129+
colorAttachments: [
130+
{ view: texture, resolveTarget, loadOp: 'load', storeOp: 'store' },
131+
],
132+
depthStencilAttachment: {
133+
view: depthTexture,
134+
depthLoadOp: 'load',
135+
depthStoreOp: 'store',
136+
},
137+
});
138+
pass.end();
139+
return true;
140+
} catch (e) {
141+
console.error(e);
142+
return false;
143+
} finally {
144+
encoder.finish();
145+
texture.destroy();
146+
resolveTarget.destroy();
147+
}
148+
}
149+
63150
/**
64151
* Shows an error dialog if getting a adapter or device wasn't successful,
65-
* or if/when the device is lost or has an uncaptured error.
152+
* or if/when the device is lost or has an uncaptured error. Also checks
153+
* for direct buffer binding, direct texture binding, and direct texture attachment binding.
66154
*/
67155
export function quitIfWebGPUNotAvailable(
68156
adapter: GPUAdapter | null,
@@ -80,6 +168,16 @@ export function quitIfWebGPUNotAvailable(
80168
device.addEventListener('uncapturederror', (ev) => {
81169
fail(`Uncaptured error:\n${ev.error.message}`);
82170
});
171+
172+
if (
173+
!supportsDirectBufferBinding(device) ||
174+
!supportsDirectTextureBinding(device) ||
175+
!supportsDirectTextureAttachments(device)
176+
) {
177+
fail(
178+
'Core features of WebGPU are unavailable. Please update your browser to a newer version.'
179+
);
180+
}
83181
}
84182

85183
/** Fail by showing a console error, and dialog box if possible. */

0 commit comments

Comments
 (0)