WebGPU 入门如何把计算结果回传页面:GPUBuffer、mapAsync 与设备丢失处理
页面里的 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 没返回结果”。
Linux inotifywait 如何只捕获目录新增文件:事件过滤、递归范围与重复通知
- 上一篇
- Linux inotifywait 如何只捕获目录新增文件:事件过滤、递归范围与重复通知
- 下一篇
- IntersectionObserver 如何避免列表滚动监听抖动:rootMargin、阈值与卸载
-
- 文章 · 前端 | 11小时前 | 前端 · Web Components LiT 响应式更新 前端组件 updateComplete
- Lit updateComplete怎样等待组件更新结束
- 425浏览 收藏
-
- 文章 · 前端 | 14小时前 | D3 scaleBand scalePoint d3-scale
- D3 scaleBand与scalePoint适用场景有什么区别
- 271浏览 收藏
-
- 文章 · 前端 | 15小时前 | 响应式 副作用 SolidJS createMemo createEffect
- SolidJS createMemo为什么不适合执行副作用
- 308浏览 收藏
-
- 文章 · 前端 | 15小时前 |
- SolidJS store嵌套字段怎样局部更新
- 130浏览 收藏
-
- 文章 · 前端 | 15小时前 |
- XState父状态机怎样向子actor发送事件
- 191浏览 收藏
-
- 文章 · 前端 | 15小时前 |
- Alpine.js $nextTick怎样等待DOM更新
- 367浏览 收藏
-
- 文章 · 前端 | 15小时前 |
- htmx局部替换时怎样保留指定元素状态
- 241浏览 收藏
-
- 文章 · 前端 | 15小时前 |
- htmx hx-sync怎样避免表单与字段请求竞争
- 390浏览 收藏
-
- 文章 · 前端 | 15小时前 | Property Web Components LiT Attribute 响应式属性
- Lit响应式属性怎样设置attribute与property的映射
- 429浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 467次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 530次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 549次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 498次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 317次使用
-
- Go语言对前端领域的入侵WebAssembly运行原理
- 2022-12-31 130浏览
-
- golang 对象深拷贝的常见方式及性能
- 2022-12-28 262浏览
-
- Go标准库http与fasthttp服务端性能对比场景分析
- 2022-12-31 206浏览
-
- golang利用pprof与go-torch如何做性能分析
- 2023-01-01 182浏览
-
- Go语言中三种不同md5计算方式的性能比较
- 2022-12-27 202浏览

