v139 · Web APIs · Compatibility Limits
Compatibility Limits
What is restricted in WebGPU compatibility mode compared to core WebGPU, why each restriction exists (OpenGL ES constraints), and how to write portable shaders that work in both modes.
Compatibility mode maps WebGPU to OpenGL ES 3.1+ and OpenGL 4.4+. These APIs lack certain features that Vulkan, Metal, and D3D12 provide. The restrictions listed here are the minimum set of compromises needed to support these older graphics APIs.
live adapter limits
Choose an adapter level to populate live limits from this browser.
| Limit | Live value | Compat implication |
|---|
feature availability
| Feature | Core WebGPU | Compatibility mode | Reason for restriction |
|---|---|---|---|
| Basic rendering, compute, textures | Yes | Yes | Supported in GLES 3.1 |
| Cube array textures | Yes | No | Not in GLES 3.1 core |
| Separate depth/stencil aspects | Yes | No | GL doesn't support separate views of depth/stencil |
| Multi-draw-indirect | Yes | No | Not universally available in GLES 3.1 |
WGSL sample_mask built-in |
Yes | No | GL sample mask limited in GLES |
| Texture array layers (2D) | Yes | Yes | Supported in GLES 3.0+ |
| Compute shaders | Yes | Yes | Required by GLES 3.1 |
| Storage buffers and textures | Yes | Yes | Supported in GLES 3.1 |
writing portable WGSL
// ✓ Works in both core and compatibility mode
@group(0) @binding(0) var myTex: texture_2d<f32>;
@group(0) @binding(1) var myArr: texture_2d_array<f32>;
@fragment fn fs(
@location(0) uv: vec2f,
@location(1) layer: f32,
) -> @location(0) vec4f {
let c = textureSample(myTex, mySampler, uv);
let a = textureSampleLevel(myArr, mySampler, uv, layer, 0.0);
return c + a * 0.5;
}
// ✗ Core only — avoid in code that needs compat mode:
// texture_cube_array — not available in compat
// @builtin(sample_mask) — not available in compat
// Separate depth/stencil views — not available in compat
detecting the mode
const adapter = await navigator.gpu.requestAdapter({
featureLevel: 'compatibility',
});
if (!adapter) {
// Even compat mode not available
useFallback();
return;
}
const isCompat = adapter.featureLevel === 'compatibility';
if (isCompat) {
// Avoid cube arrays, sample_mask, etc.
loadCompatShaders();
} else {
loadCoreShaders();
}