WebGL2 与 WebGPU 的差异
luma.gl 9 把两个后端收在同一套接口下,但差异不会消失,只会被推迟到运行期。 适配器、着色器语言、管线的可变性、附件格式与计算能力,是五处必须显式处理的地方。
切换后端只需换适配器
WebGL 用 @luma.gl/webgl 的 webgl2Adapter,
WebGPU 用 @luma.gl/webgpu 的 webgpuAdapter。
type: 'best-available' 会先试 WebGPU,失败再退回 WebGL2。
import { luma } from '@luma.gl/core';
import { webgl2Adapter } from '@luma.gl/webgl';
import { webgpuAdapter } from '@luma.gl/webgpu';
const device = await luma.createDevice({
type: 'best-available',
adapters: [webgpuAdapter, webgl2Adapter],
createCanvasContext: {
canvas: document.getElementById('cv'),
useDevicePixels: Math.min(window.devicePixelRatio, 2),
autoResize: true
}
});
console.log(device.type); // 'webgpu' 或 'webgl'
console.log(device.info.gpu); // WebGPU 下的适配器信息
UMD 版本同样可用,只是需要多加载一个 @luma.gl/webgpu 的包,
适配器从全局对象 luma.webgpuAdapter 取。
type 写成 'webgpu' 时不会再回退,浏览器不支持就直接失败。
着色器语言不同
WebGL2 只接受 GLSL ES 3.00,第一行必须是 #version 300 es,
片元输出要显式声明 out vec4。WebGPU 只接受 WGSL,
通过 source 传入,顶点与片元入口由
vertexEntryPoint 与 fragmentEntryPoint 指定。
if (device.type === 'webgl') {
pipeline = device.createRenderPipeline({
vs: glslVS,
fs: glslFS,
topology: 'triangle-list',
bufferLayout: [{ name: 'positions', stepMode: 'vertex', format: 'float32x3' }]
});
} else {
pipeline = device.createRenderPipeline({
source: wgslSource,
vertexEntryPoint: 'vsMain',
fragmentEntryPoint: 'fsMain',
topology: 'triangle-list',
bufferLayout: [{ name: 'positions', stepMode: 'vertex', format: 'float32x3' }],
colorAttachmentFormats: ['rgba8unorm'],
depthStencilAttachmentFormat: device.preferredDepthFormat
});
}
想在两个后端共用一份着色器,用 shadertools 的模块机制写 GLSL 与 WGSL 两套片段, 由组装器按后端选择,而不是在业务代码里散落分支。
管线不可变与附件格式
| 项目 | WebGL 2 | WebGPU |
|---|---|---|
| 管线状态 | 可在绘制前修改 | 创建时固定,改动必须新建 |
| 颜色附件格式 | 可省略 | colorAttachmentFormats 必填 |
| 深度附件格式 | 可省略 | depthStencilAttachmentFormat 写入深度时必填 |
| 纹理用途 | 约束宽松 | 创建时声明,缺一项即不可用 |
| 缓冲用途 | 约束宽松 | 必须写全 VERTEX | COPY_DST |
| 间接绘制 | 抛错 | drawIndirect 可用 |
| 计算着色器 | 没有 | 支持 compute 阶段 |
| 多画布 | 只支持一个 | 支持多个 |
这张表的每一行都会在迁移时变成 bug。WebGL 上能跑的代码, 在 WebGPU 上最常卡在附件格式与用途声明上,而不是着色器语法。
能力查询
差异不该靠猜,设备上有 features 与 limits 两组查询。
用它们决定是否启用某条路径,比按 device.type 分支更可靠。
if (device.isTextureFormatSupported('rgba32float')) {
// 可以做浮点精度的离屏计算
}
if (device.features.has('float32-renderable-webgl')) {
// WebGL 下浮点纹理可作为渲染目标
}
console.log(device.limits);
console.log(device.info.version, device.info.shadingLanguage);
注意事项
best-available 导致行为不一致
同一份代码在两种设备上走不同后端,画面细节、精度与性能都不同。
线上出现「这台机器上没问题」的报告时,先打印 device.type
与 device.info.renderer,不要从代码逻辑开始查。
上下文丢失
两个后端都会丢失上下文:切换显卡、系统休眠、驱动重置都会触发。
device.lost 兑现后,所有资源失效,必须重建设备并重新上传,
不能只重画一帧。
计算着色器不可移植
stage: 'compute' 只在 WebGPU 可用。需要双后端支持时,
把计算改写成片元着色器加离屏目标,用渲染管线完成同样的逐像素运算。
经纬志(2026)。《WebGL2 与 WebGPU 的差异》。https://www.jingweizhi.com/lumagl/tutorial/webgpu-vs-webgl.html(访问日期 2026-11-03)。