SDL + OpenGL,具有周期性尖峰的不规则帧时间

Posted

技术标签:

【中文标题】SDL + OpenGL,具有周期性尖峰的不规则帧时间【英文标题】:SDL + OpenGL, irregular frame times with periodic spikes 【发布时间】:2017-08-25 16:12:05 【问题描述】:

我正在使用 SDL 开发一个应用程序,我很高兴。我注意到动画中有一些小的冻结。我已经编写了一个功能最少的单独项目,我发现即使使用非常基本的设置也会出现问题。

这是代码:

#include <iostream>
#include <vector>
#include <fstream>
#include <SDL.h>
#include <glad/glad.h>

using namespace std;

// the application will close after this amount of time
const float MILISECONDS_TO_CLOSE = 10 * 1000;

int main(int argc, char** argv)

    SDL_Init(SDL_INIT_EVERYTHING);

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    SDL_Window* window =
        SDL_CreateWindow(
            "tracer",
            100, 100,
            800, 600,
            SDL_WINDOW_OPENGL
        );

    SDL_GLContext context = SDL_GL_CreateContext(window);

    // SDL_GL_SetSwapInterval(1);   // this line mitigates the problem but just slightly

    if (!gladLoadGL())
    
        cout << "gladLoadGL failed" << endl;
    

    const GLubyte *oglVersion = glGetString(GL_VERSION);
    std::cout << "This system supports OpenGL Version: " << oglVersion << std::endl;
    const GLubyte *gpuVendor = glGetString(GL_VENDOR);
    std::cout << "Graphics card: " << gpuVendor << std::endl;

    glClearColor(0.15f, 0.15f, 0.15f, 1.0f);

    vector<unsigned> deltas;
    deltas.reserve(10 * MILISECONDS_TO_CLOSE);

    static unsigned firstTime, prevTime, curTime;
    firstTime = prevTime = curTime = SDL_GetTicks();
    while (true)
    
        // compute delta time
        curTime = SDL_GetTicks();
        unsigned dt = curTime - prevTime;
        prevTime = curTime;
        deltas.push_back(dt);

        // close the application after some time
        if (curTime - firstTime > MILISECONDS_TO_CLOSE) break;

        // handle closing events
        SDL_Event event;
        if (SDL_PollEvent(&event))
        
            if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE || event.type == SDL_QUIT) break;
        

        glClear(GL_COLOR_BUFFER_BIT);

        SDL_GL_SwapWindow(window);
    

    // save recorded deltas to a file
    fstream f("out.txt", ios::out | ios::trunc);
    for (unsigned dt : deltas) f << dt << endl;
    f << flush;
    f.close();

    return 0;

程序在 10 秒内记录帧之间的时间并将结果保存在文本文件中。

我使用 python 绘制了数据我得到了这个:

水平轴以毫秒为单位表示帧时间。纵轴表示自上一帧以来经过的时间。也以毫秒为单位。

如您所见,帧之间的时间非常不规则,并且存在周期性尖峰(尖峰之间大约 1 秒)。

我已将 CMake 项目上传到 github repository,因此您可以根据需要对其进行测试。

我已使用集成 GPU 和专用 GPU(Intel 530HD 和 NVIDIA GTX 960M)进行了测试。

SDL 版本是 2.0.5。

我在 Windows 10 和 Ubuntu 16.04 LTS 上对其进行了测试。

编辑: 我已经将应用程序移植到 GLFW 并且发生了同样的情况。因此,SDL 中不太可能存在错误。我已经相应地更新了 git repo,现在有两个 CMake 项目。

EDIT2: 我已经在另一台计算机上对其进行了测试,并且工作正常。 我不知道发生了什么。会不会是硬件问题?那为什么我运行其他应用程序时没有发生呢?

驱动问题?不太可能,因为它同时使用 Intel 和 NVIDIA GPU。此外,它发生在 Ubuntu 和 Windows 上。

【问题讨论】:

似乎每秒都是尖峰。也许您的计算机上正在运行另一个进程,该进程每秒唤醒并占用所有 CPU 时间。您是否在另一台计算机上尝试过您的程序? 对不起,我忘了提到操作系统和版本。我会更新问题 @BrunoLevy 我没有在其他计算机上尝试过,但我尝试在同一台计算机上安装了两个不同的操作系统。我会试着找另一台电脑测试一下。 这是在笔记本电脑上吗? 切换到while(SDL_PollEvent(&amp;event)) 有帮助吗?现在,您正在每帧出列一个事件。 【参考方案1】:

由于 CPU 过热,我也遇到过类似的行为(尽管有更长和更低的平台期,而不是尖峰),因此决定暂时降低时钟频率。如果您的 PC 发生这种情况,您可以尝试升级内部冷却器或添加外部冷却器。或者只是降低房间空调的温度设置。

当然,这在夏天总是更成问题。

Here's where I've posted about it.

【讨论】:

这很有趣。在我提供的代码中,循环完全不受限制,因此它确实会导致过热。我尝试添加“SDL_Delay(10)”(最多 100 fps),所以过热应该不是问题。尖峰仍然存在 (img)。感谢您的建议。 @user1754322:当我过热时,我开启了垂直同步,所以最多 60fps。 我也尝试过启用垂直同步,结果也是一样。我相信它并没有过热,毕竟我用过其他交互式应用程序没有问题。一个根本不做任何工作的循环(99% 的时间是中间的)过热而其他应用程序没有,这是没有意义的。除此之外,这是一台游戏笔记本电脑。谢谢

以上是关于SDL + OpenGL,具有周期性尖峰的不规则帧时间的主要内容,如果未能解决你的问题,请参考以下文章

OSX OpenGL 深度模板组合

使用 SDL2 指定 OpenGL 版本

SDL2:如何同时拥有 SDL2 菜单和 OpenGL 上下文?

SDL2和3D渲染

OpenGL ES 直接到控制台帧缓冲区

如何使用 OpenGL 在 SDL 中获得正确的 SourceOver alpha 合成