WebGPU适配与降级
WebGPU 不是「探测到 navigator.gpu 就能上生产」。adapter 为 null、feature 申请失败、非安全上下文,都是 产品路径。失败降到 WebGL2(再失败才 2D),不要弹「请升级浏览器」了事。
核对日期 2026-08 的覆盖面:Chrome / Edge 桌面可用;Safari 26 / iOS 26 起;Firefox 已进 Windows 与 macOS Apple Silicon。Linux / Android 上的 Firefox 不完整。Android Chrome 与桌面不是同一矩阵。以 requestAdapter() 为准,不以 UA 为准。
1. 安全上下文与 navigator.gpu
WebGPU 只在安全上下文(HTTPS 或 localhost)。局域网 HTTP、部分 WebView、混合内容页:navigator.gpu 为 undefined。这不是「浏览器太旧」。
Worker 里用 self.navigator.gpu(实现提供时)。主线程有、Worker 没有:把 GPU 工作留在能拿到 adapter 的线程,不要假设 Offscreen 一定能 webgpu。
2. adapter null 是常态
export type GpuBackend = "webgpu" | "webgl2" | "none";
export async function pickBackend(
canvas: HTMLCanvasElement,
): Promise<GpuBackend> {
if (navigator.gpu) {
const adapter = await navigator.gpu.requestAdapter({
powerPreference: "high-performance",
});
if (adapter) {
try {
const device = await adapter.requestDevice();
const ctx = canvas.getContext("webgpu");
if (ctx) {
ctx.configure({
device,
format: navigator.gpu.getPreferredCanvasFormat(),
alphaMode: "premultiplied",
});
return "webgpu";
}
} catch {
// requestDevice 可因 limits / 特性失败
}
}
}
const gl = canvas.getContext("webgl2", {
failIfMajorPerformanceCaveat: true,
preserveDrawingBuffer: false,
});
return gl ? "webgl2" : "none";
}
同一 <canvas> 第一次 getContext 定死。探测 WebGPU 失败后再 webgl2 可以(尚未成功绑上 webgpu 时)。已经 configure 过的节点不能改绑 webgl2。生产:先临时 canvas 探 adapter,视图 canvas 只绑最终后端。创建细节见 01。
forceFallbackAdapter: true 拿软件实现,只给测试。生产不要靠它冒充性能。
3. feature 与 limits:请求时就要说
adapter.features / adapter.limits 是设备上限。requestDevice({ requiredFeatures, requiredLimits }) 要的比 adapter 多,promise reject。常用可选:timestamp-query、texture-compression-bc / etc2 / astc、bgra8unorm-storage。没有压缩格式就走未压缩或离线转码,不要假设桌面 BC 在 iOS 有。
export async function requestShapedDevice(
adapter: GPUAdapter,
): Promise<GPUDevice> {
const features: GPUFeatureName[] = [];
if (adapter.features.has("texture-compression-bc")) {
features.push("texture-compression-bc");
}
const maxBuffer = Math.min(adapter.limits.maxBufferSize, 256 * 1024 * 1024);
return adapter.requestDevice({
requiredFeatures: features,
requiredLimits: { maxBufferSize: maxBuffer },
});
}
适用:在已知 feature 上开 HDR / 计算着色 / 时间戳。
不适用:把 Chrome 桌面 limits 写进 iOS 常量。超 maxTextureDimension2D 的失败是 requestDevice 或运行时 validation,视实现而定。
device.lost 后整表作废,见 04。重建时 adapter 可能已变,从 requestAdapter 再走一遍。
4. compatibility mode(一笔)
部分实现对 requestAdapter({ featureLevel: "compatibility" }) 提供 兼容模式:在达不到 core WebGPU 的 GPU / 驱动上,映射到 D3D11 / GLES 一类后端,换更窄的 limits 与特性集。岗位是 扩大可启动面,不是「core 的免费替身」。要 geometry shader 级能力、完整 compute 边界时,compatibility 可能直接给你 null 或更小 limits。探测仍以返回的 adapter / device 为准;失败就 WebGL2。不要对用户解释这个词。
5. 失败形态
| 症状 | 原因 |
|---|---|
HTTP 局域网 navigator.gpu 空 | 非安全上下文 |
requestAdapter() 为 null | Linux / Android Firefox、策略禁用、无适配驱动 |
requestDevice() reject | required feature / limits 超 adapter |
已绑 webgpu 再要 webgl2 为 null | 上下文互斥 |
configure 后黑屏 | 未重绘;或 format 没用 getPreferredCanvasFormat() |
| iOS 能进页、compute 挂 | feature 未申请或 compatibility 子集 |
对象少、要读屏,降级应落到 SVG / DOM,而不是再开一张失败的 canvas。
权威资料
- W3C — WebGPU
- MDN — GPU.requestAdapter()
- MDN — GPUAdapter.requestDevice()
- MDN — GPUCanvasContext.configure()
- Secure contexts
核对日期:2026-08-26