Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 99 additions & 1 deletion sample/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,97 @@ 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(
adapter: GPUAdapter | null,
Expand All @@ -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. */
Expand Down