Visual LabINTERACTIVE LEARNING
阶段 4 · 计算基础18 分钟

GPU 读回:Copy、Map 与行对齐

MAP_READ、copyTextureToBuffer 与异步同步点

把离屏纹理复制到可映射缓冲区,处理 bytesPerRow 对齐,再从 CPU 读取像素。

LEARNING GOALS

先明确本课目标

1

创建 readback buffer

2

理解 256 字节 bytesPerRow 对齐

3

正确 map/unmap

MENTAL MODEL · 再建立心智模型

GPU 资源通常不可直接被 JavaScript 读取;先复制到 MAP_READ staging buffer,等待完成后 mapAsync。

MINIMAL EXAMPLE

为什么 GPU Buffer 不能像普通数组一样直接读取?

GPU 资源位于 GPU 可访问的内存域。要让 CPU 读取,通常先复制到带 MAP_READ | COPY_DST 的 staging buffer,再异步 mapAsync 等待 GPU 完成。

最小例子javascript
encoder.copyBufferToBuffer(
  gpuResult, 0,
  readbackBuffer, 0,
  byteLength,
);
device.queue.submit([encoder.finish()]);

await readbackBuffer.mapAsync(GPUMapMode.READ);
const copy = readbackBuffer.getMappedRange().slice(0);
readbackBuffer.unmap();
  1. 先复制 计算结果 Buffer 通常没有 MAP_READ usage,需复制到 staging buffer。
  2. mapAsync 是同步点 Promise 解析前 CPU 不能读取;频繁等待会破坏并行流水线。
  3. unmap 映射期间 Buffer 不能同时被 GPU 使用,读完应及时解除映射。

CPU 获得一份稳定字节副本,但付出了 GPU→CPU 同步与传输成本。

本课概念
OPTIONAL · 按需查阅完整术语表与概念边界

遇到陌生术语时再展开,不打断主线实验。

展开⌄
LIVE EXPERIMENT · 先获得反馈

边改边运行

浏览器加载后会激活代码编辑器、独立运行环境与实时输出。

本课挑战

实现三缓冲异步截图队列。

DEEP DIVE · 实验之后

回到原理,解释刚才发生了什么

先用结果建立反馈,再按运行流程、核心原理和知识关系逐层深入。

CORE IDEA

核心讲解

01

读回是同步边界

mapAsync 必须等 GPU 完成相关写入,可能阻塞流水线。实时程序应减少频率、缩小区域或使用多缓冲隐藏延迟。

02

行对齐

纹理到缓冲区复制的 bytesPerRow 通常要求 256 字节倍数,即使实际每行像素数据远小于此。

OPTIONAL · 迁移时查阅WebGPU 与 WebGL2 对照

主线实验完成后,再用完整映射处理跨平台或跨 API 迁移。

展开⌄
API COMPARISON

两者都应避免同步回读;WebGPU 把复制、等待与映射拆成显式阶段。

WebGL

readPixels/getBufferSubData 可能阻塞;可配合 PIXEL_PACK_BUFFER 与 fenceSync 降低立即等待。

WebGPU

先 copy 到 MAP_READ Buffer,提交后 mapAsync,在映射完成时读取 CPU 字节。

异步 API 不会自动消除同步成本;仍应做环形 staging buffer,并晚几帧消费结果。