[Fix] (DirectGLES): stop on an armless P3a subsystem verdict now that every LEGACY_MEMOS=0 lane pins an explicit 0x1ff arm - warning and continuing drew through an unconfigured driver VAO

This commit is contained in:
2026-09-08 07:00:28 -04:00
parent afda613bd9
commit 2a5e0195b8
+56 -15
View File
@@ -2322,15 +2322,38 @@ namespace MobileGL::MG_Backend::DirectGLES {
// disabled, in silence. The two families differ in whether that third verdict is
// REACHABLE, which is why the classifier takes it as a parameter rather than assuming it.
//
// NOT A STOP, unlike ResolveEsprytSlotTablesArm's NoArm. Bit 5's stop is safe because no
// shipped lane pins bit 5 clear; bits 7 and 8 are clear in every `.Handles` itest lane
// today (MG_IntegrationTest/CMakeLists.txt pins MOBILEGL_PIPE_PUSH=0x7f beside
// MOBILEGL_PIPE_LEGACY_MEMOS=0), which is contract-review item 11 and package D's to
// re-pin. Aborting here would turn that lane red for a mis-pinned control rather than
// for a defect. The verdict is therefore NAMED and loud, and the stop can be promoted
// the moment those lanes carry an explicit 0x1ff arm.
// A STOP, exactly like ResolveEsprytSlotTablesArm's NoArm, and M-4 is the promotion.
//
// It was a warning while the premise for the warning held: bits 7 and 8 were clear in
// every `.Handles` itest lane, which pinned MOBILEGL_PIPE_PUSH=0x7f beside
// MOBILEGL_PIPE_LEGACY_MEMOS=0, so aborting would have turned that lane red for a
// mis-pinned control rather than for a defect. That premise is gone: gates' M1 re-pinned
// MGL_ITEST_HANDLES_ARM_KNOBS to "MOBILEGL_PIPE_LEGACY_MEMOS=0" + "MOBILEGL_PIPE_PUSH=0x1ff"
// (MG_IntegrationTest/CMakeLists.txt), and the four CSO lanes went to 0x1ff /
// 0x800000000000_01ff, which is contract-review item 11 closed for all three lane
// families. The only lanes that set LEGACY_MEMOS=0 now carry an explicit vertex-input
// arm, so an armless verdict can no longer be a lane's own configuration - it can only
// be an operator who asked for both arms to be gone.
//
// Warning-and-continue is the wrong answer to that, for ResolveEsprytSlotTablesArm's
// reason verbatim: continuing runs the very arm the operator disabled and hands back a
// result measured on it, which is exactly the lever HandleRecycleScenario's arms are
// selected with, so a mis-set A/B would be scored silently against the wrong arm
// (ARCHITECTURE.md 9.6). Resolved lazily at the first use, not at bring-up, so the stop
// lands in a scenario body where ctest reports it rather than inside eglMakeCurrent
// where the harness reads an abort as "no usable GPU" and skips.
//
// This closes espryt D14 / closure row 7 and, with it, row 6's "LEGACY_MEMOS=0 +
// PUSH=0x7f must name a verdict": that combination now names NoArm and stops.
enum class PipeSubsystemArmVerdict { Handles, Legacy, NoArm };
// The one voice for an armless verdict, so the two families cannot disagree about what
// it means or about whether it stops. `what` names the family and the bit.
[[noreturn]] void StopOnArmlessPipeSubsystem(const char* what) {
MGLOG_F("MGPipe: Fatal{PipeLegacyMemosDisabled, \"%s, so there is no arm to run\"}", what);
std::abort();
}
PipeSubsystemArmVerdict ClassifyPipeSubsystemArm(Bool subsystemBitSet, Bool legacyMemosEnabled,
Bool legacyArmSurvivesLegacyMemos) {
if (subsystemBitSet) return PipeSubsystemArmVerdict::Handles;
@@ -2348,6 +2371,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
const PipeSubsystemArmVerdict verdict =
ClassifyPipeSubsystemArm(bitSet, MG_Config::Features.PipeLegacyMemos,
/*legacyArmSurvivesLegacyMemos=*/true);
// Unreachable for this family by the argument above, and stated as a stop anyway:
// the two P3a families answer an armless verdict the same way, and an unreachable
// branch that says something different is how the reachable one drifts.
if (verdict == PipeSubsystemArmVerdict::NoArm) {
StopOnArmlessPipeSubsystem("MOBILEGL_PIPE_PUSH leaves kMGPipeSubsystemResources "
"(bit 7) clear and the pre-handle buffer arm is gone");
}
if (verdict == PipeSubsystemArmVerdict::Legacy && !MG_Config::Features.PipeLegacyMemos) {
MGLOG_W("MGPipe: MOBILEGL_PIPE_PUSH leaves kMGPipeSubsystemResources (bit 7) clear while "
"MOBILEGL_PIPE_LEGACY_MEMOS=0 asks for the pre-handle arms to be gone; the buffer "
@@ -2389,14 +2419,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
const PipeSubsystemArmVerdict verdict =
ClassifyPipeSubsystemArm(bitSet, MG_Config::Features.PipeLegacyMemos,
/*legacyArmSurvivesLegacyMemos=*/false);
if (verdict == PipeSubsystemArmVerdict::NoArm || !kLegacyVaoArmCompiled) {
if (verdict != PipeSubsystemArmVerdict::Handles) {
MGLOG_E("MGPipe: PipeLegacyMemosDisabled - MOBILEGL_PIPE_PUSH leaves "
"kMGPipeSubsystemVertexInput (bit 8) clear and the pre-handle VAO sync is "
"%s, so this process has no vertex-input arm at all; the driver VAO will "
"not be configured and SyncToBackend says so again at the first draw",
kLegacyVaoArmCompiled ? "disabled by MOBILEGL_PIPE_LEGACY_MEMOS=0" : "not compiled");
}
if (verdict != PipeSubsystemArmVerdict::Handles &&
(verdict == PipeSubsystemArmVerdict::NoArm || !kLegacyVaoArmCompiled)) {
// M-4: A STOP, not a log line. Continuing here left the process drawing through
// an UNCONFIGURED driver VAO - every attribute pointer whatever the last owner
// of that VAO name set it to - after one MGLOG_E that a lane summary does not
// read. The lanes that pin MOBILEGL_PIPE_LEGACY_MEMOS=0 all carry an explicit
// 0x1ff now, so this verdict is an operator's configuration and nothing else.
StopOnArmlessPipeSubsystem(
kLegacyVaoArmCompiled
? "MOBILEGL_PIPE_PUSH leaves kMGPipeSubsystemVertexInput (bit 8) clear and "
"MOBILEGL_PIPE_LEGACY_MEMOS=0 disables the pre-handle VAO sync"
: "MOBILEGL_PIPE_PUSH leaves kMGPipeSubsystemVertexInput (bit 8) clear and "
"the pre-handle VAO sync is not compiled into this build");
}
const Bool enabled = verdict == PipeSubsystemArmVerdict::Handles;
MGLOG_D("MGPipe: Espryt vertex-input family runs the %s arm", enabled ? "handle" : "legacy");
@@ -3793,6 +3828,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
}
#endif
#if !MOBILEGL_PIPE_LEGACY_MEMOS
// UNREACHABLE as of M-4: VertexInputSubsystemEnabled() resolves the arm at its first
// call, and an armless verdict now stops the process there rather than returning
// false into this branch. Kept, and kept loud, because it is the second lock on the
// same question: this is what an arm resolution that ever stopped stopping would
// reach, and drawing on through an unconfigured driver VAO is exactly what must not
// happen quietly.
(void)stateVAOObject;
MGLOG_E_ONCE("MGPipe: the vertex-input subsystem bit is clear and MOBILEGL_PIPE_LEGACY_MEMOS=0 "
"removed the pre-handle VAO sync, so this configuration has no arm at all");