From b2b7a45b5c01793c615e3d934ca395a9b56d91d2 Mon Sep 17 00:00:00 2001 From: arcattack Date: Fri, 24 Jul 2026 09:57:06 -0500 Subject: [PATCH] Issues #39 + #40: gate input until the scene presents; cap the wait-screen idle loop #39 (field: 'I was able to input before the game screen actually came up -- fired weapons, moving, could hear the audio'): the simulation runs during load/wait and PadRIO fed it live input. Poll now emits only the analog heartbeat until gBTSceneHasPresented -- keyboard, pad and joystick all stand down; edge state stays parked so keys held across the boundary press cleanly at first frame. BT_BTNTEST and the panel-click seam stay live (event injection, same as before). #40 (field: 'GPU usage during waiting screen is sometimes consuming up to 45-50%'): ExecuteIdle Cleared+Presented uncapped for the whole join wait. Now capped at ~40 Hz with a 5 ms sleep on skipped passes (the overlay's change gate is 12.5 Hz -- nothing visible changes faster). Regression: 2-node relay round through the wait screen -> load -> mission (135 in-mission ticks, autofire) -> clean. Awaiting the reporter's live confirm on both. Co-Authored-By: Claude Opus 4.8 (1M context) --- engine/MUNGA_L4/L4PADRIO.cpp | 22 ++++++++++++++++++++++ engine/MUNGA_L4/L4VIDEO.cpp | 16 ++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/engine/MUNGA_L4/L4PADRIO.cpp b/engine/MUNGA_L4/L4PADRIO.cpp index 859d97f..be318fb 100644 --- a/engine/MUNGA_L4/L4PADRIO.cpp +++ b/engine/MUNGA_L4/L4PADRIO.cpp @@ -403,6 +403,28 @@ void } lastPollMilliseconds = now; + // + // Issue #39 (field 2026-07-23): the simulation runs during load/wait, + // so a player could fire, walk and hear it all BEFORE the first frame + // presented ("I was able to input before the game screen came up"). + // Until the scene is live, emit only the analog heartbeat -- keyboard, + // pad and joystick reads all stand down (edge state stays parked, so + // keys held across the boundary press cleanly at first frame). The + // scripted BT_BTNTEST harness above stays live (it injects through the + // event seam, same as the on-screen panel clicks). + // + { + extern Logical gBTSceneHasPresented; + if (!gBTSceneHasPresented) + { + RIOEvent analog; + analog.Type = AnalogEvent; + analog.Data.Unit = 0; + PushEvent(analog); + return; + } + } + // //----------------------------------------------------------------- // XInput: hot-plug probe every ~3 s, then read the connected pad. diff --git a/engine/MUNGA_L4/L4VIDEO.cpp b/engine/MUNGA_L4/L4VIDEO.cpp index 8886bb8..68a8204 100644 --- a/engine/MUNGA_L4/L4VIDEO.cpp +++ b/engine/MUNGA_L4/L4VIDEO.cpp @@ -8917,6 +8917,22 @@ void DPLRenderer::ExecuteIdle() if (gBTSceneHasPresented) return; // game graphics own the screen now + + // Issue #40 (wait screen burned 45-50% GPU, field 2026-07-23): the idle + // loop Cleared+Presented at an UNCAPPED rate for the whole join wait. + // Cap it at ~40 Hz -- the overlay's own change gate runs at 12.5 Hz, so + // nothing visible changes faster than that anyway. The 5 ms sleep also + // keeps the caller's spin off a CPU core. + { + static unsigned long s_lastIdlePresent = 0; + unsigned long now = GetTickCount(); + if (now - s_lastIdlePresent < 25UL) + { + Sleep(5); + return; + } + s_lastIdlePresent = now; + } { static unsigned long s_lastIdleLog = 0; unsigned long now = GetTickCount();