From 7df82e4fee4204513615864b1a0c337959427589 Mon Sep 17 00:00:00 2001 From: catbot Date: Thu, 18 Jun 2026 14:00:58 +0000 Subject: [PATCH] perf(window): block message loop while paused on Win32 (#134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `updating` is false (paused / minimized / stopped), the FIFO present no longer paces StartSync()'s message loop, so the bare PeekMessage(PM_REMOVE) spin pinned a core at 100% while uselessly re-running Gamepad::Tick() (mutex + per-pad COM reads) and onBeforeUpdate every iteration. Block on MsgWaitForMultipleObjectsEx with a short timeout while !updating: the loop now wakes on input or every ~16ms, eliminating the busy-spin while preserving gamepad polling / onBeforeUpdate at a sane rate (e.g. to detect a controller button asking to resume). The updating path is unchanged — present remains vsync-gated. Co-Authored-By: Claude Opus 4.8 --- implementations/Crafter.Graphics-Window.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/implementations/Crafter.Graphics-Window.cpp b/implementations/Crafter.Graphics-Window.cpp index 19f1f55..3891db7 100644 --- a/implementations/Crafter.Graphics-Window.cpp +++ b/implementations/Crafter.Graphics-Window.cpp @@ -698,7 +698,20 @@ void Window::StartSync() { } #endif #ifdef CRAFTER_GRAPHICS_WINDOW_WIN32 + // While updating, the FIFO present inside Update() paces this loop to the + // vblank, so the PeekMessage poll is vsync-gated. While NOT updating + // (paused / minimized / stopped) nothing throttles the loop, and a bare + // PeekMessage(PM_REMOVE) spin pins a core at 100% while uselessly re-running + // Gamepad::Tick() (mutex + per-pad COM reads) and onBeforeUpdate every + // iteration. Block on the message queue instead, waking on input or after a + // short timeout so gamepad polling / onBeforeUpdate still tick at a sane + // rate (e.g. to detect a controller button asking to resume). + constexpr DWORD kPausedPollIntervalMs = 16; while(open) { + if (!updating) { + MsgWaitForMultipleObjectsEx(0, nullptr, kPausedPollIntervalMs, + QS_ALLINPUT, MWMO_INPUTAVAILABLE); + } MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg);