【发布时间】:2020-03-24 21:33:51
【问题描述】:
这是一个关于基于障碍的同步 w.r.t 的具体问题。命令缓冲区提交和清理命令缓冲区所需的资源(如使用的缓冲区和图像)。
让我们假设,一切都在一个队列中,并且有三帧在飞行中。
我执行以下操作:
Create Render-CmdBfr[0..2], Fence[0..2]
...
Create StagingBuffer
Create Image
Create Init-CmdBfr
Record `copy StagingBuffer to Image` into Init-CmdBuffer
Record `barrier ALL_COMMANDS ALL_COMMANDS MEMORY_WRITE MEMORY_READ` into Init-CmdBuffer
Submit Init-CmdBuffer without any semaphore or fence
...
// Frame #1
Submit Render-CmdBfr[0] -> signal Fence[0]
// Frame #2
Submit Render-CmdBfr[1] -> signal Fence[1]
// Frame #3
Submit Render-CmdBfr[2] -> signal Fence[2]
// Frame #4
Wait for Fence[0] -> submit Render-CmdBfr[0] -> signal Fence[0]
Delete Init-CmdBfr
Delete Image
Delete StagingBuffer
// Frame #5
Wait for Fence[1] -> submit Render-CmdBfr[1] -> signal Fence[1]
// Frame #6
Wait for Fence[2] -> submit Render-CmdBfr[2] -> signal Fence[2]
... continue forever ...
有问题的部分是我删除了Init-CmdBfr、Image 和StagingBuffer。或者实际上,只要应用程序运行良好,它就没有问题。但是验证层抱怨:
带有 Id[0|VUID-vkFreeCommandBuffers-pCommandBuffers-00047] 的 Vk-callback 和 Message[尝试释放正在使用的 VkCommandBuffer 0x20e61cff060[]。 Vulkan 规范规定:pCommandBuffers 的所有元素不得处于挂起状态(https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkFreeCommandBuffers-pCommandBuffers-00047)]
还会出现更多消息,例如像下面这样:
带有 Id[0|VUID-vkDestroyBuffer-buffer-00922] 和 Message[Cannot free VkBuffer 0xe6bc0400000000a1[] 的 Vk-callback 正被命令缓冲区使用。 Vulkan 规范规定:所有直接或通过 VkBufferView 引用缓冲区的提交命令必须已完成执行 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyBuffer-buffer-00922)]
规范规定,命令缓冲区只有在离开“待处理”状态时才能被删除。通过我的barrier ALL_COMMANDS ALL_COMMANDS MEMORY_WRITE MEMORY_READ 和Fence[0] 信号和等待的完整周期,我认为这必须在第4 帧中给出。
我的第一个问题是:我对这个假设是否正确?还有,我的这种做法好吗?
我的第二个问题是:如果我是对的并且我的方法没问题,我该如何防止验证层抱怨?
我认为,验证层只是不知道障碍并抱怨,因为可能是我没有创建障碍。事实上,当我在Init-CmdBfr(即Submit Init-CmdBuffer and signal Init-Semaphore)的提交中添加信号量时,验证层不再抱怨了。但在我看来,信号量实际上是不必要的。没有它可以吗?
更新:
将所有Semaphore[i] 替换为Fence[i] 以更好地说明我的问题。 (前面的例子造成了一些混乱,抱歉。)
【问题讨论】:
-
"在没有任何信号量或栅栏的情况下提交 Init-CmdBuffer" 你怎么知道什么时候完成?
-
通过使用屏障,我知道
Init-CmdBfr的所有命令必须在Render-CmdBfr[0]开始执行之前完成(在同一个队列上)。我知道Render-CmdBfr[0]何时完成,因为它发出信号量的信号。至少我认为它是这样工作的,但我可能是错的。 -
"通过使用屏障" 屏障与后续命令同步,而不是与队列外进程同步。这就是信号量的用途。
-
是的,但在我上面描述的示例中,它不是一个完全有效的隐式同步依赖项吗?
Init-CmdBfr-> 屏障 ->Render-CmdBfr[0]-> 信号量 -> 安全删除Init-CmdBfr。 -
我的意思是,障碍是没有意义的。关于销毁命令缓冲区的有效性,它没有提供任何有用的同步。