[Fix, Test] (MG_Pipe): replace the always-false live-host-writes wire, which no producer can survive, with the one statement that stays true - the bit is the buffer family's

This commit is contained in:
2026-09-11 15:48:28 -04:00
parent 950968044c
commit 0598cfffe0
2 changed files with 39 additions and 0 deletions
+27
View File
@@ -889,6 +889,32 @@ namespace MobileGL::MG_Pipe {
void PinWholeResourceRespecifyScope(const MGPResourceDesc&, MGPipeHandle, const char*) {}
#endif
#if MOBILEGL_PIPE_VERIFY
// P5 b1's wire, and the one statement about HasLiveHostWrites that IS still always
// true once the field has a producer: the bit is the BUFFER family's. It answers "does
// this resource have a live host writer right now", which only a buffer can have - a
// texture's host writes are the unpack path's and are announced by the upload itself -
// and the two emitters that set it (MGPipeEmitResourceSubData,
// MGPipeEmitBufferSubDataResident) are both buffer-only. A texture sub-data carrying
// it is therefore an encoder that copied a field across payload halves, which is
// precisely the class of defect a shared record type invites.
//
// It replaces the always-false pin in a split build. That pin could not survive the
// producer it existed to announce; this one can, and unlike that one it is compiled in
// EVERY verify build, including build-verify-split - the matrix cell where the field
// can actually be non-zero.
void PinLiveHostWritesNamesABuffer(const MGPSubData& record, const char* call) {
if (record.HasLiveHostWrites == 0) return;
MGP_TRIP_WIRE_REPORT("MGPipe: " MGP_TRIP_WIRE_TAG("PipeLiveHostWritesTarget")
" %s {slot=%u, gen=%u}: a record whose resource target is not a "
"buffer (target=%u) declares live host writes, and only the buffer "
"family has any",
call, record.Res.Slot, record.Res.Gen, record.Target);
}
#else
void PinLiveHostWritesNamesABuffer(const MGPSubData&, const char*) {}
#endif
// The one gate every content-carrying buffer write goes through. resource_subdata and
// buffer_subdata_resident differ only in which backend hook takes the bytes and in the
// fact that one of them is allowed to be absent, so a second copy of this arithmetic
@@ -1794,6 +1820,7 @@ namespace MobileGL::MG_Pipe {
// accumulate a pending upload onto whatever TEXTURE holds slot N in the texture slot
// space. Renderbuffers have no sub-data path at all, so no correct client can produce
// one and this is a protocol fault rather than a dropped call.
PinLiveHostWritesNamesABuffer(record, "resource_subdata");
const Uint8 resourceTarget = MGPipeSubDataResourceTargetOf(record.Target);
if (resourceTarget == kMGPipeResourceTargetBuffer ||
resourceTarget == static_cast<Uint8>(MGPipeResourceTarget::Renderbuffer) ||
@@ -1260,6 +1260,18 @@ namespace {
// until now by POISON being invisible in this TU at all (see the include at the top).
#elif !MOBILEGL_PIPE_VERIFY
GTEST_SKIP() << "Fatal{PipeLiveHostWrites} is a MOBILEGL_PIPE_VERIFY wire and is compiled out here";
// P5 b1: AND IT IS RETIRED IN A SPLIT BUILD, because this is the phase the wire was
// waiting for. "HasLiveHostWrites is always false and is written by nobody" cannot
// survive the producer it exists to announce - MGPSubData::HasLiveHostWrites, set by
// MGPipeEmitResourceSubData - so under MOBILEGL_BUILD_DISAGGREGATED the always-false
// pin is gone and two other things carry the invariant instead:
// PinLiveHostWritesNamesABuffer (the bit is buffer-family only, and that IS still
// always true) and the production-path probe pair in MG_Test/SanityTest.cpp and
// MG_Test/Buffer/SplitBufferTest.cpp, both of which go red when the producer is
// deleted. This skip is what the build-verify-split lane exists to make visible.
#elif MOBILEGL_BUILD_DISAGGREGATED
GTEST_SKIP() << "P5 gave HasLiveHostWrites a producer, so the always-false wire is retired "
"in a split build; PinLiveHostWritesNamesABuffer replaces it";
#elif !MGTEST_HAVE_FORK
GTEST_SKIP() << "no fork on this platform; the wire's verdict is std::abort()";
#else