"gpu" in navigator 只说明页面看见一个 API 入口,不说明当前机器能拿到 adapter,不说明所需 feature 与 limit 存在,更不说明这条实现比 WebGL 快。驱动黑名单、硬件加速设置、操作系统、浏览器渠道、远程桌面、隐私策略和资源压力都可能改变结果。把 WebGPU 当作布尔开关,最终会让一部分用户得到黑屏,而不是更先进的动画。

本文面向准备为作品集实验或数据可视化加入 WebGPU 的前端开发者。前置知识是 Promise、GPU pipeline 与 WebGL 基础。截至 2026-07-16,MDN 仍将 WebGPU 标记为 Limited availability、非 Baseline,并要求安全上下文;W3C 文档是 2026-05-21 Candidate Recommendation Draft。浏览器支持处于变化中,本文固定这个核验时间点,不把任何实现状态写成永久结论。

视觉资产记录:封面(1600 × 900)与文中能力决策图(1200 × 680)均为 WEB/SUN 于 2026-07-16 创作的程序化 SVG;来源/许可为本项目原创自有资产,未使用第三方图片。

兼容性不是一张“支持/不支持”表

MDN WebGPU API明确标注其可用性有限,并说明 API 暴露在 Navigator 与 WorkerNavigator、只在 secure context 可用。Chrome 官方概览记录了 Chrome 113 的首批发布,以及后续 Firefox 141 在 Windows、Safari 26 等实现进展;这些信息只能描述对应版本与平台,不能推导所有 Firefox、所有 Safari 或嵌入式 WebView 都已具备同等能力。

生产文档应写“2026-07-16 在目标浏览器矩阵实测”,并列出 OS、浏览器版本和硬件,而不是写“现代浏览器都支持”。本地 localhost 通常被视为可信来源,部署却需要合法 HTTPS;测试环境能看到 navigator.gpu 不代表 HTTP 线上也能看到。

规范状态也要区分。W3C WebGPU 文档发布历史显示它仍在候选推荐草案阶段。浏览器可以在规范完成前实现,API 也可能继续演进。固定 lockfile、编译器和 shader 测试比凭记忆追新更可靠。

能力是逐层协商

完整初始化至少经过五道门:

  1. 页面处于安全上下文,且产品确实需要增强层。
  2. navigator.gpu 存在。
  3. requestAdapter() 返回非空 adapter。
  4. adapter 的 featureslimits 满足这个效果的最小合同
  5. requestDevice() 成功,配置 canvas、创建 shader module 与 pipeline 也成功。

MDN requestAdapter()说明 Promise 可能得到 null:没有合适 adapter、实现不可用或请求条件无法满足都可能发生。请求 high-performance 也只是偏好,不是保证;不要因未获得独显就拒绝一个本可运行的轻量效果。

WebGPU 能力协商和回退决策图

图 1(1200 × 680):从 HTTPS 到 device 逐级协商,任何拒绝、初始化错误或设备丢失都进入相同语义的 WebGL、Canvas 2D 或 DOM 实现。原创程序化 SVG,WEB/SUN,2026-07-16。

返回结果,不要把失败变成未捕获异常

初始化函数适合返回带后端和 cleanup 的判别联合,让调用者只关心“最终能展示什么”:

type RendererResult =
  { backend: 'webgpu'; dispose(): void } | { backend: 'webgl' | 'canvas' | 'dom'; dispose(): void };

async function createRenderer(host: HTMLElement): Promise<RendererResult> {
  if (!window.isSecureContext || !('gpu' in navigator)) {
    return createFallback(host);
  }

  try {
    const adapter = await navigator.gpu.requestAdapter({
      powerPreference: 'high-performance',
    });
    if (!adapter) return createFallback(host);

    const required = 'timestamp-query' as GPUFeatureName;
    if (!adapter.features.has(required)) return createFallback(host);

    const device = await adapter.requestDevice({
      requiredFeatures: [required],
    });
    return await createWebGpuRenderer(host, adapter, device);
  } catch (error) {
    reportInitializationFailure(error);
    return createFallback(host);
  }
}

示例中的 timestamp-query 只是演示 feature 协商,普通动效不应无理由要求它。每增加一个 required feature 或更高 limit,兼容集合都会缩小。先写最小需求,再让高能力设备开启额外效果;不要把“可能用到”全部塞进 requestDevice()

limits 也不能只看是否大于某数。WebGPU 的可移植模型要求应用在 adapter 报告范围内申请设备限制;纹理维度、绑定组、buffer 大小与 workgroup 限制都可能影响算法。设计时准备数据分块、降低粒子数量或使用较小纹理,而不是遇到较低 limit 就整页失败。

Pipeline 失败也必须回退

拿到 device 之后仍可能在 WGSL 编译、bind group layout、canvas format、pipeline 创建或资源分配处失败。Chrome 从 WebGL 到 WebGPU 的指南强调 WebGPU 使用更显式的 pipeline、command encoder 与资源绑定模型;把 WebGL 初始化代码逐行翻译,并不会自动得到正确或更快的实现。

在开发环境读取 shader compilation info,给异步 pipeline 创建加错误边界;用 device.pushErrorScope() / popErrorScope() 捕获预期的 validation 或 out-of-memory 错误,并监听 uncapturederror 记录漏出的错误。错误信息可以进入本地诊断,但不要在公开页面暴露硬件细节。

device.lost 是整个生命周期的一部分。它可能由资源压力、驱动重置、设备销毁或其他原因触发。处理器要停止调度、释放 DOM 引用、撤下 GPU ready 状态;只在明确可恢复且有次数上限时重新初始化,否则落到备用后端,避免无限重试。

const generation = ++rendererGeneration;
let disposed = false;

device.lost.then((info) => {
  if (disposed || generation !== rendererGeneration) return;
  stopFrameLoop();
  host.removeAttribute('data-gpu-ready');
  recordDeviceLoss(info.reason);
  mountFallback(host);
});

return () => {
  disposed = true;
  if (generation === rendererGeneration) rendererGeneration += 1;
  stopFrameLoop();
  disposeGpuResources();
};

Canvas 配置同样属于可失败边界。先取得 webgpu context,再用 navigator.gpu.getPreferredCanvasFormat() 选择当前平台推荐格式,按实际 CSS 尺寸与受控 DPR 配置画布。尺寸为零、宿主已从 DOM 移除或页面已经 cleanup 时,不应继续创建纹理和 command buffer。ResizeObserver 只更新待处理尺寸,下一帧再重配资源,避免同一回调读写布局。

若把渲染移到 Worker,WebGPU 在支持环境可以通过 WorkerNavigator 使用,但 OffscreenCanvas、消息传输和页面生命周期又形成一层独立能力门禁。主线程仍拥有语义 DOM与路由 scope;切页时向 Worker 发送停止协议并终止它,不能因为绘制不在主线程就假设资源会自动归零。Worker 失败也应回到同一备用后端,而不是出现第二套错误页面。

回退应共享输入和语义

不要维护四个完全独立的产品。把动画输入抽象成与后端无关的状态,例如 seed、时间、指针、密度、颜色与文章节点;WebGPU、WebGL、Canvas 2D 都消费同一快照,DOM 则呈现稳定的最终构图。这样能力不足改变的是渲染质量,不是页面内容和操作。

推荐层级不是固定的:计算密集实验可以 WebGPU → WebGL2 → 静态图;少量粒子可以 WebGPU → Canvas 2D → DOM;装饰标题可能直接 WebGPU → CSS。每层都必须单独可测试、可销毁,并在 Reduced Motion 下选择静态状态。回退资源应与 HTML 一同提供,不能等 WebGPU 失败后再请求一个不存在的备用包。

质量降级也可以发生在 WebGPU 内部:降低实例数、纹理尺寸、采样次数或更新频率,比“全功能或黑屏”更平滑。但每一档必须保持数据含义一致,并在 UI 中避免伪装成同等精度。例如粒子只是装饰可以无提示减少;数据图若抽样会改变判断,就必须标明或切换静态准确表示。

“可用”不等于“更快”

Chrome WebGPU 故障排查列出安全上下文、硬件加速、adapter 不可用和设备配置等失败原因,也提醒软件路径或不成熟的移植可能让 WebGPU 表现更差。不要让用户为了作品集效果开启不安全 flag、关闭浏览器保护或修改系统设置;这不是兼容方案。

性能比较必须让输出、输入、尺寸与质量相同。记录设备、GPU、系统、浏览器、DPR、画布尺寸、粒子数、shader 版本、预热策略和采样区间;同时观察 CPU 提交、GPU 时间、长帧、内存与初始化开销。WebGPU 在稳态计算中更快,也可能因较大初始化和 chunk 让首屏更慢。本文未执行这些测试,因此不提供“提升倍数”。

失败模式与验收

失败模式 为什么错 验收方式
只检测 navigator.gpu adapter、feature、device 仍可能失败 模拟 null、拒绝和 pipeline error
使用 UA 白名单 同版本也受 OS、驱动和策略影响 用真实能力协商与目标矩阵
要求所有可选 feature 无谓缩小兼容集合 记录每个 required feature 的用途
device lost 后刷新页面 丢失用户状态且可能再次失败 停止调度并切换备用后端
WebGPU 与回退内容不同 能力不足导致功能缺失 共享状态模型与键盘路径
把可用写成更快 未测量仍下性能结论 同输入、同质量、同设备 trace

测试矩阵至少包含:非安全上下文、navigator.gpu 缺失、adapter 为 null、缺少可选 feature、较低 limit、WGSL 编译失败、device lost、Reduced Motion、页面隐藏和反复切页。每种状态都应有可读内容、明确 cleanup、无控制台未捕获错误。

结论

WebGPU 的正确入口不是一条 feature flag,而是一段可失败的协商协议。按 secure context、API、adapter、features/limits、device 和 pipeline 逐层收窄;把运行时错误与 device lost 纳入状态机;让 WebGL、Canvas 或 DOM 消费同一份语义输入。这样浏览器支持扩大时可以自然升级,支持缺口出现时页面也不会把实验性能力变成用户故障。

Sources