From 6ce729bab5bab89ba397fdb5828ff96cc0b447eb Mon Sep 17 00:00:00 2001 From: Cyd Date: Wed, 5 Aug 2026 22:45:23 -0500 Subject: [PATCH] Lit cockpit buttons keep up with the sim BT411's f99003c, brought across. Its playtesters reported the cockpit lighting going slow or stopping altogether while the 3D view stayed smooth, and RP412 has the same structure exactly: the on-screen vRIO buttons light themselves from PadRIO::GetLampState, but what FILLS that store is lampManager->Update() in GaugeRenderer::ExecuteForeground - once per full gauge cycle. Which is the cycle the previous commit was about. Measured on a starved frame budget it now completes 3.1 times a second, and completed 0.7 times a second before that; either way far too slow to carry a flashing lamp. So sweep the lamps once per frame from the main render instead, which runs regardless of how little frame is left over. It is cheap, and AssertNewLampValue already drops anything unchanged, so this pushes no extra traffic - it only stops changes arriving late. Only when a PadRIO is active, i.e. cockpit-less play, and only while a mission is actually running. With real serial hardware selected the pod keeps its authentic bandwidth-paced cadence, untouched. RP412LAMPSWEEP=0 restores the once-per-cycle behaviour. BT411's other half, 02ce9f5, does not apply. That one is about Windows throttling WM_TIMER and paint messages for background windows, which made the glass panels' flash crawl whenever they did not have focus. RP412 has no timer-driven repaint anywhere - the MFD windows are D3D devices presented from SVGA16::Update, and the panel strips repaint from there too - so there is no throttled message path to bypass. That path was starved rather than throttled, and the previous commit is the fix. Verified: no regression at either budget, 20.0 display sweeps/s at a normal frame budget and 3.1/s starved, both unchanged by this commit; mission runs clean. The lamp win itself is structural - the sweep is now an unconditional per-frame call - and would want a busy multiplayer mission to see directly. Co-Authored-By: Claude Opus 5 (1M context) --- MUNGA_L4/L4VIDEO.cpp | 77 +++++++++++++++++++++++++++++++++++++++++++ RP_L4/RPL4ENVIRON.cpp | 8 +++++ 2 files changed, 85 insertions(+) diff --git a/MUNGA_L4/L4VIDEO.cpp b/MUNGA_L4/L4VIDEO.cpp index 4bb91ce..8c07e6f 100644 --- a/MUNGA_L4/L4VIDEO.cpp +++ b/MUNGA_L4/L4VIDEO.cpp @@ -17,6 +17,10 @@ #include "..\munga\nttmgr.h" #include "..\munga\app.h" #include "l4particles.h" +#include "l4padrio.h" // PadRIO::IsActive, for the per-frame lamp sweep +#include "..\munga\gaugrend.h" +#include "..\munga\lamp.h" +#include "..\munga\mode.h" #include "DXUtils.h" using namespace std; @@ -5983,11 +5987,84 @@ void //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Execute Method, performs the rendering of one frame // +// +//=========================================================================== +// RPSweepCockpitLamps +// +// Push the cockpit lamp STATE once per frame, instead of once per gauge +// cycle. +// +// The on-screen vRIO buttons light themselves from PadRIO::GetLampState, +// and they redraw with their MFD strip. What FILLS that store is +// LampManager::Update -> AssertNewLampValue -> SetLamp, and that rides +// the gauge renderer's FOREGROUND turn - which comes round only once per +// full gauge cycle. On a busy map the cycle takes the best part of a +// second, so the lit buttons froze and any flash stalled while the 3D +// view, a separate per-frame render, stayed perfectly smooth. BT411 saw +// the same thing on its glass surround and fixed it the same way. +// +// It is cheap: a sweep over the lamps, no raster, and AssertNewLampValue +// already drops anything that has not changed - so this pushes no extra +// traffic, it only stops changes arriving late. +// +// Only when a PadRIO is active, i.e. cockpit-less play. With real serial +// hardware selected the pod keeps its authentic bandwidth-paced cadence, +// untouched. RP412LAMPSWEEP=0 restores the once-per-cycle behaviour. +//=========================================================================== +// +static void + RPSweepCockpitLamps() +{ + static int + enabled = -1; + + if (enabled < 0) + { + const char + *setting = getenv("RP412LAMPSWEEP"); + + enabled = (setting != NULL && setting[0] == '0') ? 0 : 1; + } + if (!enabled || !PadRIO::IsActive() || application == NULL) + { + return; + } + + // + // Only while a mission is actually running. This is called from the + // top of the frame, ahead of the state switch below, so it would + // otherwise fire while the mission is still being built and the + // gauges do not exist yet. + // + if (application->GetApplicationState() != Application::RunningMission) + { + return; + } + + GaugeRenderer + *renderer = application->GetGaugeRenderer(); + ModeManager + *modes = application->GetModeManager(); + + if (renderer != NULL && modes != NULL) + { + LampManager + *lamps = renderer->GetLampManager(); + + if (lamps != NULL) + { + lamps->Update(modes->GetModeMask()); + } + } +} + void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::InterestingEntityIterator* all_iterator) { Component *component; HRESULT hr; + RPSweepCockpitLamps(); // keep the lit buttons tracking the sim (see above) + // timing variables __int64 ticks = HiResNowTicks(); #ifdef LOGFRAMERATE diff --git a/RP_L4/RPL4ENVIRON.cpp b/RP_L4/RPL4ENVIRON.cpp index 724cea9..47a4e96 100644 --- a/RP_L4/RPL4ENVIRON.cpp +++ b/RP_L4/RPL4ENVIRON.cpp @@ -201,6 +201,14 @@ namespace "# has stopped refreshing from one whose picture simply is not changing.\n" "#RP412GAUGEDIAG=1\n" "\n" +"# 0 = light the on-screen cockpit buttons on the same slow cadence the\n" +"# arcade pod's serial hardware used. The lamp state is filled once per\n" +"# gauge cycle, so under the load described above the lit buttons froze\n" +"# and flashing ones stalled while the 3D view stayed perfectly smooth.\n" +"# On by default: the buttons are refreshed every frame instead. Ignored\n" +"# when real RIO hardware is selected - the pod keeps its own cadence.\n" +"#RP412LAMPSWEEP=0\n" +"\n" "# 1 = Steam networking (lobbies, FakeIP mesh). Needs the Steam client\n" "# running and steam_appid.txt beside the exe; without them the game\n" "# logs the reason and falls back to plain TCP. 0 = TCP only.\n"