我有一个顶点缓冲区,存储在设备内存和缓冲区中,主机可见,主机连贯.
要写入主机端的顶点缓冲区,我将其映射到memcpy并取消映射设备内存.
为了从中读取,我在记录渲染过程中将顶点缓冲区绑定在命令缓冲区中.这些命令缓冲区在一个循环中提交,该循环获取,提交和呈现以绘制每个帧.
目前我在程序启动时写了一次顶点缓冲区.
然后顶点缓冲区在循环期间保持不变.
我想修改主机端每帧之间的顶点缓冲区.
我不清楚的是将这些主机端写入与设备端读取同步的最佳/正确方法.目前我在飞行中同时允许每个框架都有一个围栏和一对信号量.
对于每个帧:
我等着篱笆.
我重置围栏.
获取信号信号量#1.
队列提交等待信号量#1并发出信号量#2的信号并发出信号.
现在等待信号量#2
在这里放置主机端map/memcpy/unmap的正确位置在哪里?我应该如何正确地与设备读取同步?
如果您想利用异步 GPU 执行,您希望 CPU 避免因 GPU 操作而停顿。所以永远不要在围栏上等待刚刚发布的批次。内存也是如此:您永远不应该希望写入您刚刚提交的 GPU 操作正在读取的内存。
您至少应该对事物进行双重缓冲。如果您每帧都更改顶点数据,则应分配足够的内存来保存该数据的两个副本。无需进行多次分配,甚至无需进行多次分配VkBuffer
(只需将分配和缓冲区设置得更大,然后在绑定时选择要使用的存储区域)。当 GPU 命令读取一个存储区域时,您写入另一个区域。
您提交的每个批次都从特定内存中读取。因此,当 GPU 完成从该内存读取时,将设置该批次的栅栏。因此,如果您想从 CPU 写入内存,则在代表该内存读取的 GPU 读取操作的栅栏设置之前,您无法开始该过程。
但是因为您像这样进行双缓冲,所以您将要写入的内存的栅栏不是您上一帧提交的批处理的栅栏。这是您在此之前提交框架的批次。由于 GPU 收到该操作已经有一段时间了,因此 CPU 实际等待的可能性要小得多。也就是说,围栏应该已经设置好了。
现在,你不应该vkWaitForFences
在那个围栏上做文字。您应该检查它是否已设置,如果没有,请花时间做其他有用的事情。但是,如果您没有其他有用的事情可以做,那么等待可能是可以的(而不是坐下来进行测试)。
一旦设置了栅栏,您就知道可以自由地写入内存。
我怎么知道我用 memcpy 写入的内存在被渲染通道读取之前已完成发送到设备?
你知道,因为记忆是连贯的。这就是在这种情况下的VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
含义:主机对设备内存的更改对 GPU 可见,无需显式可见性操作,反之亦然。
嗯……差不多。
如果要避免使用任何同步,则必须在修改完 CPU 上的内存后调用vkQueueSubmit
读取批处理。如果它们以错误的顺序被调用,那么您将需要一个内存屏障。例如,您可以让批处理的某些部分等待主机设置的事件(通过),它会在您完成写入时通知 GPU。因此,您可以在执行内存写入之前提交该批次。但在这种情况下,调用应该包括一个源阶段掩码(因为谁在设置事件),并且它应该有一个内存屏障,其源访问标志也包括(因为谁在写入内存)。vkSetEvent
vkCmdWaitEvents
HOST
HOST_WRITE
但在大多数情况下,在提交批处理之前只写入内存更容易。这样,您就无需使用主机/事件同步。
归档时间: |
|
查看次数: |
204 次 |
最近记录: |