【发布时间】:2015-01-23 15:53:48
【问题描述】:
我正在尝试制作一个用于视频游戏的 CPU 和 GPU 分析器。目标是在屏幕上显示 2 个图表,显示帧的不同任务所花费的时间。这是对其外观的非常粗略的说明:
我使用 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 上,它大约是每小时几分之一毫秒。
-
同步...不影响性能...不太可能 IMO
-
另一个想法:阻塞 OpenGL 调用的问题是,它们会刷新你的管道并等到这个。在交换缓冲区之后直接同步怎么样,因为这已经刷新了管道?在这种情况下,glGetInteger64v 应该立即返回
-
@BDL “驱动程序将换出你的渲染上下文”是什么意思?时间戳查询是否被视为需要自己的命令缓冲区的绘图调用?这似乎令人惊讶。在这种情况下,在主线程中进行查询并在另一个线程中等待它完成可能会起作用,对吧?为了完整起见:我尝试了 GTX 660,时间每分钟漂移大约一毫秒(大约)。我还尝试了 Radeon HD 7950 和它在同一个范围内(但漂移似乎在另一个方向:o)。你用什么方法来测量 CPU 时间?
-
我和你一样使用了 QueryPerformanceCounter
标签: opengl