[MG_Backend] (Disaggregated): P5e fb - the FBO doors, both attachment lists, the binds, the blit and the detach walk read records

- The doors: RefuseFramebufferBindingSlotRead raises
  Fatal{UnmigratedPipeInput, "GetFramebufferBindingSlot@<verb>"} where a decline used
  to fall through to the pre-handle arm. Under a transport with the framebuffer bit
  set the fallback is not a safe default - it would read a row belonging to a client
  this apply is no longer synchronous with - so SyncCurrentFBO's and BindCurrentFBO's
  declines become the detector CONTRACT-P5E §5.4 asks for.
- The two attachment texture lists are the package's core: the one unconditional
  per-draw live read of this family, taken whether the memo hit or missed. They are
  now keyed {Fbo, ContentHash, ContextSerial, g_backendContextGeneration} with entries
  {Res, twin} that borrow nothing, and the dedupe asks the two BOUND HANDLES rather
  than two pointers. Three frontend reads go in one move: both binding slots, the
  FramebufferObject the entries borrowed their attachment slots from, and
  GetTextureContextId.
- SyncCurrentFBOByRecord drives the twin through SyncToBackendByHandle /
  SyncReadBufferToBackendByHandle; NoteStateForHandle is gone, which was the server's
  last cross-record hold on a frontend framebuffer.
- FramebufferRecordMatchesBinding is monolith-only: the record was resolved from the
  applier's own bound handle, so there is no second answer left to corroborate.
- ForceBindCurrentFBO reads the binding slot INSIDE the else instead of on both sides
  of its own handle arm (S3 finding #7); the three legacy stamps go with it, which is
  safe for the reason the serial memo is invalidated rather than stamped there.
- SyncAndBindFramebufferByHandle configures from the record, so a DSA framebuffer that
  was never bound is configured correctly instead of being named and bound unconfigured.
- Both blit arms take two const MGPFramebufferState&: draw buffers from DrawBuffers[],
  the read buffer by matching ReadSurface against Color[], kind/level/layer/layered/
  format from the surface, Samples from the record, the textures by handle.
- The detach walk uses the reverse index and the records instead of ForEachLive +
  StateForHandle + the frontend attachment array. The frontend-keyed scope stays at
  this site: every caller reaches it from a barriered row (§4.4).
- SyncRenderbufferObjectToBackend refuses by name under a transport - its only caller
  is the copy-image endpoint, whose renderbuffer form both the emitter and the sink
  already refuse - and the scope at that site is deleted.
- Clear's debug-only draw-FBO diagnostic reads the record under a transport.
This commit is contained in:
2026-09-18 08:02:24 -04:00
parent 3012d52e2b
commit 6c37c20f59
3 changed files with 487 additions and 115 deletions
+2 -2
View File
@@ -9659,8 +9659,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
// (D-C1), which is every point a framebuffer can hold on the handle arm: D-C3 refuses
// bit 9 outright on a driver reporting more than 8 colour attachments, and the
// FRONT/BACK points belong to the DEFAULT framebuffer, which has no twin at all.
static const MG_Pipe::MGPSurface* PushedSurfaceForAttachment(const MG_Pipe::MGPFramebufferState& record,
FramebufferAttachmentType point) {
const MG_Pipe::MGPSurface* PushedSurfaceForAttachment(const MG_Pipe::MGPFramebufferState& record,
FramebufferAttachmentType point) {
if (point == FramebufferAttachmentType::Depth) return &record.Depth;
if (point == FramebufferAttachmentType::Stencil) return &record.Stencil;
if (point < FramebufferAttachmentType::Color0 || point > FramebufferAttachmentType::Color31) {