The conviction was empirical, not theoretical: a new write-site trap
(BT_PLANE_AUDIT) in the seven L4VB16 drawing primitives logs any draw whose
color carries bits outside its port's plane mask -- the exact cross-display
corruption condition (Replace ORs an unmasked color; Or/Xor ignore the mask
entirely; And clears foreign planes). A quiet solo session produced 15-30
leaks per minute:
[plane] PORT 'sec' pixmap draw at(0,0) idx 217 entry=0xffffff00 mask=0x3f
[plane] LEAK DrawPixelMap8[table] at(639,0) color=0xffffff00 mask=0x3f leak=0xff00
THE DEFECT: L4GraphicsPort::translationTable[256] is never initialized in the
ctor, and BuildSecondaryTranslation fills only the entries its BitWrangler
reaches -- 2^numberOfBits: 64 for the sec plane (mask 0x3F), 4 for the overlay
(0xC0). Entries above that stay heap garbage. Every draw resolves color
through this table, and the PIXMAP path indexes it with raw pixel values
0..255: the 480x640 radar background carries pixel index 217, whose garbage
entry's high bits (0xFF00 = ALL EIGHT MFD planes) were stamped into the shared
640x480 buffer -- invisible on the culprit page (the in-plane bits happened
dark) and visible as bright fragments at the same coordinates on every OTHER
display. That is the operator's screenshot exactly: the same-position blips
on Mfd1+Mfd2 and the Heat-display block.
FIX (engine, both layers):
* zero translationTable in the L4GraphicsPort ctor (plane-neutral default);
* BuildSecondaryTranslation now cycles the in-plane pattern across entries
[2^bits..255] -- high-index art degrades to its (index mod 2^bits) colour
IN-PLANE and can never leak. The 1995 binary ships the SAME 64-entry fill
and survived on 6-bit art discipline; garbage is not a preservable
behaviour, so the cycle-fill is a guarded PORT deviation (documented).
A/B PROOF: same probe, 60s -- 0 leaks after the fix (15-30/min before).
sim3 3-pod regression: zero crashes.
SECOND real defect found + fixed en route: sessions configure the CAMERA seat
first ("cameraInit" -- which includes the MISSION-REVIEW context:
configure(0, sec, 0, 0x00FF, native, rgb, mrpal.pcc), a DirectColor context
whose translation tables legitimately hold full RGB565 values spanning all 16
plane bits), and the viewpoint swap to the mech re-configured WITHOUT tearing
that tree down (btl4app's s_gaugeTreeBuilt latch treats the mech build as the
first). The orphaned review gauges kept executing through stale DirectColor
ports. BTL4GaugeRenderer::ConfigureForModel now overrides (ConfigureForModel
made virtual in L4GREND.h) and tears the prior entity-bound tree down before
every rebuild -- safe on first build, and the review screen rebuilds the same
way when the seat returns to the camera.
Also logged (open-questions): the review-screen PlayerStatus panels read the
compiled player at RAW BINARY OFFSETS (+0x1FC vehicle / +0x1C8 score /
+0x1C4 alive-dead box) -- the databinding trap, dormant until the review
screen runs; bridge before enabling the review.
Ruled out along the way (with evidence): the pilot-list label/erase geometry
(erase box 128x32 covers the 64x16 name rasters), the radar name labels
(view-level ClipImage clips them), PlayerStatus in-game execution ([ps] probe:
never runs in-game), and the PNAME bitmap dimensions (egg generator emits
64x16 exactly).
Why it "started with the comms feature" (#43): that wave registered the new
gauge classes with the config interpreter, letting more of the authored page
furniture parse and draw than before -- the leaking high-index pixmaps rode in
with it. [T3 correlation detail; the leak + fix are T2 live-verified.]
Diagnostics kept (env-gated): BT_PLANE_AUDIT (the leak trap, now a permanent
regression tripwire), BT_PS_LOG, the port-level pixmap identity trap.
KB: gauges-hud.md (#48 section), decomp-reference.md (BT_PLANE_AUDIT),
open-questions.md (PlayerStatus databinding entry). checkctx CLEAN.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
94 lines
4.0 KiB
C++
94 lines
4.0 KiB
C++
//===========================================================================//
|
|
// File: btl4grnd.hpp //
|
|
// Project: BattleTech Brick: Gauge Renderer Manager //
|
|
// Contents: //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 02/13/95 CPB Initial coding. //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1994, Virtual World Entertainment, Inc. All rights reserved //
|
|
// PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
//
|
|
// SURVIVING HEADER (ground truth -- reproduced verbatim from
|
|
// 410SRC/.../BT_L4/BTL4GRND.HPP). Only the File:/Brick: banner above was
|
|
// corrected from the original (which carried a stale "rpl4grnd.hh" copy of
|
|
// the Red Planet sibling's comment). The class declaration is unchanged.
|
|
//
|
|
// Implementation reconstructed in btl4grnd.cpp from the shipped binary:
|
|
// BTL4GaugeRenderer ctor @004cbea0 (vtable 0051cebc)
|
|
// ~BTL4GaugeRenderer @004cbf40 (vtable slot 0)
|
|
// TestInstance @004cbf90
|
|
// NotifyOfNewInterestingEntity @004cbfa0 (vtable slot 9)
|
|
// NotifyOfBecomingUninterestingEntity @004cc028 (vtable slot 10)
|
|
//
|
|
|
|
#if !defined(BTL4GRND_HPP)
|
|
# define BTL4GRND_HPP
|
|
|
|
# if !defined(L4GREND_HPP)
|
|
# include <l4grend.hpp>
|
|
# endif
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~ BTL4GaugeRenderer ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
class BTL4GaugeRenderer:
|
|
public L4GaugeRenderer
|
|
{
|
|
public:
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Construction, Destruction, Testing
|
|
//--------------------------------------------------------------------
|
|
//
|
|
BTL4GaugeRenderer();
|
|
~BTL4GaugeRenderer();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
void
|
|
NotifyOfNewInterestingEntity(Entity *entity);
|
|
void
|
|
NotifyOfBecomingUninterestingEntity(Entity *entity);
|
|
|
|
//
|
|
// PORT FIX (Gitea #12 -- NOT in the surviving 1995 header): tear the
|
|
// built gauge tree down when the viewpoint mech is RE-STREAMED
|
|
// in-session (pre-launch host drop/rejoin re-creates every mech; the
|
|
// lobby-built tree's attribute pointers dangle and each widget is
|
|
// permanently DISABLED by the BT_DEV_GAUGES SEH guard, GAUGE.cpp:618).
|
|
// Performs the entity-bound half of the engine's mission-transition
|
|
// teardown (GaugeRenderer::ShutdownImplementation, GAUGREND.cpp:3264):
|
|
// alarms + all gauges + the entity grids. Warehouse / graphics ports /
|
|
// interpreter / controls lamps stay -- entity-independent, reused by
|
|
// the immediate ConfigureForModel rebuild. Called from
|
|
// BTL4Application::MakeViewpointEntity before ConfigureForModel;
|
|
// a no-op on the first (lobby) build.
|
|
//
|
|
void
|
|
TearDownForViewpointRestream();
|
|
|
|
// Gitea #48 (THE MFD-ARTIFACT ROOT CAUSE): tear the previous
|
|
// configuration's gauge tree down on EVERY viewpoint configure, then
|
|
// build. The camera seat configures first (`cameraInit` -- which
|
|
// includes the MISSION-REVIEW ports: `configure(0, sec, 0, 0x00FF,
|
|
// native, rgb, mrpal.pcc)` -- a DirectColor context whose translation
|
|
// tables hold full RGB565 values spanning ALL 16 plane bits); the swap
|
|
// to the mech re-configures WITHOUT tearing that tree down (the
|
|
// btl4app latch treats the mech build as "first"), so the review
|
|
// gauges kept executing through their orphaned DirectColor ports and
|
|
// every draw stamped pixels into EVERY display's plane -- the "stray
|
|
// blocks / misplaced lamps" on Heat/Mfd/sec. Convicted live by the
|
|
// BT_PLANE_AUDIT write trap: pixmap draws with mask 0x3F/0xC0 leaking
|
|
// 0xFF00/0x3F at the review furniture positions.
|
|
virtual void
|
|
ConfigureForModel(const char *configuration_name, Entity *entity);
|
|
};
|
|
|
|
|
|
#endif
|