【问题标题】:SDL_PollEvent() stuttering while idle?SDL_PollEvent() 空闲时口吃?
【发布时间】:2023-04-10 22:25:01
【问题描述】:

我使用 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。那是我的延迟:

使用垂直同步。请注意,滞后后的增量略短。不知道为什么:

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

编辑 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 移动我的增量分配。

示例 sn-p:

    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 后,控制台输出如下:

编辑 4:更多数据。看起来口吃几乎每 3000 毫秒发生一次。我的控制台输出只有 > 50 毫秒的增量。图像格式为:# of game loop cycles |增量时间 | SDL_GetTicks()

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

编辑 5:看起来滞后与 USB 设备有关。 SDL 是否每 3000 毫秒或其他时间查找所有设备?

将 GPU 放回我的机器后,我注意到延迟显着下降,并且我注意到与之前和之后的唯一区别是我的 USB 耳机不再插入。

凭直觉,我再次运行了我的循环,这次是观察任何超过 3 毫秒的 deltaTime。我在移除设备时观察了控制台的变化:

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

所以当前的问题是:USB 设备是如何导致这种卡顿的?与 (a) USB 设备和 (b) SDL_RenderPresent() 相关的每 3000 毫秒 SDL 会做什么?

【问题讨论】:

  • 是什么让你认为是 PollEvent 导致口吃,而不是例如渲染现在?您能否制作其他人可以在他们的机器上验证的最小完整示例(并将其编辑到问题中)?您确定不是 printf/cout 导致您的速度变慢吗?
  • 我将我的 deltaTime 计时器移动到仅围绕 SDL_PollEvent 循环,并得到了与控制台类似的结果。当我移动计时器以排除 SDL_PollEvent 循环时,控制台显示稳定的增量,但我仍然口吃。我会尝试把我拥有的东西放在一起并更新。
  • @keltar 问题已更新为请求的代码。
  • 如果你全屏(比如正确的SDL_WINDOW_FULLSCREEN mode-change 全屏,而不是桌面大小的无边框窗口)而不是窗口,会有什么变化吗?
  • 没有针对不同窗口类型的更改,但我将用一些曲线球来更新帖子。看起来它与 USB 设备有关。

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


【解决方案1】:

我仍然不确定究竟是什么导致了问题,但它肯定与 USB 设备有关。插入的设备越多,延迟峰值就越长,并且几乎每 3000 毫秒发生一次。

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

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

【讨论】:

  • 我建议提交回归错误报告。
  • bugzilla.libsdl.org/show_bug.cgi?id=4417 对于那些在家里跟随的人。
  • @genpfault 这个修复似乎解决了这个问题。我会把它添加到答案中。
  • 这和插入USB设备的数量有关?!怎么回事?这让我发疯了很长一段时间。切换了语言和游戏库,这一直在发生。非常感谢您缩小了这个问题的范围!
  • 今晚我以为我在调试奇怪的口吃几个小时几乎要发疯了。从 v2.0.9 恢复到 v2.0.7,问题也停止了。他们确实需要发布 v2.0.10,其中包含您的操纵杆轮询修复程序。
猜你喜欢
  • 2015-01-03
  • 2022-12-16
  • 1970-01-01
  • 2021-07-19
  • 1970-01-01
  • 2012-08-09
  • 2011-01-31
  • 1970-01-01
相关资源
最近更新 更多