在vulkan中同步顶点缓冲区?

And*_*zos 5 vulkan

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

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

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

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

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

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

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

对于每个帧:

  1. 我等着篱笆.

  2. 我重置围栏.

  3. 获取信号信号量#1.

  4. 队列提交等待信号量#1并发出信号量#2的信号并发出信号.

  5. 现在等待信号量#2

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

Nic*_*las 9

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

您至少应该对事物进行双重缓冲。如果您每帧都更改顶点数据,则应分配足够的内存来保存该数据的两个副本。无需进行多次分配,甚至无需进行多次分配VkBuffer(只需将分配和缓冲区设置得更大,然后在绑定时选择要使用的存储区域)。当 GPU 命令读取一个存储区域时,您写入另一个区域。

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

但是因为您像这样进行双缓冲,所以您将要写入的内存的栅栏不是您上一帧提交的批处理的栅栏。这是您在此之前提交框架的批次。由于 GPU 收到该操作已经有一段时间了,因此 CPU 实际等待的可能性要小得多。也就是说,围栏应该已经设置好了。

现在,你不应该vkWaitForFences在那个围栏上做文字。您应该检查它是否已设置,如果没有,请花时间做其他有用的事情。但是,如果您没有其他有用的事情可以做,那么等待可能是可以的(而不是坐下来进行测试)。

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


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

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

嗯……差不多。

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

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

  • 我同意,如果我在发出 memcpy 之前等待队列提交发出的栅栏信号,设备将在主机写入之前完成读取。不清楚的是另一面。我如何知道使用 memcpy 写入的内存在渲染通道读取之前已完成发送到设备?当 memcpy 返回时,它不会立即在设备上可用,对吗?我不需要将写入完成与读取开始同步吗?即如何对这些进行排序? (2认同)