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