SDL_PollEvent()在空闲时口吃?

时间:2018-12-06 04:21:29

标签: c++ sdl game-engine sdl-2

我已经使用SDL2整理了C ++中一个非常基本的游戏循环,我注意到每隔几秒钟,即使什么也没发生,SDL_PollEvent似乎异常缓慢。

我将deltaTime发送到控制台的每个循环中,在SDL_PollEvent滞后的周期上,它差了大约100毫秒。我已经通过移动定时器确认了此功能,但是我不确定在哪里可以进一步诊断问题。

我的循环:

while (!quit) {

    uint32_t startTime = SDL_GetTicks();

    while (SDL_PollEvent(&e) != 0) {
    std::cout << "Event: "<< e.type << std::endl; // Added later, read update
        if (e.type == SDL_QUIT) {
            quit = true;
        }
    }

    if (engine.AllowUpdate()) { // Restricts updates to every 20ms
        GameState::Update(); 
    }


    engine.rMan.BeginRender();
    //^v Literally just SDL_RenderClear and SDL_RenderPresent
    engine.rMan.FinishRender();

    engine.deltaTime = SDL_GetTicks() - startTime;
    std::cout << std::setw(10) << engine.deltaTime;
}

没有Vsync的控制台输出,请注意106。这是我的滞后:No Vsync console output

使用Vsync。请注意,滞后之后的增量要短一些。不知道为什么:Vsync console output

我还注意到,即使我没有调试,此问题也会发生,并且至少在另一台计算机上不存在。任何有关如何进行的建议都将受到欢迎。

编辑1:试图打印以控制台所有正在通过队列的事件,以查看是否其中一个引起了问题。在上面的代码中添加了打印行。在出现延迟的时候似乎没有发生任何事情,否则我就处于闲置状态。

编辑2:根据要求,一些可运行的代码,在带有SDL2-2.0.9的VS2017上使用c ++ 14构建:

#include <iostream>
#include <SDL.h>

void InitSDL();
void BuildWindow();
void BuildRenderer();

SDL_Window* window;
SDL_Renderer* renderer;

int main(int argc, char* args[]) {
    InitSDL();
    BuildWindow();
    BuildRenderer();
    bool quit = false;

    uint32_t deltaTime = 0;

    while (!quit) {
        uint32_t startTime = SDL_GetTicks();

        SDL_Event e;
        while (SDL_PollEvent(&e) != 0) {
            if (e.type == SDL_QUIT) {
                quit = true;
            }
        }
        deltaTime = SDL_GetTicks() - startTime;
        std::cout << deltaTime << std::endl;

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);
        SDL_RenderPresent(renderer);
    }

    return 0;
}

void InitSDL() {
    Uint32 flags = SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS;
    SDL_Init(flags);
}

void BuildWindow() {
    window = SDL_CreateWindow
    ("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        800, 600, NULL);
}

void BuildRenderer() {
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
}

放在一起时,我注意到了几件事:

<罢工> 1。没有SDL_RenderPresent ,就不会发生口吃。经过仔细检查后,情况似乎并非如此,但是SDL_RenderPresent似乎受到了口吃的影响。

  1. 在SDL_PollEvent期间某处出现了与口吃相吻合的deltaTime的增加,这可以从deltaTime的分配位置得到证明

  2. 第一个deltaTime总是更长,尽管我怀疑这与启动时触发的一些默认事件有关。

编辑3:多进行一些挖掘。尝试仅在SDL_RenderPresent周围移动我的增量分配。

示例片段:

    SDL_Event e;
    while (SDL_PollEvent(&e) != 0) {
        std::cout << "Event: "<< e.type << std::endl;
        if (e.type == SDL_QUIT) {
            quit = true;
        }
    }

    uint32_t startTime = SDL_GetTicks();
    //SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    //SDL_RenderClear(renderer);
    SDL_RenderPresent(renderer);
    deltaTime = SDL_GetTicks() - startTime;
    std::cout << deltaTime << std::endl;

启用vsync后,获得以下控制台输出:Console output vsync delta on render

编辑4:更多数据。好像断断续续地每3000ms发生一次。我的控制台输出的增量仅> 50ms。图片格式为:游戏循环次数| deltaTime | SDL_GetTicks() just bad deltas

我还考虑到这是一个硬件问题,因为我在另一台计算机上没有这个问题,并且我还下载了其他一些开源SDL游戏,并且遇到了相同的断断续续的情况,相距3000毫秒。我还在Windows 10和Windows 7的相同硬件上看到相同的问题。除非有人认为有必要,否则我不会发布我的规格,但是我已经通过看到相同的问题消除了专用GPU出现故障的可能性在移除我的GPU的情况下通过RDP运行游戏时的确切问题。

编辑5:滞后似乎与USB设备有关。 SDL是否每隔3000ms或所有时间对所有设备进行一次查找?

将GPU重新放回机器后,我发现时滞大大减少了,并且发现与之前和之后的唯一区别是不再插入USB耳机。

直觉上,我再次运行我的循环,这次是在3ms内观察任何deltaTime。移除设备时,我看着控制台进行了更改: USB device impact

尤里卡!有点。没有插入USB设备,deltaTime始终保持在3ms以下。我测试的第二台计算机是一台笔记本电脑,因此没有插入USB设备。我回去,并使用相同的USB鼠标对其进行了测试,正如预期的那样,每隔3000毫秒我看到一个明显的断续。

因此,当前的问题是:USB设备如何引起这种卡顿?与(a)USB设备和(b)SDL_RenderPresent()相关的SDL每隔3000毫秒做什么?

1 个答案:

答案 0 :(得分:9)

我仍然不确定到底是什么引起了这个问题,但是这肯定与USB设备有关。插入的设备越多,延迟峰值就越长,并且几乎每隔3000ms就会发生一次。

我从SDL2-2.0.9回滚到SDL2-2.0.8,问题已停止。

编辑:在https://hg.libsdl.org/SDL/rev/9091b20040cf找到的变更集似乎可以解决SDL2-2.0.9中的此问题。