在我的Vulkan应用程序中,我正在使用单个命令缓冲区,我正在预先记录其中的所有内容,现在我有一个错误,其中一个我对此感到怀疑的地方,就是我复制一个区域的地方从暂存缓冲区到GPU(设备本地)缓冲区的数据,然后我在该缓冲区上执行操作。
问题是,即使我使用单个命令缓冲区,我是否应该进行同步?
我的问题不仅仅是复制缓冲区,这是一个普遍的问题,是否有任何情况,即使在单个命令缓冲区应用程序中,您应该进行同步?
答案 0 :(得分:1)
在Vulkan中,你必须几乎同步一切。
这不是因为您只使用一个命令缓冲区,命令无法异步运行。
例如,假设您正在复制缓冲区,并希望将此缓冲区作为顶点缓冲区读取。
您必须从TRANSFER_STAGE
到VERTEX_INPUT_STAGE
并使用srcAccess TRANSFER_WRITE
和dstAccess VERTEX_ATTRIBUTE_READ
发出内存屏障。
这样,屏障确保传输完成并且内存可用且可见。
它可能是红色的:
当第二个命令到达VERTEX_INPUT_STAGE
时,请等待先前的命令完成TRANSFER_STAGE
(这是执行障碍)。并刷新TRANSFER_WRITE
的{{1}}缓存,并使TRANSFER_STAGE
的{{1}}缓存无效(这是内存屏障)。我在这里为特定阶段使用了flush / invalidate这个词,因为某些阶段VERTEX_ATTRIBUTE_READ
和VERTEX_INPUT_STAGE
不访问内存,因此尝试对它们执行内存屏障是没用的。
但是,我读到你正在使用一个临时缓冲区,当你写入你的临时缓冲区时,来自HOST的memoryBarrier是由提交命令缓冲区产生的。但是,如果您不使用COHERENT内存,则必须使用TOP
。
一个好主意可能是在使用数据之前使用屏障:
BOTTOM
您可以获得更多信息here
答案 1 :(得分:0)
即使我使用单个命令缓冲区,我是否应该进行同步?
我很想说一句话答案:"是"。
即使使用单个缓冲区(或通常是队列),也需要进行同步,因为命令缓冲区中的命令允许在执行时重叠。您需要同步对资源(VkImage
s,VkBuffer
及其内存的访问权限。您通常使用管道障碍来执行此操作,这会在队列中某些命令的子操作之间添加执行依赖和内存依赖。
您可能在应用中使用了交换链。没有"演示管道"要与管道障碍同步,因此必须使用信号量进行同步。
最后,您仍然需要与主机(CPU)同步。您不能销毁仍在使用的句柄(并且您最终需要销毁/清除)。您必须使用 fences 或类似围栏的vkDeviceWaitIdle()
同步来确保它们未被使用。
让我们不要忘记(一如既往)您需要同步CPU线程。要在Vulkan中具体说明,您仍需要在传递给命令的参数周围同步/互斥。
只有少数例外,您不必进行某种显式同步。例如,只要在调用vkQueueSubmit
之前发生一致(或刷新),就不需要同步主机(CPU)写入。