WebGPU feature detection: query before you create a device
Check adapter.features before calling requestDevice so your WebGPU app degrades gracefully instead of crashing on unsupported GPUs.
24 Jul 2025, 23:39 UTC

The problem: a missing feature crashes your renderer
You ship a WebGPU application that loads BC-compressed textures. It works on your laptop in Chrome. A user opens the same page in Firefox on the identical hardware, and the application throws an unhandled promise rejection before the first frame draws. The cause is not your shader code or your canvas size. It is an optional GPU capability that one adapter exposes and the other does not.
The useful takeaway is simple: inspect adapter.features before you call requestDevice(), and pass only the features you truly require. In WebGPU, feature support is a hard gate, not a soft optimization.
How WebGPU feature names work
The WebGPU specification defines a fixed set of GPUFeatureName values. Each describes an optional capability, such as BC texture compression, indirect-first-instance, or shader-float64. An adapter exposes the features it supports through adapter.features, a set-like collection you can query with .has().
When you call adapter.requestDevice({ requiredFeatures: [...] }), the browser rejects the promise if the adapter does not support every item in that list. That rejection happens during device creation, not later when you encode commands. If you request a feature the adapter lacks, there is no device to fall back to.
Worked example: require BC texture compression only when available
Run this in a browser console or a module served over a secure context. WebGPU is only available in secure contexts such as HTTPS or localhost.
async function createDeviceWithBC() {
if (!navigator.gpu) {
throw new Error('WebGPU is not available in this browser');
}
const adapter = await navigator.gpu.requestAdapter();
if (!adapter) {
throw new Error('No WebGPU adapter found');
}
const supportsBC = adapter.features.has('texture-compression-bc');
try {
const device = await adapter.requestDevice({
requiredFeatures: supportsBC ? ['texture-compression-bc'] : [],
});
return {
device,
bcEnabled: device.features.has('texture-compression-bc'),
};
} catch (error) {
console.error('WebGPU device creation failed:', error);
throw error;
}
}
Where to run: Browser developer tools console, or application code after the page loads. Permissions: No special user permission, but the page must be in a secure context and WebGPU must be enabled by the browser. Expected check: If BC is supported, device.features.has('texture-compression-bc') returns true. If it is not supported, the function returns a device without that feature instead of rejecting. Risk: Leaving the try/catch out means an unhandled rejection can crash the renderer on adapters that lack the feature.
Why support differs across browsers and devices
WebGPU implementations translate to different graphics APIs depending on the platform: Direct3D 12 on Windows, Metal on macOS and iOS, and Vulkan on Linux and Android. Because those APIs expose different texture-compression formats, an adapter may report texture-compression-bc on one browser and omit it on another. Mobile GPU vendors also ship varying subsets of the specification, so a feature available on a desktop adapter is not guaranteed on a phone.
Some browsers gate WebGPU behind experimental flags in pre-release channels. A feature you see in a developer flag or nightly build does not reflect what your users will have in production.
Trade-off: feature gating versus fallback complexity
| Approach | Benefit | Cost |
|---|---|---|
Require texture-compression-bc |
Simpler asset pipeline; smaller compressed textures | Blocks users whose adapters lack the feature |
| Query features, then choose BC, ASTC, ETC2, or uncompressed textures | Broadest device coverage | Multiple texture assets and code paths to maintain |
| Fall back to WebGL2 when WebGPU features are insufficient | Reaches older hardware | Separate rendering backend and shader language |
Practical verification and closing checklist
Open Chrome or Firefox developer tools, go to the GPU panel, and inspect navigator.gpu, adapter.features, and adapter.limits. Confirm which optional capabilities are active before you build feature-dependent resources.
Before you ship, verify this on real target devices, not only your development machine. Feature presence does not guarantee performance, and limits such as maxTextureDimension2D can still constrain your pipeline even when a feature is present.
- Call
navigator.gpu.requestAdapter()and check fornull. - Inspect
adapter.features.has()for each optional capability you need. - Pass a minimal
requiredFeaturesset torequestDevice(). - Wrap device creation in
try/catch. - Enable a fallback pipeline or WebGL2 renderer when required features are absent.
- Test on at least two browsers and one mobile device if your audience includes mobile users.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.