【问题标题】:OpenGL Inconsistent FramerateOpenGL帧率不一致
【发布时间】:2014-11-07 11:35:14
【问题描述】:

我一直在创建/将我用 C# 制作的游戏移植到 C++ 中,当我开始查看每秒帧数时,我注意到发生了一些奇怪的事情。

我最初是用 C# 编写我的游戏,并且帧速率总是非常一致。当我打开 VSync 时,我会得到稳定的 60fps,而没有,大约在 600-700 左右。它几乎总是一个静态数字。现在,在 c++ 环境中,我注意到帧速率下降了很多并且显得非常不稳定/不一致(很确定这与我的实现有关)。

我打算设置一个日志并让应用程序在捕获帧计数的同时运行,但是,这导致帧速率下降,所以我决定不尝试通过该路径向大家展示。相反,我只会说当应用程序启动时,帧速率显示为 0 大约 20 毫秒,然后跳到大约 2500 fps。然后应用程序将在 +500 或 -500 左右跳跃,有时甚至会有效地翻倍到接近 4000fps 的位置。 使用 OpenTK,第一次启动时帧率始终显示为 60fps(启用 Vsync),并且没有出现几毫秒显示 0fps 的问题。

我很确定帧速率在下降、增加、下降、增加等。在我看来,当它达到最大值时,它看起来就像一个滚动的变量。

我还应该提到 我没有使用 OpenGL 库。我想从头开始编写它,我已经做得非常成功。我只是不知道为什么帧率如此不一致。

这是初始化所有内容并计算帧速率本身的主要类。希望有人可以帮助我发现我做错了什么。我提前道歉,因为该课程大约有 220 行代码。

http://pastebin.com/tV4Sd2K3

我只渲染一个三角形,这是通过立即模式完成的。

这里还有三张快速图片,以进一步说明我在说什么: 这个持续大约 20-30ms,然后上升到超过 2000fps。

这个显示了一个突然的低峰值(我实际上只是在渲染一个三角形!)

还有一个高峰值,再次只渲染 1 个三角形。没有其他事情发生!

这些图片只是一个简单的例子,它有时会更糟或更好。

获得帮助后的最终想法: 这个问题是由我在 Visual Studio 中的实现和调试引起的。我创建了一个发布版本,关闭了所有内容,然后运行了可执行文件。帧的偏差仅为+-50左右;它健康地挂在 2700-2800fps 左右。所以,经验教训:在 Visual Studio 中调试不是所见即所得。

【问题讨论】:

  • 后台运行的还有什么?也忘记立即模式,它已被弃用,而是使用着色器和 VBO
  • @ratchetfreak Visual Studio 和 Google Chrome,我只使用即时模式进行初始调试;我很快就会把它从我的引擎中剥离出来。
  • chrome 可能是一个意外的资源占用,因为它为每个选项卡生成进程的方式,而且 VBO 会更快并且不使用相同的 GL 调用,因此您从中获得的任何见解都不会切断即时模式后生效
  • 虽然我没有为您提供答案,但请注意,太多的事情可能会干扰一个过程。 Chrome 使用硬件加速;如果启用了合成,窗口管理器也会这样做。当你有一个时解决问题 - 成千上万的 FPS 没有任何好处,也没有说明性能。将沉重的几何图形放到垂直同步间隔以下并在那里测量。
  • @ratchetfreak 我非常怀疑现在的即时模式会导致零星的 500fps 增加和减少。当然,那将是客户端/软件分隔符...

标签: c++ opengl frame-rate


【解决方案1】:

timeGetTime() 是一种非常错误的时间测量方式。所以我怀疑你首先有准确的 FPS 值。使用boost::chrono(注意,std::chrono 目前在 Visual Studio 2013 实现中不能提供良好的准确性)或本机 QueryPerformanceCounter

另一件事,即实际的 FPS 跳转问题,是您的主循环:

while (isGameRunning)
{
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        if (msg.message == WM_QUIT)
        {
            break;
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    else
    {
        draw();
    }
}

只有在没有 Win32 消息可以继续时才绘制(当PeekMessage() 返回false 时)。因此,对于任何消息,您都会丢失帧。

你应该这样做:

while (isGameRunning)
{
    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) // add PM_NOYIELD
    {
        // Move it to `WndProc`.
        // Break loop by setting `isGameRunning` to `false`
        //if (msg.message == WM_QUIT)
        //{
        //  break;
        //}
        TranslateMessage(&msg);
        DispatchMessage(&msg);

    }
    // Draw unconditionnaly
    draw();
}

HTH。

【讨论】:

  • 您的更新是一项改进。现在它只跳大约 150 帧左右,比它正在做的近 500-600 fps 的速度要好得多。
  • 我会接受你作为答案,因为你为这个可能无法解决的问题付出了努力,但帮助很大。谢谢。
  • 另外,我相信在 Visual Studio 旁边运行它确实也会恶化。我创建了一个发布版本,关闭了所有内容,然后运行了可执行文件。帧的偏差仅为+-50左右;它以 2700-2800fps 的速度健康地挂起。
  • 如何在处理消息后立即绘制是一种改进?如果队列中有两条消息会发生什么? (一个将被处理,其余的将延迟到下一帧)。在绘图之前处理所有事件是常见且正确的做法。
  • @keltar 哦,我没注意到在编辑初始 sn-p 时是 if 而不是 while(即使我删除了 else =/)。实在是太傻了。固定。
猜你喜欢
  • 1970-01-01
  • 2021-11-10
  • 1970-01-01
  • 2015-12-25
  • 2013-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多