WebGPU 入门如何把计算结果回传页面:GPUBuffer、mapAsync 与设备丢失处理
来源:17golang原创
时间:2026-08-30 02:45:50 381浏览 收藏
页面里的 WebGPU 计算已经提交,JavaScript 却拿不到结果,问题通常不在 WGSL 公式,而在“GPU 可写的缓冲区”和“JavaScript 可读的缓冲区”没有分开。可靠的回传路径是:计算写入 output,命令编码器把它复制到 stagingBuffer,再等待 mapAsync 完成,读取 getMappedRange,最后 unmap。
把 GPU 结果交给页面,关键不是直接读取 output,而是用
GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST创建 stagingBuffer,并严格遵守映射、读取、解除映射的顺序。
要点速览
output负责接收计算结果,stagingBuffer负责被 JavaScript 读取。copyBufferToBuffer完成 GPU 内部搬运,mapAsync完成异步可读准备。- 设备丢失后,旧设备创建的 buffer、pipeline 等资源都要跟着重建。
先分清 output 和 stagingBuffer 的职责
WebGPU 的 buffer 使用权限是在 device.createBuffer 时声明的。计算输出通常需要 STORAGE | COPY_SRC,因为计算着色器要写入它,之后还要作为复制源;给 JavaScript 读取的 stagingBuffer 则使用 MAP_READ | COPY_DST。MAP_READ 不能和任意用途混搭,先把职责分开,后面的命令才不会在验证阶段失败。
const output = device.createBuffer({
size: BUFFER_SIZE,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
});
const stagingBuffer = device.createBuffer({
size: BUFFER_SIZE,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
});
这里的 output 不是 JavaScript 变量的普通数组,它是 GPU 设备管理的存储;stagingBuffer 也不是“自动同步的镜像”。两者之间必须明确编码一次复制命令。

copyBufferToBuffer 之后再请求 mapAsync
计算 pass 结束后,用 GPUCommandEncoder.copyBufferToBuffer 把 output 的结果复制到 stagingBuffer,再通过 device.queue.submit 提交命令。提交后才能对 stagingBuffer 调用 mapAsync;映射完成前,getMappedRange 不能使用。
const commandEncoder = device.createCommandEncoder();
commandEncoder.copyBufferToBuffer(
output,
0,
stagingBuffer,
0,
BUFFER_SIZE,
);
device.queue.submit([commandEncoder.finish()]);
await stagingBuffer.mapAsync(
GPUMapMode.READ,
0,
BUFFER_SIZE,
);
const mapped = stagingBuffer.getMappedRange(0, BUFFER_SIZE);
const data = mapped.slice(0);
stagingBuffer.unmap();
console.log(new Float32Array(data));
mapAsync 返回的 Promise 兑现,只说明这个范围已经可以被访问;读取完成后要先复制出自己的 ArrayBuffer,再调用 unmap。缓冲区保持 mapped 状态时,不能继续作为 GPU 命令的目标。

改动的重点是映射边界,不是把等待写得更长
如果映射范围从偏移量开始,offset 必须满足 API 的对齐要求,size 也必须落在 buffer 范围内。最稳妥的入门代码是从 0 映射完整的 BUFFER_SIZE,并让它保持 4 字节对齐;等数据结构稳定后,再为多个结果分段设计偏移量。
不要用一个同时承担 STORAGE、MAP_READ 等互相冲突职责的 buffer 代替两个 buffer,也不要在 mapAsync 尚未兑现时读取 mapped range。遇到 OperationError,优先检查 usage、offset、size 和当前 mapState,不要盲目增加延迟。
设备丢失后要重建整套 GPU 资源
GPUDevice.lost 是一个在设备生命周期内保持 pending、设备丢失时才兑现的 Promise。浏览器资源管理或驱动更新都可能触发设备丢失;如果原因不是主动调用 GPUDevice.destroy,应用可以重新申请 device,但旧 device 创建的 buffer、pipeline 和 bind group 不能继续复用。
device.lost.then((info) => {
console.error(`WebGPU device was lost: ${info.message}`);
if (info.reason !== "destroyed") {
init();
}
});
恢复函数应重新执行适配器申请、设备创建、buffer 创建和 pipeline 初始化。页面层只保留“正在恢复”的状态,避免用户连续点击时把旧设备上的命令再次提交。
常见问题
为什么不能直接对 output 调用 mapAsync?
output 通常使用 STORAGE | COPY_SRC,并没有 MAP_READ 权限。把结果复制到使用 MAP_READ | COPY_DST 创建的 stagingBuffer,才是常见的 GPU 到 JavaScript 回传路径。
mapAsync 完成后还要调用 unmap 吗?
要。读取 mapped range 并复制出数据后调用 unmap,缓冲区才重新对 GPU 命令可用;不要把 mapped 状态当成永久读取模式。
设备丢失后只重新 requestDevice 可以吗?
不够。旧设备拥有的 buffer、pipeline、bind group 等资源都需要重建,恢复流程应回到初始化阶段,并暂时阻止旧任务继续提交。
最小验收:看得到结果,也能处理失效设备
一个可交付的 WebGPU 回传实现,至少应能在控制台看到从 output 复制来的数值,确认 mapAsync 只在提交复制命令后调用,并在读取后执行 unmap。再人为触发设备失效或模拟恢复路径,确认 GPUDevice.lost 会重新创建整套资源。这样排查时,问题会落在清晰的 buffer 权限、命令顺序或设备生命周期上,而不是一段无法定位的“GPU 没返回结果”。
-
130 收藏
-
262 收藏
-
206 收藏
-
182 收藏
-
202 收藏
-
474 收藏
-
398 收藏
-
196 收藏
-
207 收藏
-
文章 · 前端 | 3小时前 | 前端 · 路由 · javascript · 兼容性 · 浏览器 API · 嵌套路由 JavaScript URLPattern URLPattern groups URLPattern test 浏览器 API445 收藏
-
213 收藏
-
106 收藏
-
160 收藏
-
文章 · 前端 | 13小时前 | html · 前端 · javascript · 弹窗 · 浏览器API · dialog close cancel HTMLDialogElement requestClose163 收藏
-
111 收藏
-
290 收藏
-
文章 · 前端 | 16小时前 | 前端 · 性能 · 浏览器 · css · 长列表 · 前端性能 content-visibility contain-intrinsic-size 大列表 滚动抖动366 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习