为什么 Vulkan 中的围栏状态检查和重置如此缓慢?

Why is fence status checking and resetting in Vulkan so slow?

如果我使用 vkGetFenceStatus() 检查围栏的状态,大约需要 0.002 毫秒。这可能看起来不是很长的时间,但在渲染或游戏引擎中的时间量是很长的时间,尤其是在执行其他计划作业的同时等待栅栏时,很快就会加起来接近一毫秒的时间。如果围栏状态保持在主机端,为什么检查这些并重置它们需要这么长时间?其他人在调用此函数时是否得到类似的时间?

理想情况下,检查设置围栏所花的时间应该无关紧要。虽然在 120FPS 下占用帧的 0.02% 并不理想,但归根结底,它不应该那么重要。理想的场景是这样的:

基本上,您应该围绕这样的想法构建您的围栏逻辑,即如果围栏几乎肯定已经设置,您将只检查它。

如果您提交第 1 帧,则在开始构建第 2 帧时不应检查围栏。您应仅在开始构建第 3 帧(或第 4 帧,具体取决于延迟时间)时检查它你愿意容忍)。

最重要的是,如果未设置,则表示 CPU 未完成足够的工作或 GPU 的工作量过多。如果 CPU 超出 运行 GPU,CPU 可以等待。也就是说,CPU 性能不再重要,因为您受制于 GPU。

所以检查围栏所花费的时间或多或少是无关紧要的。

如果您处于任务分派的场景中,并且希望尽快 运行 图形任务,但如果图形任务尚未准备好,您还有其他任务可用,那就是这可能会成为一个问题。但即便如此,从第一次检查图形任务是否准备就绪到你 运行 没有其他任务可以开始之间的那一小段 space 时间,这只是一个问题CPU 需要开始等待 GPU 准备就绪。

在这种情况下,我建议每帧只测试两次围栏。一有机会就测试它;如果未设置,请执行 所有 其他任务。在完成这些任务后 dispatched/done...只需在 GPU 上等待 vkWaitForFences。要么设置围栏并且函数将立即 return,要么您正在等待 GPU 准备好接收更多数据。

在其他情况下这可能会成为问题。如果 GPU 缺少专用传输队列,您可能会出于不同目的测试同一个栅栏。但即使在这些情况下,我也建议每帧只测试一次围栏。如果数据上传未完成,如果该数据现在必不可少,则您要么必须进行硬同步,要么延迟到下一帧使用它。


如果这仍然是一个问题,并且您的 Vulkan 实现允许时间线信号量,请考虑使用它们来跟踪队列进度。 vkGetSemaphoreCounterValue 可能比 vkGetFenceStatus 快,因为它只是读取一个数字。