Question

WIN32 game loop is slow, can't handle 60HZ or 30HZ. What to do?

I'm just trying to learn to program a few things, and a game loop is one of those.

This game loop only process Windows messages, but it can not even handle 30 fps.

This is true also if the message processing is done only once per loop, replacing WHILE with IF.

I use QueryPerformanceCounter() function to get number of 100ns ticks before work is done and after, subtracting them to get time used. Loop time is 100ns * 166666 * 2 = 0.0333332s.

The boolean 'timeExceeded' is set if the the wait time is positive, indicating that time used is more than the intended loop time.

What to do?

#include <Windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    // windows class information
    static const wchar_t class_name[] = L"Test";
    WNDCLASS wc{ };
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = class_name;
    if (!RegisterClassW(&wc))
        return 0;

    // Get correct windows size based on disered client area
    RECT client_rect;
    client_rect.left = 0;
    client_rect.top = 0;
    client_rect.right = 800;
    client_rect.bottom = 600;
    if (!AdjustWindowRect(&client_rect, WS_OVERLAPPEDWINDOW, FALSE))
        return 0;

    // create windows
    HWND hwnd = CreateWindowEx(
        WS_EX_OVERLAPPEDWINDOW, class_name, L"Test",
        WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED,
        100, 100, -client_rect.left + client_rect.right, -client_rect.top + client_rect.bottom,
        0, 0, hInstance, 0
    );
    if (hwnd == 0)
        return 0;



    // Show Window
    ShowWindow(hwnd, SW_SHOWNORMAL);

    // Timer & setup
    LARGE_INTEGER frequency;
    if (!QueryPerformanceFrequency(&frequency))
        return 0;
    if (frequency.QuadPart != 10000000LL)
        return 0;

    HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
    if (hTimer == 0)
        return 0;


    // timer data
    LARGE_INTEGER start_time;
    LARGE_INTEGER end_time;
    LARGE_INTEGER rest_time;
    LARGE_INTEGER loop_time;
    loop_time.QuadPart = -166666LL*2;   // loop time

    bool timeExceeded = false;      // does time exceeds loop time


    // message loop data
    MSG msg = { };
    bool running = true;

    while (running)
    {
        // measure time
        if (!QueryPerformanceCounter(&start_time))
            break;

        // process messages
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                running = false;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        // other work

        // Get elapsed time and wait for 30hz - elapsed time
        if (!QueryPerformanceCounter(&end_time))
            break;

        rest_time.QuadPart = loop_time.QuadPart + (end_time.QuadPart - start_time.QuadPart);
        if (rest_time.QuadPart >= 0)
        {
            timeExceeded = true;
            continue;
        }
        if (!SetWaitableTimer(hTimer, &rest_time, 0, 0, 0, 0))
            break;

        if (WaitForSingleObject(hTimer, INFINITE) != 0)
            break;
    }

    // clean up
    CloseHandle(hTimer);
    
    return 0;
}



LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
 4  195  4
1 Jan 1970