WebGPU 中的缓冲映射机制
1. 什么是缓冲映射
就不给定义了,直接简单的说,映射(Mapping)后的某块显存,就能被 CPU 访问。
三大图形 API(D3D12、Vulkan、Metal)的 Buffer(指显存)映射后,CPU 就能访问它了,此时注意,GPU 仍然可以访问这块显存。这就会导致一个问题:IO冲突,这就需要程序考量这个问题了。
WebGPU 禁止了这个行为,改用传递“所有权”来表示映射后的状态,颇具 Rust 的哲学。每一个时刻,CPU 和 GPU 是单边访问显存的,也就避免了竞争和冲突。
当 JavaScript 请求映射显存时,所有权并不是马上就能移交给 CPU 的,GPU 这个时候可能手头上还有别的处理显存的操作。所以,GPUBuffer 的映射方法是一个异步方法:
const someBuffer = device.createBuffer({ /* ... */ })
await someBuffer.mapAsync(GPUMapMode.READ, 0, 4) // 从 0 开始,只映射 4 个字节
// 之后就可以使用 getMappedRange 方法获取其对应的 ArrayBuffer 进行缓冲操作
不过,解映射操作倒是一个同步操作,CPU 用完后就可以解映射:
somebuffer.unmap()
注意,mapAsync 方法将会直接在 WebGPU 内部往设备的默认队列中压入一个操作,此方法作用于 WebGPU 中三大时间轴中的 队列时间轴。而且在 mapAsync 成功后,内存才会增加(实测)。
当向队列提交指令缓冲后(此指令缓冲的某个渲染通道要用到这块 GPUBuffer),内存上的数据才会提交给 GPU(猜测)。
由于测试地不多,我在调用 destroy 方法后并未显著看到内存的变少,希望有朋友能测试。
创建时映射
可以在创建缓冲时传递 mappedAtCreation: true,这样甚至都不需要声明其 usage 带有 GPUBufferUsage.MAP_WRITE
const buffer = device.createBuffer({
usage: GPUBufferUsage.UNIFORM,
size: 256,
mappedAtCreation: true,
})
// 然后马上就可以获取映射后的 ArrayBuffer
const mappedArrayBuffer = buffer.getMappedRange()
/* 在这里执行一些写入操作 */
// 解映射,还管理权给 GPU
buffer.unmap()
2 缓冲数据的流向
2.1 CPU 至 GPU
JavaScript 这端会在 rAF 中频繁地将大量数据传递给 GPUBuffer 映射出来的 ArrayBuffer,然后随着解映射、提交指令缓冲到队列,最后传递给 GPU.
上述最常见的例子莫过于传递每一帧所需的 VertexBuffer、UniformBuffer 以及计算通道所需的 StorageBuffer 等。
使用队列对象的 writeBuffer 方法写入缓冲对象是非常高效率的,但是与用来写入的映射后的一个 GPUBuffer 相比,writeBuffer 有一个额外的拷贝操作。推测会影响性能,虽然官方推荐的例子中有很多 writeBuffer 的操作,大多数是用于 UniformBuffer 的更新。
2.2 GPU 至 CPU
这样反向的传递比较少,但也不是没有。譬如屏幕截图(保存颜色附件到 ArrayBuffer)、计算通道的结果统计等,就需要从 GPU 的计算结果中获取数据。
譬如,官方给的从渲染的纹理中获取像素数据例子:
const texture = getTheRenderedTexture()
const readbackBuffer = device.createBuffer({
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
size: 4 * textureWidth * textureHeight,
})
// 使用指令编码器将纹理拷贝到 GPUBuffer
const encoder = device.createCommandEncoder()
encoder.copyTextureToBuffer(
{ texture },
{ buffer, rowPitch: textureWidth * 4 },
[textureWidth, textureHeight],
)
device.submit([encoder.finish()])
// 映射,令 CPU 端的内存可以访问到数据
await buffer.mapAsync(GPUMapMode.READ)
// 保存屏幕截图
saveScreenshot(buffer.getMappedRange())
// 解映射
buffer.unmap()
WebGPU 中的缓冲映射机制的更多相关文章
- KVm中EPT逆向映射机制分析
2017-05-30 前几天简要分析了linux remap机制,虽然还有些许瑕疵,但总算大致分析的比较清楚.今天分析下EPT下的逆向映射机制.EPT具体的工作流程可参考前面博文,本文对于EPT以及其 ...
- Hibernate的映射机制是怎样?
Hibernate的映射机制对象关系映射(Object Relation Mapping(ORM))是一种为了解决面向对象与面向关系数据库互不匹配现象的技术,简而言之ORM是通过使用描述对象之间映射的 ...
- WebGPU 中消失的 FBO 和 RBO
目录 1 WebGL 中的 FBO 与 RBO 1.1 帧缓冲对象(FramebufferObject) 1.2 颜色附件与深度模板附件的真正载体 1.3 FBO/RBO/WebGLTexture 相 ...
- MFC消息映射机制以及画线功能实现
---此仅供用于学习交流,切勿用于商业用途,转载请注明http://www.cnblogs.com/mxbs/p/6213404.html. 利用VS2010创建一个单文档标准MFC工程,工程名为Dr ...
- Linux 内核中的 Device Mapper 机制
本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...
- Android IOS WebRTC 音视频开发总结(七五)-- WebRTC视频通信中的错误恢复机制
本文主要介绍WebRTC视频通信中的错误恢复机制(我们翻译和整理的,译者:jiangpeng),最早发表在[这里] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:blac ...
- 详解Java的MyBatis框架中SQL语句映射部分的编写
这篇文章主要介绍了Java的MyBatis框架中SQL语句映射部分的编写,文中分为resultMap和增删查改实现两个部分来讲解,需要的朋友可以参考下 1.resultMap SQL 映射XML 文件 ...
- MFC编程入门之五(MFC消息映射机制概述)
在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息,通过对消息的处理实现相应的操作.比较典型的过程是,用户操作窗口,然后有消息产生,送给窗口的消息处理函数处理,对用户的操作做出响应. 一.什 ...
- windows的页自映射机制
windows下由于启用了页机制,所有软件层面的地址操作都是VA,通过descriptor(base address(32bit))+offset得到的线性地址并不直接对应物理地址,而是经过页转换机构 ...
随机推荐
- MD5,SHA1及SHA256等哈希加密方法实现:Java,C#,Golang,Python
哈希算法又称散列算法,它可以从任何数据中快速的创建一个凭证,而这个凭证很难被推倒出来,因为一丁点的变化会导致凭证的差别恨到,也就是说哈希算法具有不可逆性,因此它在密码数据校验方面用的很广,比如我们常用 ...
- Linux登录时,下游回显非常慢
问题现象 登录linux时,远程连接正常,[root@...]回显非常慢,在执行脚本时,很容易导致命令下发错乱 原因分析 家目录下的.bash_history文件太大,导致每次登陆时读取这个文件耗时太 ...
- 初识python 之 爬虫:爬取双色球中奖号码信息
人生还是要有梦想的,毕竟还有python.比如,通过python来搞一搞彩票(双色球).注:此文仅用于python学习,结果仅作参考.用到知识点:1.爬取网页基础数据2.将数据写入excel文件3.将 ...
- LINUX学习--nginx服务器的安装
一.安装环境 操作系统CentOS6.8 关闭SeLinux和iptables防火墙 二.网络yum源 将下面的软件下载到 /etc/yum.repos.d/ 的目录下 官方基础:http:// ...
- Go 分布式令牌桶限流 + 兜底策略
上篇文章提到固定时间窗口限流无法处理突然请求洪峰情况,本文讲述的令牌桶线路算法则可以比较好的处理此场景. 工作原理 单位时间按照一定速率匀速的生产 token 放入桶内,直到达到桶容量上限. 处理请求 ...
- 【Java】枚举类
文章目录 枚举类的使用 如何定义枚举类 方式一:jdk5.0之前,自定义枚举类 方式二:jdk5.0,可以使用enum关键字定义枚举类 Enum类的主要方法 toString() values() v ...
- day 9 scanf输入和gets输入的区别
(1).计算机高级语言程序运行方法有编译执行和编译解释两种,一下叙述中正确的是[A] A.C语言程序仅可以编译执行 B.C语言程序仅可以解释执行 C.C语言程序既可以编译执行又可以解释执行 D.以上说 ...
- K8s中的volumes-容器数据存放类型及位置
学习对象:kubectl explain pod.spec.volumes.pod.spec.containers.image.volumeMounts 介绍Volumes 容器内部也有自己的空间,但 ...
- Javascript面向对象——创建对象、构造函数的原型
Javascript面向对象--创建对象.构造函数的原型 其实:JavaScript中的创建类,就是创建一个构造函数,在创建对象时用到new这个关键字, 一.创建对象 1.函数创建对象 functio ...
- winfrom 双缓冲
在窗体load函数中 this.DoubleBuffered = true; //控件,需要反射的方式设置 Type dgvType = this.dgv.GetType(); PropertyInf ...