OpenGL和CPU/GPU定时器同步

3

我正在尝试制作一个CPU和GPU分析器,用于视频游戏。目标是在屏幕上显示两个图表,提供帧中不同任务所花费的时间。以下是其非常简单的示例:

enter image description here

我正在使用QueryPerformanceCounter(在Windows上)获取CPU时间和glQueryCounter(GL_TIMESTAMP)获取GPU时间。
问题是我得到的CPU和GPU时间不是相对于同一起点的。我第一次尝试修复这个问题是在应用程序初始化期间进行阻塞调用以获取GPU时间戳(使用glGetInteger64v(GL_TIMESTAMP)),紧随其后的是获取CPU时间。两个时间之间的差异使我基本上可以将GPU时间转换为CPU时间并使两个图表同步。但是几秒钟(或几分钟)后,时间就会漂移,我的图表不再正确同步。
我不能在游戏开始后再进行另一个阻止调用以获得GPU时间,因为我不想失去一帧并使游戏卡顿。
有人尝试过这样做或者有任何关于如何在不影响性能的情况下同步CPU和GPU时间的建议吗?
我还有另一个想法,但我不知道它是否能很好地工作:让单独的线程进行阻塞调用以获取GPU时间,也获取CPU时间,并以某种方式将差异发送回主线程。然后,线程将休眠几秒钟,然后重新启动。如果这个方法看起来不错,我会尝试并更新帖子。

编辑:我在AMD和NV卡上尝试了上面的想法,看起来效果不错。即使调用glGetInteger64v(GL_TIMESTAMP)很多次(每次之间只有1ms的睡眠),似乎对性能没有影响。我仍然需要进行更深入的测试,但到目前为止,这看起来是一个不错的解决方案。


虽然我对你的问题没有答案,但我绝对不会使用“其他想法”的方法:如果你在两个线程中使用相同的上下文,那么该块将会像只使用一个线程一样阻塞游戏。当为每个线程使用单独的上下文时,驱动程序将在执行阻塞调用时切换你的渲染上下文,这也会导致游戏卡顿。为了完整起见:在我使用过的所有GPU上,GPU和CPU之间的时间差异并没有随着时间的推移而发散得太大。在我的当前nvidia 680上,每小时大约是几毫秒的一小部分。 - undefined
另一个想法是:阻塞OpenGL调用的问题在于它会刷新你的流水线并等待完成。那么,在swapbuffer之后直接进行同步,因为这已经刷新了流水线,怎么样?在这种情况下,glGetInteger64v应该立即返回。 - undefined
@BDL 你说的"驱动程序将替换你的渲染上下文"是什么意思?时间戳查询是否被视为需要自己的命令缓冲区的绘制调用?这似乎令人惊讶。在这种情况下,主线程中进行查询并在其他线程中等待其完成可能会起作用,对吗?为了完整起见:我在GTX 660上尝试过,时间每分钟大约漂移一毫秒(粗略估计)。我还在Radeon HD 7950上尝试过,它的范围相同(但漂移似乎朝另一个方向:o)。你用什么方法来测量CPU时间? - undefined
@BDL 我尝试在 SwapBuffer 之后(以及之前)调用 glGetInteger64v(GL_TIMESTAMP)。在 Nvidia 上效果还不错,大约需要20微秒。但是在 AMD 上,根据游戏是否受 GPU 限制,它的值会在60到200微秒之间跳动。 - undefined
@derhass 嗯,这是一个同步的API,它直接返回值。这就是我所说的阻塞。相比之下,如果结果可用,glQueryCounter + glGetQueryObject 是非阻塞的。 - undefined
显示剩余3条评论
1个回答

1

我创建了一个单独的线程,对glGetInteger64v(GL_TIMESTAMP)进行阻塞调用。即使在每次调用之间等待1毫秒这样愚蠢的小时间段,性能也没有明显的差异。但需要注意的是,在此修改之前,我已经有几个OpenGL上下文。

在最终代码中,我在每次调用glGetInteger64v(GL_TIMESTAMP)之间等待30秒。这似乎足够频繁,可以避免我测试过的所有PC上出现任何可见的漂移。

我在Nvidia卡(GTX 460、GTX 660、GTX 780ti、GTX 780M)和AMD(Radeon HD 7950)上进行了测试,所有卡都配备了Intel CPU。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接