分析OpenGL应用程序 - 当驱动程序阻塞CPU端时

时间:2015-02-22 20:07:13

标签: performance opengl rendering nvidia vsync

我制作了一个游戏中的图形分析器(CPU和GPU),Nvidia驱动程序有一个奇怪的行为,我不知道如何处理。

以下是正常情况的截图: GPU Profiler, vysnc on 你在这里看到的是连续3帧,顶部是GPU,底部是CPU。两个图都是同步的。

“END FRAME”栏仅包含对SwapBuffers的调用。它看起来很奇怪,直到GPU完成所有工作才会阻塞,但这就是当vsync打开时驱动程序选择做的事情,并且所有工作(CPU和GPU)都可以在16ms内完成(AMD也是如此)。我的猜测是它可以最大限度地减少输入滞后。

现在我的问题是它并不总是那样做。根据框架中发生的情况,图形有时如下所示: GPU Profiler, vysnc on, V2 这里实际发生的是,第一个OpenGL调用是阻塞,而不是调用SwapBuffers。在这种特殊情况下,阻止调用是glBufferData。如果我添加一个只做那个的虚拟代码(创建一个统一的缓冲区,用随机值加载并销毁它),它就更加明显了:

GPU Profiler, vysnc on, V2 with dummy code

这是一个问题,因为这意味着图表中的条形图可能会因为没有明显原因而变得非常大。人们看到这一点可能会得出一些关于某些代码变慢的错误结论。

所以我的问题是,我该如何处理这个案子?我需要一种方法来随时显示有意义的CPU时序。

添加一个加载统一缓冲区的虚拟代码并不是很优雅,可能不适用于未来版本的驱动程序(如果驱动程序仅阻止在drawcalls上呢?)。

glClientWaitSync同步也不是一件好事,因为如果帧速率下降,驱动程序将停止阻塞以允许CPU和GPU帧并行运行,我需要检测到停止调用glClientWaitSync(但我不知道该怎么做。)

(欢迎提出更好标题的建议。)

编辑:这是没有vsync的情况,当GPU是瓶颈时: GPU Profiler, vysnc off, V2 GPU帧占用的时间比CPU帧长,因此驱动程序决定在glBufferData期间阻止CPU,直到GPU赶上来。

条件不一样,但问题是:CPU时序“错误”,因为驱动程序会创建一些OpenGL功能块。这可能是一个比使用vsync的更简单的例子。

1 个答案:

答案 0 :(得分:3)

这实际上是按预期工作的。由于VSYNC而导致的阻塞不一定必须在SwapBuffers (...)的呼叫期间发生,VSYNC导致阻塞的原因有几个,而且几乎完全不受你的控制。

当交换链中充满了等待交换的后备缓冲区时(通常只有1个后备缓冲区),在交换完成之前,不得允许执行修改帧缓冲区的命令。这导致管道失速,并且是第一次打击。请记住,即使管道已停止,GL仍可在此状态下排队命令。

在大多数平台上,没有API允许您在窗口系统的交换链中显式请求反向缓冲区的数量。您可以请求 double - 缓冲,驱动程序可以将双缓冲解释为2或更多(您将看到标记为“启用三重缓冲”< / em>在一些驱动程序中。)

罢工两个来自被称为“提前渲染”的东西。这是GL在拒绝接受新命令之前将排队的特定于驱动程序的工作量。再一次,作为OpenGL软件的开发人员,您无法对此进行任何控制。在某些驱动程序中,您可以深入挖掘并手动配置。增加该值将允许CPU在管道停滞时排队更多工作,但往往会增加延迟(特别是D3D实现它的方式,禁止帧丢弃)。

一旦渲染管道停止等待缓冲区交换并且你耗尽渲染前提限制,那就是三次攻击。调用线程将阻塞下一个GL命令,直到VBLANK滚动并取消阻塞管道。


正如您所描述的,

glClientWaitSync (...)将有效地消除所有渲染。这可能是最大限度地减少时序变化的理想选择,但如果您在达到刷新率时遇到问题,则会对整体帧速率产生负面影响。

Adaptive VSYNC应该是您追求的第一件事。在支持此功能的驱动程序上,您可以通过设置负交换间隔启用它,并在无法维持刷新率时避免阻止。实际上,自适应VSYNC的目的是在绘制太快时限制渲染。如果您的绘图速度比监视器可以处理的速度快,那么分析GL API调用似乎并不是特别重要。

在最坏的情况下,您始终可以完全禁用VSYNC。在Windows Vista引入的现代合成窗口管理器中,无论是否启用VSYNC,都会在窗口模式下阻止撕裂。 VSYNC实际上只是在这种情况下节省电力并将其关闭以进行更准确的分析可能是可接受的折衷方案。您可以轻松实现自己的限制机制,以防止您的引擎以非常高的帧速率绘制,而不会出现VSYNC引入的不可预测的行为。