[Fix] (Pipe): retire wire's local Named constant now that the contract mints MGPipeFramebufferTarget::Named

This commit is contained in:
2026-09-08 15:08:22 -04:00
parent 8f1eaafa79
commit 712c946744
3 changed files with 12 additions and 26 deletions
+2 -2
View File
@@ -2145,12 +2145,12 @@ namespace MobileGL::MG_Pipe {
// GL HAS TWO INDEPENDENT FRAMEBUFFER BINDINGS AND THIS RECORD DESCRIBES ONE FRAMEBUFFER,
// so Target says which binding - if any - the description also BINDS it to. Both is one
// object bound to both and moves both handles from one call; Named
// (kMGPipeFramebufferTargetNamed) moves neither, which is how the DSA entry points
// (MGPipeFramebufferTarget::Named) moves neither, which is how the DSA entry points
// describe a framebuffer they are about to blit into or clear without claiming it is
// bound (ID-19). A value above Named is not a target this server has, and guessing one
// would put a draw's attachments into the read binding or the other way round.
const char* fault = nullptr;
if (state.Target > kMGPipeFramebufferTargetNamed) {
if (state.Target >= static_cast<Uint8>(MGPipeFramebufferTarget::Count)) {
fault = "the record names no framebuffer binding target";
}
// THE RECORD IS ADDRESSED BY THE FRAMEBUFFER HANDLE NOW, so the handle has to be one.
+7 -21
View File
@@ -155,25 +155,11 @@ namespace MobileGL::MG_Pipe {
// 4-billion-entry resize.
inline constexpr Uint32 kMGPipeMaxFramebufferSlots = 1u << 16;
// THE FOURTH set_framebuffer_state TARGET, AND IT IS THE CONTRACT'S TO MINT (c0e:
// MGPipeFramebufferTarget::Named = 3). It is declared here as a plain constant because wire
// v3 and c0e run in parallel: the applier must ADMIT the value now, and this package may not
// write MGPipeTypes.h. When c0e lands, this constant is deleted and every use below becomes
// static_cast<Uint8>(MGPipeFramebufferTarget::Named) - wire's verification round retires it,
// and the static_assert underneath is what makes forgetting impossible: the day the
// enumerator exists, MGPipeFramebufferTarget::Count becomes 4 and this fires.
//
// ITS MEANING: "this record describes the framebuffer it names; no binding changes." Draw /
// Read / Both write the record AND set the bound handle(s); Named writes the record only.
// That is what lets the DSA entry points - BlitNamedFramebuffer and the four
// ClearNamedFramebuffer* - be handed a record for a framebuffer that is bound to neither
// binding, which is the hole esprytobj's C-1 found: the applier used to hold the two BOUND
// records only, so a named blit or clear reached a driver FBO that never got its
// attachments.
inline constexpr Uint8 kMGPipeFramebufferTargetNamed = 3;
static_assert(static_cast<Uint8>(MGPipeFramebufferTarget::Count) == kMGPipeFramebufferTargetNamed,
"c0e has landed MGPipeFramebufferTarget::Named: delete kMGPipeFramebufferTargetNamed "
"and spell the enumerator (wire's verification round, ID-21)");
// THE FOURTH set_framebuffer_state TARGET is the contract's MGPipeFramebufferTarget::Named (c0e):
// "this record describes the framebuffer it names; no binding changes." Draw / Read / Both
// write the record AND set the bound handle(s); Named writes the record only, which is how
// the DSA entry points - BlitNamedFramebuffer and the four ClearNamedFramebuffer* - hand the
// server a record for a framebuffer bound to neither binding (esprytobj review C-1, ID-19).
// The two framebuffer BINDINGS, and there are two rather than three: Both and Named are
// things a RECORD says, not bindings a server has. MGPipeApplierState::BoundFramebuffer is
@@ -592,7 +578,7 @@ namespace MobileGL::MG_Pipe {
// described this binding yet", which is what a make-current leaves behind.
//
// set_framebuffer_state Draw / Read / Both writes the RECORD at state.Fbo's slot AND
// sets the handle(s) here; Named (kMGPipeFramebufferTargetNamed) writes the record and
// sets the handle(s) here; Named (MGPipeFramebufferTarget::Named) writes the record and
// touches nothing here at all - that is the whole of the fourth target's meaning.
Array<MGPipeHandle, kMGPipeFramebufferBindingCount> BoundFramebuffer{};
// ONE SERIAL FOR THE FAMILY, and it moves on EVERY write - a Named record's included,
@@ -962,7 +948,7 @@ namespace MobileGL::MG_Pipe {
// can never displace another's, and a slot whose object has been recycled is simply
// overwritten by its successor's record (D-I2: no wire lifetime, so nothing to retire).
// - Draw / Read / Both ADDITIONALLY set BoundFramebuffer[Draw] / [Read] / both.
// kMGPipeFramebufferTargetNamed sets NEITHER: it is how a DSA entry point hands Espryt
// MGPipeFramebufferTarget::Named sets NEITHER: it is how a DSA entry point hands Espryt
// a framebuffer it is about to blit into or clear WITHOUT claiming it is bound.
//
// FramebufferSerial advances on every applied record, Named included.
@@ -273,7 +273,7 @@ TEST(FramebufferEmit, ATargetOutsideTheThreeBindingsIsRefusedNamingTheRecord) {
#else
ApplierGuard guard;
MGPFramebufferState bad = FramebufferRecord(MGPipeHandle{7, 4}, MGPipeFramebufferTarget::Draw, 100);
bad.Target = static_cast<Uint8>(kMGPipeFramebufferTargetNamed + 1);
bad.Target = static_cast<Uint8>(MGPipeFramebufferTarget::Count);
const Uint64 serialBefore = MGPipeApplier().FramebufferSerial;
ExpectRefusedNaming("set_framebuffer_state {slot=7, gen=4, target=4}: the record names no framebuffer "
@@ -440,7 +440,7 @@ TEST(FramebufferEmit, ANamedRecordDescribesTheFramebufferItNamesWithoutMovingEit
const Uint64 serialBefore = MGPipeApplier().FramebufferSerial;
MGPFramebufferState named = FramebufferRecord(MGPipeHandle{6, 3}, MGPipeFramebufferTarget::Draw, 300);
named.Target = kMGPipeFramebufferTargetNamed;
named.Target = static_cast<Uint8>(MGPipeFramebufferTarget::Named);
named.Color[0].Res = MGPipeHandle{21, 1};
MGPipeApplySetFramebufferState(named);
@@ -451,7 +451,7 @@ TEST(FramebufferEmit, ANamedRecordDescribesTheFramebufferItNamesWithoutMovingEit
"clears into a driver framebuffer with no attachments";
EXPECT_EQ(MGPipeApplier().FramebufferRecordFor(MGPipeHandle{6, 3})->Width, 300u);
EXPECT_EQ(MGPipeApplier().FramebufferRecordFor(MGPipeHandle{6, 3})->Color[0].Res, (MGPipeHandle{21, 1}));
EXPECT_EQ(MGPipeApplier().FramebufferRecordFor(MGPipeHandle{6, 3})->Target, kMGPipeFramebufferTargetNamed);
EXPECT_EQ(MGPipeApplier().FramebufferRecordFor(MGPipeHandle{6, 3})->Target, static_cast<Uint8>(MGPipeFramebufferTarget::Named));
// (b) AND NEITHER BINDING MOVED.
ASSERT_NE(MGPipeApplier().DrawFramebuffer(), nullptr);