Synchronizing a Game Loop to a desired number of ticks per second with the WIN32 API

371 Views Asked by At

I want to write a Game Loop and measure the time it took to render. At the end of the loop I want the Thread to sleep for a certain amount of time to not exhaust the CPU. Currently I want to run the loop 60 times a second.

Here is the minimal example I came up with:

#include <iostream>
#include <Windows.h>

class Clock {
public:
    Clock() : m_Start(), m_Elapsed(0) {}

    double AbsoluteTime() {
        LARGE_INTEGER current_time;
        QueryPerformanceCounter(&current_time);

        LARGE_INTEGER frequency;
        QueryPerformanceFrequency(&frequency);

        return static_cast<double>(current_time.QuadPart) / frequency.QuadPart;
    }

    void Start() {
        m_Start = AbsoluteTime();
    }

    double GetElapsed() {
        double current_time = AbsoluteTime();

        m_Elapsed = current_time - m_Start;
        return m_Elapsed;
    }

private:
    double m_Start;
    double m_Elapsed;
};

int main() {
    Clock clock;
    Clock fpsClock;
    int frameCount = 0;

    while (true) {
        clock.Start();

        // Do some rendering stuff....

        double elapsed = clock.GetElapsed();
        double delay = (1.0 / 60.0) - elapsed;

        if (delay > 0) {
            Sleep(static_cast<DWORD>(delay * 1000));
        }

        frameCount++;

        if (fpsClock.GetElapsed() > 1.0) {
            std::cout << "FPS: " << frameCount << std::endl;
            fpsClock.Start();
            frameCount = 0;
        }
    }

    return 0;
}

However when executing this code all I get is 33 Frames printing every second. I am really not sure why this happens. If I dont use the Sleep method at all I get over 4600 frames a second. So it cant be a performance issue. Has anybody has encountered this before or knows how to fix it?

2

There are 2 best solutions below

0
Damir Tenishev On

The Sleep function has limited resolution:

The system clock "ticks" at a constant rate. If dwMilliseconds is less than the resolution of the system clock, the thread may sleep for less than the specified length of time. If dwMilliseconds is greater than one tick but less than two, the wait can be anywhere between one and two ticks, and so on. To increase the accuracy of the sleep interval, call the timeGetDevCaps function to determine the supported minimum timer resolution and the timeBeginPeriod function to set the timer resolution to its minimum. Use caution when calling timeBeginPeriod, as frequent calls can significantly affect the system clock, system power usage, and the scheduler.

I would recommend to use SetWaitableTimer and SleepEx functions.

0
YangXiaoPo-MSFT On

The default resolution of Sleep is limited as they said. The program outputs between 33 and 35 FPS for me. After setting the minimum resolution with timeBeginPeriod, the program outputs between 60 and 62 FPS. It's important that Sleep is not designed for absolute timing.

enter image description here