在vulkan中同步顶点缓冲区?

问题描述 投票:5回答:1

我有一个顶点缓冲区,存储在设备内存和缓冲区中,主机可见,主机连贯。

要写入主机端的顶点缓冲区,我将其映射到memcpy并取消映射设备内存。

为了从中读取,我在记录渲染过程中将顶点缓冲区绑定在命令缓冲区中。这些命令缓冲区在一个循环中提交,该循环获取,提交和呈现以绘制每个帧。

目前我在程序启动时写了一次顶点缓冲区。

然后顶点缓冲区在循环期间保持不变。

我想修改主机端每帧之间的顶点缓冲区。

我不清楚的是将这些主机端写入与设备端读取同步的最佳/正确方法。目前我在飞行中同时允许每个框架都有一个围栏和一对信号量。

对于每个帧:

  1. 我等着篱笆。
  2. 我重置围栏。
  3. 获取信号信号量#1。
  4. 队列提交等待信号量#1并发出信号量#2的信号并发出信号。
  5. 现在等待信号量#2

在这里放置主机端map / memcpy / unmap的正确位置在哪里?我应该如何正确地与设备读取同步?

vulkan
1个回答
4
投票

如果您想利用异步GPU执行,您希望CPU避免因GPU操作而失速。因此,永远不要在栅栏上等待刚发布的批次。内存也是如此:你永远不应该想要写入你刚刚提交的GPU操作读取的内存。

你应该至少加倍缓冲。如果要每帧更改顶点数据,则应分配足够的内存来保存该数据的两个副本。不需要进行多次分配,甚至不需要制作多个VkBuffers(只需使分配和缓冲区更大,然后选择在绑定时使用哪个存储区域)。虽然GPU命令正在读取一个存储区域,但您可以写入另一个区域。

您提交的每个批次都从某个内存中读取。因此,当GPU完成从该存储器读取时,将设置该批次的栅栏。因此,如果要从CPU写入内存,则在表示该内存读取的GPU读取操作的栅栏设置之前,您无法开始该过程。

但是因为你是这样的双缓冲,你要写入的内存的栅栏不是你最后一帧提交的批次的栅栏。这是你之前提交框架的批次。由于GPU接收到该操作已有一段时间,因此CPU不太可能实际等待。也就是说,希望已经设置了围栏。

现在,你不应该在那个栅栏上做一个字面上的vkWaitForFences。您应该检查它是否已设置,如果不是,请对您的时间做一些有用的事情。但是,如果你没有其他任何有用的东西,那么等待可能就行了(而不是坐在测试上旋转)。

一旦设置了围栏,您就知道可以自由地写入内存。


我如何知道我用memcpy写入的内存在渲染通道读取之前已经完成发送到设备?

你知道,因为记忆是连贯的。这就是VK_MEMORY_PROPERTY_HOST_COHERENT_BIT在这种情况下的意思:GPU可以看到主机对设备内存的更改,而无需显式可见性操作,反之亦然。

嗯......差不多。

如果要避免必须使用任何同步,则必须在完成修改CPU上的内存后调用vkQueueSubmit作为读取批处理。如果他们以错误的顺序被调用,那么你将需要一个内存屏障。例如,您可以让批处理的某些部分等待主机设置的事件(通过vkSetEvent),该事件在您完成写入时告诉GPU。因此,您可以在执行内存写入之前提交该批次。但在这种情况下,vkCmdWaitEvents调用应该包括HOST的源阶段掩码(因为那是谁设置事件),它应该有一个内存屏障,其源访问标志还包括HOST_WRITE(因为那是谁写入内存)。

但在大多数情况下,在提交批处理之前更容易写入内存。这样,您就可以避免使用主机/事件同步。

© www.soinside.com 2019 - 2024. All rights reserved.