Glass cockpit lamps: sweep every frame so lit buttons track the sim under load
Playtesters (all on the glass surround) reported the cockpit lighting sometimes going slow or nonexistent while the 3D view stayed perfectly smooth. The RIO serial/lamp stack is byte-identical to pod-proven Red Planet (diffed L4LAMP/L4RIO/L4SERIAL), so the wiring was fine -- the defect is the glass UPDATE CADENCE: The lit buttons draw every frame (BTDrawCockpitPanels, reading PadRIO::GetLampState), but the lamp STATE sweep that fills that store (LampManager::Update -> AssertNewLampValue -> SetLamp) rides the gauge renderer's FOREGROUND turn, which fires only once per full gauge cycle (foreground->background->copy). The cycle can't reach the next foreground turn until the throttled background gauge sweep drains the ~140-instrument active list -- and that background task starves under MP load (issue #45, "instruments freeze while fps stays healthy"). So the lamp sweep ran ~1x/second: buttons froze / flashes stalled while the view (a separate per-frame foreground render) stayed smooth. Fix: BTGlassSweepLamps() runs the lamp sweep EVERY frame on the dev/glass composite path (L4VB16.cpp, in BTDrawGaugeInset), decoupled from the gauge cycle. It is cheap -- deduped state pushes over ~72 lamps, no raster. The pod never enters BTDrawGaugeInset (real gauge hardware), so its authentic bandwidth-paced serial lamp cadence is untouched. BT_GLASS_LAMP_SWEEP=0 restores the authentic once-per-cycle behaviour. Verified: Release links clean (only the 40 tolerated /FORCE externals); glass surround boots and runs, lamp sweep pushes state (43 [lamp] pushes, buttons lit), ~60 fps, no crash. The under-load win is structural (the sweep is now an unconditional per-frame call); true MP-starvation repro needs multiple nodes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1284,6 +1284,47 @@ void BTCockpitMouseUp(void)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// (glass lamp responsiveness, 2026-08) Sweep the cockpit lamp STATE every frame.
|
||||
//
|
||||
// The lamp sweep -- LampManager::Update -> AssertNewLampValue -> RIO/PadRIO::SetLamp,
|
||||
// which is what lights the cockpit buttons -- authentically rides the gauge
|
||||
// renderer's FOREGROUND turn (GaugeRenderer::ExecuteForeground, gaugrend.cpp), and
|
||||
// that turn fires only ONCE PER FULL GAUGE CYCLE (foreground -> background -> copy).
|
||||
// The cycle only advances to the next foreground turn after the THROTTLED background
|
||||
// gauge sweep drains the whole active-instrument list -- and that background task
|
||||
// starves under load (issue #45: "every cockpit instrument freezes at its last paint
|
||||
// while the underlying values AND fps stay perfectly healthy"). So on a busy MP
|
||||
// mission the lamp sweep ran ~1x/second: the lit buttons froze / flashes stalled while
|
||||
// the 3D view (a separate per-frame foreground render) stayed smooth -- exactly the
|
||||
// "lighting slow or nonexistent" playtest reports (all on glass desktops).
|
||||
//
|
||||
// The lamp sweep is CHEAP -- deduped state pushes over ~72 lamps, no raster -- so on
|
||||
// the dev/glass composite path we run it EVERY frame here, decoupled from the gauge
|
||||
// cycle, and the buttons track the sim regardless of background-sweep slack. The pod
|
||||
// NEVER enters BTDrawGaugeInset (it drives real gauge hardware), so its authentic
|
||||
// bandwidth-paced serial lamp cadence is untouched. BT_GLASS_LAMP_SWEEP=0 restores the
|
||||
// authentic once-per-cycle behaviour.
|
||||
//
|
||||
static void
|
||||
BTGlassSweepLamps()
|
||||
{
|
||||
static int s_on = -1;
|
||||
if (s_on < 0)
|
||||
{
|
||||
const char *e = getenv("BT_GLASS_LAMP_SWEEP");
|
||||
s_on = (e != NULL && e[0] == '0') ? 0 : 1;
|
||||
}
|
||||
if (!s_on) return;
|
||||
|
||||
GaugeRenderer *gr = BTResolveGaugeRenderer();
|
||||
if (gr == NULL || application == NULL) return;
|
||||
LampManager *lm = gr->GetLampManager();
|
||||
ModeManager *mm = application->GetModeManager();
|
||||
if (lm != NULL && mm != NULL)
|
||||
lm->Update(mm->GetModeMask());
|
||||
}
|
||||
|
||||
//
|
||||
// Free entry point the MAIN renderer calls (L4VIDEO DPLRenderer::ExecuteImplementation,
|
||||
// just before EndScene). No-op unless BT_DEV_GAUGES is set. Docks the 6-surface panel
|
||||
@@ -1292,7 +1333,9 @@ void BTCockpitMouseUp(void)
|
||||
//
|
||||
void BTDrawGaugeInset(LPDIRECT3DDEVICE9 device)
|
||||
{
|
||||
if (!DevGaugeComposite() || !DevGaugeDocked() || device == NULL) return;
|
||||
if (!DevGaugeComposite()) return;
|
||||
BTGlassSweepLamps(); // keep the cockpit lamps tracking the sim EVERY frame (see above)
|
||||
if (!DevGaugeDocked() || device == NULL) return;
|
||||
if (GlassPanelsOwnSurfaces()) return; // the per-display glass windows draw the surfaces
|
||||
if (gBTGaugeCockpit)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user