9

一个多星期以来,我一直在调查我的 DirectX 11 C++ 应用程序中的一个问题,因此我正在向 StackOverflow 上的好人寻求任何可以帮助我找到这个问题的见解。

我的应用程序将主要以每秒 60-90 帧的速度运行,但每隔几秒钟我就会得到一个大约需要 1/3 秒才能完成的帧。经过大量调查、调试和使用各种代码分析器,我将范围缩小到对 DirectX API 的调用。但是,从一个缓慢的帧到下一帧,并不总是同一个 API 调用导致速度下降。在我最近的一次运行中,停止的呼叫(总是大约五分之一秒)是

  • ID3D11DeviceContext:UpdateSubresource
  • ID3D11DeviceContext:DrawIndexed
  • IDXGISwapChain:现在

不仅停止的函数不是同一个函数,而且这些函数中的每一个(主要是前两个)慢速调用可能来自我代码中的不同位置,从一个到另一个。

根据我放置在代码中以帮助测量事物的多个分析工具和我自己的高分辨率计时器,我发现这种“打嗝”会以不到 3 秒(~2.95)的一致间隔发生。

此应用程序从外部硬件收集数据并使用 DirectX 实时可视化该数据。在应用程序运行时,硬件可能处于空闲状态或以各种速度运行。硬件运行得越快,收集的数据就越多,并且必须进行可视化。我指出这一点是因为在考虑此错误的某些特征时它可能很有用:

  • 硬件空闲时不会出现长帧。这对我来说很有意义,因为软件只需要重绘它已经拥有的数据,而不必将新数据传输到 GPU。
  • 但是,无论硬件运行速度如何,长帧都会以这些一致的 3 秒间隔出现。因此,即使我的应用程序每秒收集两倍的数据量,长帧的频率也不会改变。
  • 这些长帧的持续时间非常一致。始终在 0.25 到 0.3 秒之间(我相信是对 DirectX API 的缓慢调用是一致的,因此整体帧持续时间的任何变化都在该调用之外)。
  • 上周进行现场测试时(当我第一次发现这个问题时),我注意到在应用程序的几次运行中,经过很长时间(可能 20 分钟或更长时间)的连续测试,除了观看之外没有与程序进行太多交互,打嗝就会消失。如果我们与应用程序的某些功能交互或重新启动程序,打嗝会再次出现。对我来说没有意义,但几乎就像 GPU “想通”并解决了问题,但当我们改变它之前所做的工作模式时又恢复了原状。不幸的是,我们硬件的性质使我很难在实验室环境中复制它。

此错误在具有非常相似硬件(双 GTX580 卡)的两台不同机器上始终出现。但是,在该应用程序的最新版本中,并未出现此问题。不幸的是,代码从那时起经历了许多变化,因此很难确定是什么具体变化导致了问题。

我考虑了图形驱动程序,因此更新到最新版本,但这并没有什么不同。我还考虑了对两台计算机进行了其他更改的可能性,或者可能对运行在两台计算机上的软件进行了更新,这可能会导致 GPU 出现问题。但是我想不出除了在应用程序运行时在两台机器上运行的 Microsoft Security Essentials 之外的任何东西,而且我已经尝试禁用它的实时保护功能,但无济于事。

虽然我希望原因是我可以关闭的外部程序,但最终我担心我必须使用 DirectX API 做一些不正确/不正确的事情,导致 GPU 必须每隔几秒钟进行一次调整。也许我在更新 GPU 上的数据的方式上做错了(因为延迟只发生在我收集要显示的数据时)。然后 GPU 每隔几秒钟就会停顿一次,并且在停顿期间碰巧调用的任何 API 函数都不能像往常一样快地返回?

任何建议将不胜感激!

谢谢,蒂姆

更新(2013.01.21):

我终于屈服了,并重新搜索了我的应用程序的先前版本,直到我发现没有发生此错误的地方。然后我一个接一个地进行修订,直到我准确地找到错误开始发生的时间并设法查明问题的根源。在我将“无符号整数”字段添加到顶点类型后,问题开始出现,我为其分配了一个大的顶点缓冲区。由于顶点缓冲区的大小,此更改将大小增加了 184.65 MB(从 1107.87 MB 增加到 1292.52)。因为我确实在我的顶点结构中需要这个额外的字段,所以我找到了其他方法来减少整体顶点缓冲区大小,并将其降低到 704.26 MB。

我最好的猜测是,添加该字段及其所需的额外内存导致我超出了 GPU 的某个阈值/限制。我不确定这是超出了总内存分配,还是超出了单个顶点缓冲区的某些限制。无论哪种方式,似乎这种过度都会导致 GPU 每隔几秒就必须做一些额外的工作(也许与 CPU 通信)每隔几秒,所以我对 API 的调用不得不等待这个。如果有人有任何信息可以阐明大型顶点缓冲区的含义,我很想听听!

感谢所有给我时间和建议的人。

4

1 回答 1

1

1)尝试打开VSYNC

2)您是否正在分配/释放大块内存?尝试在程序开始时分配内存并且不要释放它,只需覆盖它(这可能是您使用 updatesubresource 所做的)

3) 将与硬件设备的交互放在单独的线程上。在设备完全完成向应用程序传递数据后,将其加载到 GPU 中。不要让设备控制主线程。我怀疑设备经常阻塞主线程,我完全在推测,但如果你是直接将数据从设备复制到 GPU,设备偶尔会阻塞,这会导致速度变慢。

于 2013-01-18T20:38:31.260 回答