WebGL-vs-WebGPU-vs-Canvas2D
1. 问题先分类,再选表面
| 你真正要的 | 优先 | 不要先上 |
|---|---|---|
| 可命中、可读屏、可复制文本的图形 UI | DOM / SVG | 任何 canvas |
| 笔刷、混合模式烘焙、少量像素滤镜 | Canvas 2D | 为一条水印开着色器 |
| 万级实例、点精灵、每像素公式、三维网格 | WebGL2 | 2D 里 fillRect 硬撑 |
| 计算着色、更干净的资源生命周期 | WebGPU(探测到 adapter) | 假装 2026 年可以删 WebGL |
Canvas 2D 适用,当 帧的真相是像素。SVG 适用,当 帧的真相是文档节点。WebGL / WebGPU 适用,当 帧的真相是 GPU 程序。
混用两张 canvas 是生产常态:GL 画密度,2D / DOM 画轴、tooltip、表单。getContext 在同一元素上互斥,见 上下文生命周期。
2. Canvas 2D:够用就别上 GPU
适用
- 百~千级 path,每对象很「像素」
- 导出模型简单:读 backing store
- 和视频帧、
ImageBitmap、Worker 同一套位图
死线(碰到就该换或叠一层)
- 实例过万还要每帧独立变换:2D 同步光栅打不过
- 每像素 LUT / 扭曲 / 多 pass 辉光:需要 fragment
- 要深度、网格、PBR:不是 2D 的活
3. WebGL2:生产默认光栅器
生产创建只认 webgl2。它解决的是 draw call + buffer + 纹理 在现有浏览器上的最大公约数。
适用: 散点、粒子、后处理、瓦片、视频纹理、简单三维查看。移动端与企业 WebView 的基线仍在这里。
不适用:
- 把它当 DOM。文本、表单、读屏叠 SVG / HTML,见 与 2D 叠层
- 需要可移植 compute。WebGL2 能 ping-pong FBO 冒充,但不是计算 API
requestAdapter()已成功且产品就是计算管线:直接 WebGPU,GL 当降级
4. WebGPU:探测之后用,不是许可证
WebGPU 更接近现代 GPU:显式 pass、buffer 生命周期、compute。navigator.gpu.requestAdapter() 为 null 是产品路径。
适用: 直方图、卷积、粒子积分、需要 compute 的图像处理;团队已能承受降级面。
不适用: 「先写 WebGPU 再考虑 GL」。Safari / Firefox / Android 覆盖面仍要当二等公民,见 07。安全上下文是硬条件。
5. 一个可执行的判定流程
type Surface = "css" | "svg" | "canvas2d" | "webgl2" | "webgpu";
export function chooseSurface(input: {
truth: "document" | "pixels" | "gpu-program";
interactiveText: boolean;
pixelBrush: boolean;
needsCompute: boolean;
instanceCount: number;
adapterOk: boolean;
}): Surface {
if (input.interactiveText || input.truth === "document") {
return "svg";
}
if (input.pixelBrush || input.truth === "pixels") {
return "canvas2d";
}
if (input.truth !== "gpu-program" && input.instanceCount < 8_000) {
return "canvas2d";
}
if (input.needsCompute && input.adapterOk) {
return "webgpu";
}
return "webgl2";
}
instanceCount 是每帧要独立更新的图元数,不是场景里存在的总节点。静态一万个 SVG path 仍可能比每帧重绘一千个 GPU 实例更合适——测过再翻案。adapterOk 必须是运行时探测,不要写死浏览器名单。
两张 canvas 叠层时,判定函数可以返回两次:场景 webgl2,chrome canvas2d 或 DOM。不要为了「只用一个元素」把 UI 画进 shader。
6. 失败形态
| 症状 | 选错了什么 |
|---|---|
| 编辑器做不出选择 / 读屏 | 用 GL 替代了文档 |
| 粒子 2D 分桶后仍 20fps | 该 GPU 还在 2D |
同一元素 getContext 返回 null | 违反单例,该两张叠 |
| 上了 WebGPU 白屏 | requestAdapter() 为 null 没有 GL 降级 |
| 只要一个 blur 却开了后处理栈 | 该 2D filter 或预烘焙 |
权威资料
核对日期:2026-08-26