Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SDL_PollEvent() stuttering while idle?

I've cobbled together a very basic game loop in C++ using SDL2, and I've noticed that every few seconds, SDL_PollEvent seems to be unusually slow, even when nothing is happening.

I sent my deltaTime to console every loop, and its about 100ms difference on the cycles that SDL_PollEvent is lagging. I've already confirmed that it's something with this function by moving my timers around, but I'm not sure where to diagnose the issue further.

My loop:

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;
}

Console output with no Vsync, note the 106. That's my lag:No Vsync console output

With Vsync. Note that the delta following the lag is slightly shorter. Not sure why:Vsync console output

I've also noticed that this issue happens even if I'm not debugging, and is not present on at least one other machine. Any suggestions on how to proceed would be very welcome.

EDIT 1: Tried to print to console all events that were going through the queue to see if one of them was causing the issue. Added the print line to the code above. No events seemed to be firing at the times that there was lag, and I was otherwise idle.

EDIT 2: As requested, some runnable code, built with c++14 on VS2017 with SDL2-2.0.9:

#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);
}

While putting this together, I noticed a few things:

1. The stutter did not occur without SDL_RenderPresent After double-checking, this does not appear to be the case, however, SDL_RenderPresent appears to be impacted by the stutter.

  1. The increase in deltaTime that coincides with the stutter appears to occur somewhere during SDL_PollEvent, as evidenced by where deltaTime is being assigned

  2. The first deltaTime is ALWAYS longer, though I suspect this has something to do with some default events firing on startup.

EDIT 3: Did a little more digging. Tried to move my delta assignment around just the SDL_RenderPresent.

Example snippet:

    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;

With vsync on, got the following console output:Console output vsync delta on render

EDIT 4: MORE DATA. Looks like the stutter is happening every 3000ms almost exactly. I had the console output just the deltas that were > 50ms. Format in image is: # of game loop cycles | deltaTime | SDL_GetTicks() just bad deltas

I've also considered that this is a hardware problem, since I'm not having this issue on another machine, and I've also downloaded a few other open source SDL games and am experiencing the same stutter, 3000ms apart. I am also seeing the same problem on the same hardware in both Windows 10 and Windows 7. Not going to post my specs unless someone thinks it's necessary, but I've already eliminated the possibility of my dedicated GPU being at fault by seeing the same exact issue when running the game through RDP with my GPU removed.

EDIT 5: Looks like the lag has something to do with USB devices. Does SDL do a lookup of all devices every 3000ms or something?

After putting my GPU back in my machine, I noticed the lag dropped significantly, and I noticed that the only difference from before and after was that my USB headset was no longer plugged in.

On a hunch, I ran my loop again, this time watching for any deltaTime over 3ms. I watched the console for changes as I removed devices: USB device impact

Eureka! Sort of. With no USB devices plugged in, deltaTime remained below 3ms consistently. The secondary machine I tested on was a laptop, and thus had no USB devices plugged in. I went back, and tested it with the same USB mouse, and as expected, I saw a noticeable stutter every 3000ms.

So the current question is: How can USB devices be causing this stuttering? What does SDL do every 3000ms that is related to (a) USB devices and (b) SDL_RenderPresent()?

like image 265
Aaron Schultheis Avatar asked Dec 06 '18 04:12

Aaron Schultheis


1 Answers

I'm still not sure exactly what is causing the problem, but it certainly has something to do with USB devices. The more devices plugged in, the longer the latency spike, and it occurs almost every 3000ms exactly.

I rolled back from SDL2-2.0.9 to SDL2-2.0.8, and the issue has stopped.

EDIT: Changeset found at https://hg.libsdl.org/SDL/rev/9091b20040cf appears to resolve this issue in SDL2-2.0.9.

like image 114
Aaron Schultheis Avatar answered Oct 21 '22 10:10

Aaron Schultheis