单个命令缓冲区中的同步

Syncronization in single command buffer

在我的 Vulkan 应用程序中,我使用单个命令缓冲区并预先记录其中的所有内容,现在我有一个错误,我怀疑的地方之一是我复制了一个从暂存缓冲区到 GPU(设备本地)缓冲区的数据区域,然后我对该缓冲区进行操作。

问题是,即使我使用单个命令缓冲区,我也应该进行同步吗?

我的问题并非仅针对复制缓冲区,它是一个一般性问题,是否存在即使在单个命令缓冲区应用程序中也应该进行同步的情况?

在 Vulkan 中,几乎所有内容都必须同步。

并不是因为您只使用一个命令缓冲区,所以命令不能 运行 异步。

假设您正在复制一个缓冲区,然后您希望将此缓冲区作为顶点缓冲区读取。

您必须使用 srcAccess TRANSFER_WRITE 和 dstAccess VERTEX_ATTRIBUTE_READ.

发出从 TRANSFER_STAGEVERTEX_INPUT_STAGE 的内存屏障

这样,屏障确保传输完成并且内存既可用又可见。

它可能是那样的红色: 当第二个命令到达VERTEX_INPUT_STAGE时,请等待前面的命令完成TRANSFER_STAGE(这是执行障碍)。并刷新 TRANSFER_STAGETRANSFER_WRITE 缓存并使 VERTEX_INPUT_STAGEVERTEX_ATTRIBUTE_READ 缓存无效(这是内存屏障)。我在这里对特定阶段使用了 flush / invalidate 这个词,因为某些阶段 TOPBOTTOM 不访问内存,因此尝试对它们执行内存屏障是没有用的。

但是,我读到您正在使用暂存缓冲区,当您写入暂存缓冲区时,HOST 的 memoryBarrier 是通过提交命令缓冲区创建的。但是,如果不使用COHERENT内存,则必须使用vkFlushMappedMemoryRanges.

一个好主意是在使用数据之前使用屏障 :

TRANSFER
WORK that do not use the value transferred
BARRIER
USE DATAS

您可以获得更多信息here

Should I do synchronization even when I'm using a single command buffer?

我忍不住打个字回答:"yes".

即使是单个缓冲区(或通常是队列),您也需要同步,因为命令缓冲区中的命令在执行时允许重叠。您需要同步他们对 资源 VkImages、VkBuffers 和他们的内存)的访问。您通常使用 管道屏障 来做到这一点,它在一些子操作之间添加 执行依赖性 内存依赖性 队列中的命令。

您可能正在您的应用中使用交换链。没有"presentation pipeline"与pipeline barrier同步,所以必须用semaphores来同步

最后您还需要与主机同步 (CPU)。您不能销毁仍在使用的句柄(最终您确实需要 destroy/clenup)。您必须通过使用 fences 或类似 fence 的 vkDeviceWaitIdle() 同步来确保它们未被使用。

别忘了(一如既往)您也需要同步 CPU 线程。具体来说,在 Vulkan 中,您仍然需要 synchronize/mutex 围绕您传递给命令的参数。

只有少数例外情况您不必进行某种显式同步。例如,只要在调用 vkQueueSubmit.

之前发生,您就不需要同步一致(或刷新)的主机 (CPU) 写入