在Vulkan中,当我想将GPU的一些内存转移回CPU时,我认为最有效的方法是将数据写入具有标志VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT
的内存中。
问题1:这个假设正确吗?
(可用存储器属性标志的完整列表可在Vulkan的VkMemoryPropertyFlagBits文档中找到)
为了获取最新数据,我必须使用vkInvalidateMappedMemoryRanges来使内存无效,对吗?
问题2:vkInvalidateMappedMemoryRanges
的幕后发生了什么?这仅仅是来自内部缓存的memcpy
还是一个更长的过程?
问题3:如果这可能需要更长的时间(即这不是简单的memcpy
),那么我大概应该有可能与它的完成同步,对吗?但是,vkInvalidateMappedMemoryRanges
不提供任何同步参数。实际上,我的问题是:如果必须同步它,如何同步它?
答案 0 :(得分:3)
问题1:这个假设正确吗?
可能不是,但是是否支持替代方案取决于您的平台。对于GPU-> CPU传输,实际上有三个选项:
此类型对主机可见,并保证是一致的,但不缓存在主机上。 CPU读取会非常缓慢,但是如果您只回读少量数据(可能比发出vkInvalidateMappedMemoryRanges()
便宜,并且几乎没有数据流向),这可能没问题。如果您再也不想在CPU上再次触摸它了。
此类型对主机可见并已缓存,但不能保证是一致的(如果不手动执行一致性,CPU和GPU可能会在同一地址看到不同的内容)。对于这种类型的内存,必须在GPU写入之后和CPU读取之前使用vkInvalidateMappedMemoryRanges()
(或在其他方向使用vkFlushMappedRange()
),以确保一个处理器可以看到另一个处理器写的内容,否则您可能会读取过时的数据
最后,您拥有主机缓存和一致的内存类型,如果要在CPU上进行高带宽读取,则可以兼得两者的优势。但是并不能保证在所有平台上都可用。对于CPU上的批量数据读取,我希望在可用的情况下这是最有效的。
值得注意的是,所有分配都没有“最佳”内存设置。不要将主机缓存或主机一致性内存用于您不希望转移回CPU的事情(内存一致性在功耗或内存性能方面并不是免费的)。
问题2:在vkInvalidateMappedMemoryRanges期间,底层发生了什么?这仅仅是一些内部缓存的记忆,还是一个更长的过程?
在内存不连贯的情况下,它将执行使它们连贯的一切操作。通常,这意味着使CPU高速缓存中的高速缓存行无效(丢弃),这些高速缓存行可能包含过时的数据副本,以确保CPU随后的读取可以看到GPU实际写入的版本。
问题3:如果这可能需要更长的时间(即,这不是简单的memcpy),那么我可能应该有某种可能与它的完成同步,对吧?
不。无效是CPU端的操作,因此完成操作需要花费CPU时间,并且CPU繁忙。通常,您可以通过使用一致性内存来完全避免这样做。