vulkan - 使用 Vulkan 和 vkInvalidateMappedMemoryRanges 同步将内存从 GPU 传输到 CPU?
问题描述
在 Vulkan 中,当我想将 GPU 的一些内存传输回 CPU 时,我认为最有效的方法是将数据写入具有 flags 的内存中VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT
。
问题1:这个假设正确吗?
(可用内存属性标志的完整列表可以在 Vulkan 的VkMemoryPropertyFlagBits文档中找到)
为了获取最新数据,我必须使用vkInvalidateMappedMemoryRanges使内存无效,对吗?
问题 #2: 期间发生了什么vkInvalidateMappedMemoryRanges
?这只是memcpy
来自一些内部缓存还是可能是一个更长的过程?
问题#3:如果这可能需要更长的时间(即它不是一个简单的memcpy
),那么我可能应该有一些可能与它的完成同步,对吧?但是,vkInvalidateMappedMemoryRanges
不提供任何同步参数。实际上,我的问题是:如果我必须同步它,我该如何同步它?
解决方案
问题1:这个假设正确吗?
可能不是,但这取决于您的平台是否支持替代方案。对于 GPU->CPU 传输,实际上有三个选项:
1. HOST_VISIBLE
这种类型对主机可见并保证是一致的,但不会缓存在主机上。CPU 读取将非常慢,但如果您只读取少量数据,这可能没问题(并且可能比发出便宜vkInvalidateMappedMemoryRanges()
,并且如果您从不希望再次触摸它,则几乎没有将数据流式传输到 CPU 缓存中中央处理器)。
2. HOST_VISIBLE | 主机缓存
这种类型对主机可见并被缓存,但不能保证是一致的(如果你不手动强制一致性,CPU 和 GPU 可能会在同一地址看到不同的东西)。对于这种类型的内存,您必须vkInvalidateMappedMemoryRanges()
在 GPU 写入之后和 CPU 读取之前(或vkFlushMappedRange()
用于其他方向)使用,以确保一个处理器可以看到另一个处理器写入的内容,否则您可能会读取过时的数据。
一旦进入缓存,数据访问将很快,您可以从 CPU 端数据获取技巧(例如显式预加载和缓存预取)中受益,但您将为无效操作支付开销。
3. HOST_VISIBLE | 主机缓存 | HOST_COHERENT
最后,您拥有主机缓存和连贯的内存类型,如果您要在 CPU 上进行高带宽读取,那么这两种类型都可以为您提供最好的选择。硬件自动提供一致性实现,因此无需无效,但不能保证在所有平台上都可用。对于 CPU 上的批量数据读取,我希望这在可用的情况下是最有效的。
值得注意的是,所有分配都没有“最佳”内存设置。不要将主机缓存或主机一致性内存用于您从未期望传输回 CPU 的内容(内存一致性在功率或内存性能方面并不是免费的)。
问题 #2:在 vkInvalidateMappedMemoryRanges 期间发生了什么?这只是来自某些内部缓存的 memcpy 还是可能是一个更长的过程?
如果您有不连贯的记忆,那么它会尽一切努力使它们连贯。通常,这意味着使 CPU 缓存中可能包含数据的陈旧副本的缓存行无效(丢弃),以确保 CPU 的后续读取看到 GPU 实际写入的版本。
问题#3:如果这可能需要更长的时间(即它不是一个简单的memcpy),那么我可能应该有一些可能与它的完成同步,对吧?
不可以。失效是 CPU 端的操作,因此需要 CPU 时间才能完成,并且在操作完成时 CPU 很忙。通常,您可以通过使用连贯内存来完全避免这样做。
推荐阅读
- oracle - PLSQL:当数据不是来自该类型时,FORALL 插入
- delphi - 上传后 TIdFTP 文件损坏
- xpages - Openntf Domino API v10“已完成公式”添加到日志
- sharpdevelop - 如何更改默认的 SharpDevelop 库?
- python - 将 postgres 转储文件导入 hdfs 或 hive 表?
- java - 英特尔 HD 3700 linux 的 Java 8 Swing 渲染问题
- xsd - 跳过 BizTalk 平面文件程序集中的元素?
- php - Laravel,只能在控制器内闪烁错误消息吗?
- node.js - Reactjs - 登录后移至下一页
- gitkraken - Gitkraken - 当重新定位错误“无法将没有 HEAD 的子模块添加到索引”时