[Fix] (Espryt): make the vertex-input bit require the resource bit and give both new subsystems a named verdict when the knobs leave no arm

This commit is contained in:
2026-09-08 04:52:15 -04:00
parent b28058f37c
commit 511b3752c0
2 changed files with 88 additions and 4 deletions
+78 -2
View File
@@ -2266,14 +2266,90 @@ namespace MobileGL::MG_Backend::DirectGLES {
// order question to answer (SlotTables.h).
BackendBufferResourceTable g_backendBufferResources;
// The two P3a families get the three-way treatment ClassifyEsprytSlotArm established for
// bit 5, rather than reading their bit and stopping there: "the bit is clear AND the
// legacy arm has been taken away" is a real configuration an operator can ask for, and a
// family that only reads its own bit answers it by running the very arm that was
// 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.
enum class PipeSubsystemArmVerdict { Handles, Legacy, NoArm };
PipeSubsystemArmVerdict ClassifyPipeSubsystemArm(Bool subsystemBitSet, Bool legacyMemosEnabled,
Bool legacyArmSurvivesLegacyMemos) {
if (subsystemBitSet) return PipeSubsystemArmVerdict::Handles;
if (legacyArmSurvivesLegacyMemos || legacyMemosEnabled) return PipeSubsystemArmVerdict::Legacy;
return PipeSubsystemArmVerdict::NoArm;
}
Bool ResolveResourceSubsystemArm() {
const Bool enabled = (MG_Config::Features.PipePush & MG_Pipe::kMGPipeSubsystemResources) != 0;
const Bool bitSet = (MG_Config::Features.PipePush & MG_Pipe::kMGPipeSubsystemResources) != 0;
// The buffer family's legacy arm is the Ops_* table and g_glesBufferBackendOps, which
// are compiled UNCONDITIONALLY - only the VAO twin's memos and the pre-handle VAO
// body live under MOBILEGL_PIPE_LEGACY_MEMOS - so this family cannot be left armless
// and NoArm is unreachable for it. Said out loud rather than assumed, because the
// knob is still answered below.
const PipeSubsystemArmVerdict verdict =
ClassifyPipeSubsystemArm(bitSet, MG_Config::Features.PipeLegacyMemos,
/*legacyArmSurvivesLegacyMemos=*/true);
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 "
"ops table is compiled unconditionally, so the LEGACY arm is what this process runs");
}
const Bool enabled = verdict == PipeSubsystemArmVerdict::Handles;
MGLOG_D("MGPipe: Espryt resource family runs the %s arm", enabled ? "handle" : "legacy");
return enabled;
}
Bool ResolveVertexInputSubsystemArm() {
const Bool enabled = (MG_Config::Features.PipePush & MG_Pipe::kMGPipeSubsystemVertexInput) != 0;
const Bool bitSet = (MG_Config::Features.PipePush & MG_Pipe::kMGPipeSubsystemVertexInput) != 0;
const Bool resourcesBitSet =
(MG_Config::Features.PipePush & MG_Pipe::kMGPipeSubsystemResources) != 0;
// BIT 8 REQUIRES BIT 7, and it is refused here rather than half-run. The vertex-input
// handle arm resolves every attribute's driver buffer id through
// FindBufferResourceForHandle, i.e. out of the resource SLOT TABLE - and only bit 7
// puts twins in that table (with bit 7 clear EnsureBufferResource takes the legacy
// arm and parks the twin on PipeResource::m_backend instead). The pair therefore
// produced a walk in which every BindAttributeBufferByHandle logged once and
// `continue`d WITHOUT disabling the array, so every draw fetched through whatever
// pointer the driver VAO last held. The mirror pair (bit 7 set, bit 8 clear) is fine:
// the legacy VAO walk calls BindAttributeBuffer -> EnsureBufferResource, which
// dispatches to the handle arm by itself.
if (bitSet && !resourcesBitSet) {
MGLOG_E("MGPipe: kMGPipeSubsystemVertexInput (bit 8) is set but kMGPipeSubsystemResources "
"(bit 7) is clear; the vertex-input handle arm resolves attribute buffer ids "
"through the resource slot table, which only bit 7 populates - REFUSING bit 8 and "
"running the legacy vertex-input arm. Set bit 7 as well, or clear both");
return false;
}
#if MOBILEGL_PIPE_LEGACY_MEMOS
constexpr Bool kLegacyVaoArmCompiled = true;
#else
constexpr Bool kLegacyVaoArmCompiled = false;
#endif
// Unlike the buffer family, this one's legacy arm IS conditional: the pre-handle
// SyncToBackend body and the twin memos it reads are inside MOBILEGL_PIPE_LEGACY_MEMOS.
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");
}
}
const Bool enabled = verdict == PipeSubsystemArmVerdict::Handles;
MGLOG_D("MGPipe: Espryt vertex-input family runs the %s arm", enabled ? "handle" : "legacy");
return enabled;
}
+10 -2
View File
@@ -697,8 +697,16 @@ namespace MobileGL::MG_Backend::DirectGLES {
// the table above - so an answer that changed mid-run would strand every resource
// already built and leak the driver ids they own.
Bool ResolveResourceSubsystemArm();
// Same shape for the vertex-input family (bit 8). Kept separate because the two bits
// are separately clearable and the A/B has to be able to run either one alone.
// Same shape for the vertex-input family (bit 8), and separate because the two bits are
// separately clearable - but NOT independent, and the resolver says so out loud rather
// than half-running: bit 8 REQUIRES bit 7, because the vertex-input handle arm resolves
// every attribute's driver buffer id out of the resource slot table and only bit 7 puts
// twins there. `0x17f` (bit 8 on, bit 7 off) is therefore refused at arm resolution with
// a named MGLOG_E and runs the legacy vertex-input arm; `0x0ff` (bit 7 on, bit 8 off) is
// a real, supported A/B, because the legacy VAO walk reaches the handle arm through
// EnsureBufferResource's own dispatch. Both resolvers also answer
// MG_Config::Features.PipeLegacyMemos, so "the bit is clear and the legacy arm was taken
// away" is a named verdict instead of a silent legacy run.
Bool ResolveVertexInputSubsystemArm();
// INLINE for the reason SlotTables.h spells out at EsprytSlotTablesEnabled: both are