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