在我的应用程序中,Vulkan 验证层抱怨栅栏和信号量无法被销毁,因为它们仍在使用中。
正如它声称的那样,该消息“有点奇怪”
验证错误:[VUID-vkDestroyFence-fence-01120] |消息 ID = 0x5d296248 | vkDestroyFence():无法在 VkFence 0xcb3ee80000000007[] 当前正在使用的 VkFence 0xcb3ee80000000007[] 上调用栅栏
(基本上告诉我栅栏将“自行使用”),但我认为,这更像是一种奇怪的格式化消息的方式,并且没有“更深层次”的含义。基本上栅栏仍在使用。
我的“所有”栅栏和二进制信号量都抛出了完全相同的消息(一个栅栏,两个信号量,只有一个队列用于“所有”)。
经过一些调试,我发现只有当清理既没有检查提交命令的栅栏,也没有等待队列变为空闲时,才会发生这种情况。
等待围栏或只是等待队列就足够了。
但这不可能是在命令问题仍在运行时进行销毁的“纯粹的时间问题”,因为命令提交和销毁都是手动触发的,延迟远远超出了 GPU 的善恶。
当破坏发生时,提交的命令必须“长时间完成”(我没有“那么快”......😂)。
然后我发现,通过 vkGetFenceStatus() 检查栅栏的状态就可以解决问题,即在销毁之前执行 vkGetFenceStatus() 会导致验证层保持沉默。
这似乎表明 GPU 上进行了一些“惰性”评估,只要 CPU 通过检查栅栏或等待队列空闲而直接或间接“不询问”,就不会结束提交的命令。
有点像薛定谔猫,看一眼就会死……
这种行为是预期的吗?
我在官方文档中找不到任何相关内容?!
验证层不是“GPU”;它们是外部代码,您可以使用它们来确保您正确使用 Vulkan API。
API 规定您不能在使用栅栏时破坏栅栏。这意味着,为了使您的销毁调用有效,您的代码必须知道栅栏不再使用。
因此,验证层被编程,因此您必须做一些事情来表明您的代码知道栅栏不再使用。并在一段时间内做其他事情不是吗。您认为您已经花费了足够的 CPU 时间让 GPU 完成该批次。但你不知道它已经完成了。 这就是验证层所关心的。它希望你的代码肯定正确,而不是可能正确。
因此,验证层要求您使用 Vulkan API 执行一些操作,以与包含栅栏的批次的完成同步。检查围栏的状态就是其中之一,而且通常是您应该使用的。