跳转到内容

GPUBuffer

GPUBuffer 是一块 GPU 内存。顶点、索引、uniform、存储数据和间接绘制参数都用它。用 device.createBuffer(descriptor) 创建。

interface GPUBufferDescriptor {
label?: string;
size: GPUSize64; // 字节数,必须是 4 的倍数
usage: GPUBufferUsageFlags;
mappedAtCreation?: boolean;
}
interface GPUBuffer {
readonly size: GPUSize64Out;
readonly usage: GPUFlagsConstant;
readonly mapState: "unmapped" | "pending" | "mapped";
mapAsync(mode: GPUMapModeFlags, offset?: GPUSize64, size?: GPUSize64): Promise<undefined>;
getMappedRange(offset?: GPUSize64, size?: GPUSize64): ArrayBuffer;
unmap(): undefined;
destroy(): undefined;
}

这些标志可以组合。有两条硬限制:MAP_READ 只能再加 COPY_DST,MAP_WRITE 只能再加 COPY_SRC。

标志允许的操作
MAP_READmapAsync(GPUMapMode.READ)
MAP_WRITEmapAsync(GPUMapMode.WRITE)
COPY_SRC作为 copyBufferToBuffer / copyBufferToTexture 的源
COPY_DST作为复制的目标,或 writeBuffer() 的目标
INDEXsetIndexBuffer()
VERTEXsetVertexBuffer()
UNIFORM绑定类型 "uniform"
STORAGE绑定类型 "storage" 或 "read-only-storage"
INDIRECTdrawIndirect()、dispatchWorkgroupsIndirect()
QUERY_RESOLVEresolveQuerySet() 的目标

最常见的上传方式是 queue.writeBuffer(buffer, bufferOffset, data)。bufferOffset 必须是 4 的倍数,缓冲的 usage 必须包含 COPY_DST。

mappedAtCreation: true 会让缓冲一开始就处于映射状态,可以立刻 getMappedRange(),即使 usage 里没有 MAP_READ 或 MAP_WRITE。写完必须 unmap(),否则不能提交使用这块缓冲的命令。

映射状态下的缓冲不能同时被 GPU 使用。mapAsync() 会等到 GPU 用完对应范围。unmap() 或 destroy() 会使 getMappedRange() 返回的 ArrayBuffer 失效。