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) <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-08-05 22:45:23 -05:00
co-authored by Claude Opus 5
parent f4fef29428
commit 6ce729bab5
2 changed files with 85 additions and 0 deletions
+77
View File
@@ -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