diff --git a/restoration/source410/BT_L4/GAUGE-BLOCK.NOTES.md b/restoration/source410/BT_L4/GAUGE-BLOCK.NOTES.md index 6ffd0b04..af209788 100644 --- a/restoration/source410/BT_L4/GAUGE-BLOCK.NOTES.md +++ b/restoration/source410/BT_L4/GAUGE-BLOCK.NOTES.md @@ -1020,3 +1020,44 @@ correctly to 3/5/7). Suspect the tile/strip blit for VertTwoPartBar-family widgets writing tile pixel VALUES rather than using them as a mask with the port colour -- the same widget draws correctly on the MFD heads, so it is specific to this port or this call site. + +-------------------------------------------------------------------------------- +5.3.41 -- the hunt for the plane-write defect: not caught, but bounded +-------------------------------------------------------------------------------- +Two more hypotheses died, and the defect gained a nasty property. + + 5. PlayerStatus blitting `recoloredMech` through DrawPixelMap8 -- it is + dirty-gated (change-driven, matching the intermittency) and DOES blit an + 8-bit pixmap. KILLED: the widget map for a DIRTY run contains no + playerStatus at all. It is built by cameraInit (the observer page) and + never exists in a mech cockpit. + 6. Heat driving the coolant values and thus the change-driven redraw. + KILLED: a run with BT_FORCE_FIRE=1 (weapons firing, heat climbing) came + back clean. + +IT IS A HEISENBUG. Rate across this session: dirty on roughly 3 runs in 25. +Every run since instrumentation was added has been clean -- and the pattern +lines up with STARTUP LOG VOLUME: runs with the attribute log or the blit +trace enabled (hundreds of DEBUG_STREAM lines during init) are clean; the +three dirty runs all had the lighter conf. A chatty trace slows startup +enough to suppress it, which is why the blit trace was narrowed to fire only +for pixmaps landing on a NON-palette port (near-silent in the clean case). +That narrowed trace did catch real traffic -- 17x17 PixelMap8 blits onto +Mfd1/Mfd2/Mfd3, i.e. 8-bit pixmaps on single-bit planes -- but those render +correctly (the MFD heads are within ~150px on clean runs), so the library +evidently thresholds them. Not the culprit, but the right bug class to keep +watching. + +HUNTING RECIPE FOR NEXT TIME (two traps cost runs here): + * Detect dirty as Eng1 in (17981, 25000]. Eng1 == 0 means the cockpit is + not up yet, and my first detector read that as "dirty". + * Require the reading to be STABLE across two captures ~20s apart. An + early capture during mission start caught a completely different frame -- + a full 3-D cockpit view, purple sky, canopy struts, HUD reticle, with the + gauges at POD positions rather than plane-packed (Eng1 read 62927). It + did not recur across 8 samples over the following minute, so it is an + early-run transient, not a persistent render. Worth a look on its own + though: BTDPL.INI is in the mount and the engine's DPLRenderer is linked, + so the dPL path may be producing a frame during the launch sequence even + with L4VIDEO=OFF. That is the first evidence this session that the 3-D + path emits anything at all -- do not confuse it with btl4vid being done. diff --git a/restoration/source410/MUNGA/GRAPH2D.CPP b/restoration/source410/MUNGA/GRAPH2D.CPP index 309033ed..07e586db 100644 --- a/restoration/source410/MUNGA/GRAPH2D.CPP +++ b/restoration/source410/MUNGA/GRAPH2D.CPP @@ -2588,6 +2588,43 @@ void if (ClipImage(&sourceBounds, &position, pixelmap->Data.Size)) { + // + // BLIT TRACE (env BT_VIS_BLIT): every 8-bit pixmap that reaches + // a port, with the port it lands on and the rect it covers. + // Hunting the write that puts raw packed bytes into the + // plane-packed gauge buffer. + // + // + // Log ONLY pixmap blits landing on a port that is NOT one of the + // two palette ports (sec / overlay). An 8-bit pixmap reaching a + // single-bit plane is the thing being hunted, and filtering here + // keeps the trace near-silent -- which matters, because the + // defect is a STARTUP TIMING race and a chatty trace suppresses + // it (six consecutive clean runs once logging was added). + // + if (getenv("BT_VIS_BLIT") != NULL + && graphicsPort != NULL && graphicsPort->name != NULL + && stricmp(graphicsPort->name, "sec") != 0 + && stricmp(graphicsPort->name, "overlay") != 0) + { + static int blitSamples = 0; + if (blitSamples < 400) + { + ++blitSamples; + DEBUG_STREAM << "[blit] port='" + << ((graphicsPort != NULL && graphicsPort->name != NULL) + ? graphicsPort->name : "(null)") + << "' at " << position.x << "," << position.y + << " src " << sourceBounds.bottomLeft.x << "," + << sourceBounds.bottomLeft.y << ".." + << sourceBounds.topRight.x << "," + << sourceBounds.topRight.y + << " size " << pixelmap->Data.Size.x << "x" + << pixelmap->Data.Size.y + << " opaque=" << (opaque ? 1 : 0) + << " rot=" << rotation << "\n" << flush; + } + } graphicsPort-> DrawPixelMap8( currentOperation,