Search code examples
c++sdlgame-enginevsync

SDL/OpenGL game runs too fast on 144Hz screen; can't use vsync


This is how I handle the game loop:

while (running) {
    diff = duration_cast<milliseconds>(end - start).count();
    start = clock::now();

    dt = diff / (16.0);

    handleInput(); // get input
    update(dt); // game logic
    render(); // render game

    SDL_GL_SwapWindow(window); // swap frame buffer

    end = clock::now();
}

It is intended to be a fixed timestep game locked to 60FPS (it's a re-made emulation of an SNES game) however it runs on 144 timestep on my 144hz screen, making it far too fast. Vsync can't solve this, so what can?


Solution

  • Here is a quick example of how game loop can be implemented:

    int32_t tickInteval = 1000/FPS; // frequency in Hz to period in ms
    uint32_t lastUpdateTime = 0;
    int32_t deltaTime = 0;
    while (running) { // running condition
        uint32_t currentTime = SDL_GetTicks();
        deltaTime = currentTime - lastUpdateTime;
    
        int32_t timeToSleep = tickInteval - deltaTime;
        if(timeToSleep > 0)
        {
            SDL_Delay(timeToSleep); // energy saving
        }
    
        update(deltaTime); // game logic
        lastUpdateTime = currentTime;
    }
    

    I would recommend to look close on this topic.


    UPD.
    One might be concerned with uint32_t overflow. And yes it will overflow. After almost two months of uninterrupted run of the game (49.7 days to be precise). What will happen then? currentTime will be a very small positive integer, lastUpdateTime will be a very large positive integer. But the subtraction of two will not overflow no matter what. Moreover if the difference does not fit into int32_t it will be wrapped around modulo of UINT_MAX + 1 resulting in a small positive integer that will be the exact number of ticks these two values different (with regard to unsigned overflow of one).