Commit Graph
370 Commits
Author SHA1 Message Date
swung0x48 6c37c20f59 [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.
2026-09-18 08:02:24 -04:00
swung0x48 3012d52e2b [MG_Backend] (Disaggregated): P5e fb - the attachment surface, the two by-handle twins and the image unit read records
- SyncAttachmentSurface loses its frontend attachment parameter (CONTRACT-P5E §5.4).
  The storage syncs have by-handle forms now, so the object was only there to be
  cross-checked - and a second answer only a monolith build can produce is not a
  check. Review N-6's one-directional hole ("record empty, frontend still holding")
  becomes unrepresentable: the caller's detach and the attach read one test.
- The renderbuffer cross-check at the old Managers.cpp:9711 is DELETED rather than
  transport-gated (§4.4). It was the one HandleOf in this family that was not gated
  while its texture sibling was; it ran a client-allocator probe on the apply thread
  under split, legal only because the scope named it and the client was parked.
- BackendFramebufferObject::SyncToBackendByHandle and
  BackendRenderbufferObject::SyncToBackendByHandle land in place of c0e's aborting
  seams, beside the object forms they overload. The record's eleven surfaces are the
  point set; the per-point frontend version memo is gone and the record hash is the
  only gate, with g_attachmentBackendIdGeneration and the re-entry kept because no
  client-side value can answer what they answer.
- SyncReadBufferToBackend's decision moves into ApplyReadBufferFromRecord, which takes
  no frontend object; both overloads funnel through it.
- The reverse index texture -> framebuffers, maintained at the by-handle sync, for the
  detach walk (tx2 needs it) instead of a walk over every twin's frontend attachments.
- Images: ResolveShaderImageRecord and its identity probe are gone - under a transport
  there is no second answer to arbitrate. SyncImageTextureBinding gains a record
  overload; Access is DECODED through MGPipeValueTypes.h (ruling 16 / ID-94) and the
  stale "the encoding does not exist" comment is deleted. The bind's format rules are
  factored into one helper both arms call rather than written twice.
- The image sweep gate is re-keyed onto (ShaderImagesSerial, TextureShutterSerial,
  ContextSerial, g_backendContextGeneration) under a transport (ruling 7 / ID-86),
  never a backend re-mint counter; the window/high-water union is kept and the walk
  reads BoundShaderImages[].
- MarkWritableImageBufferTexturesGpuWritten returns early under a transport - the
  client owns the GPU-write set; paired with sb's deletion of the backend marks.
- BoundImageUnitFormat answers from MGPImageView::InternalFormat under a transport.
2026-09-18 07:53:05 -04:00
swung0x48 f6cfcbd36b [MG_Pipe, MG_Backend, MG_Remote, MG_Test] (Disaggregated): P5e wave 1 integration - one body per seam, and the stamp waits for ra
- c0e and id were implemented in parallel and each declared the two shared seams,
  so the merge produced five duplicate definitions the text could not collide:
  MGPipeBarriered, MGPipeApplierCurrentRecordIsBarriered and the three by-handle
  twin resolvers. Resolved per ID-99 and ID-103.
- MGPipeBarriered keeps c0e's real body (the static wait-class column, the XFB
  escalation and the client-array escalation); id's constant-true placeholder goes.
- The current-record flag keeps c0e's thread_local storage and setter and loses
  id's MGPipeApplierState member: it describes which record THIS THREAD is inside,
  not per-context state the applier owns, and the allocator guard that reads it
  would otherwise have to find the right context's applier first. id's test hook
  posts through the setter.
- The three resolvers keep id's real bodies beside each registry; c0e's asserting
  stubs for them go. The seam stubs no package has bodied yet stay.
- ApplyOne stamps `true` while kMGPipeP5eClientWaitRuleLanded is false. The
  predicate says what the client WILL do; until ra changes EmitAndWaitTails the
  client still blocks after every record, so a `false` stamp would withdraw the
  §4.4 exemption from a probe the client's own wait still makes safe. The
  predicate is computed on every record regardless, so it is exercised for the
  whole phase instead of first running on the day it starts deciding.
- Gates on the merged tree: unit 2206/2206, integration-split 111/111, both
  generators --check/--self-test green, include closure 0 problems, dirty surface
  rc 0, doc citations one pre-existing CONTRACT-P5.md line (c0e retired another).
2026-09-18 07:05:48 -04:00
swung0x48 367e473416 Merge branch 'p5e/id' into feat/disaggregated (P5e id: handle-keyed twins, the barriered exemption, the scope rename) 2026-09-18 07:00:07 -04:00
swung0x48 c06878ef73 [MG_Pipe, MG_Impl, MG_Backend, MG_Test] (Disaggregated): P5e c0e - the cross-package seams
- MGPipeBarriered(op, payload, applierState), IMPLEMENTED, not stubbed: the static wait-class
  column plus the two payload-derived escalations the contract names (an open XFB span, a draw
  carrying kDrawClientArrays). One function and two callers is the point - the emit table and
  the sink must reach the same answer or the client runs on while the server reads a value that
  has already moved. set_context_values now mirrors IsTransformFeedbackActive into the applier
  state as well, because a predicate that read it out of gPipeInputs would be reading the very
  block run-ahead stops filling.
- MGPipeApplierCurrentRecordIsBarriered() with the writer beside it. It answers true by default
  and that IS the landed lockstep answer, not a stub: on a server without kCapRunAheadApply
  every record is barriered and CONTRACT-P5C's two exemption scopes keep working unchanged.
- The sb applier fields (BoundShaderBuffers[3][84], the three windows, the writable masks and
  ShaderBuffersSerial) and the pg record fields (the three binding tails, Signature,
  BindingsSerial) with the two entry points MGPipeApplySetShaderBuffers /
  MGPipeApplySetProgramBindings declared and ABORTING BY NAME.
- The by-handle backend seams in Managers.h with aborting bodies in one block: ResolveVaoTwin,
  ResolveTextureTwin, ResolveProgramTwin, SyncTextureToBackendByHandle,
  SyncMipmapsToBackendByHandle, and the FBO / RBO / program SyncToBackendByHandle overloads.
  Five packages sit on opposite sides of these calls - tx2 writes what fb calls, fb writes what
  tx2 needs, id rekeys the registries all three read - so the signature is fixed once here and
  each family replaces a body. Abort and not null: a resolver that answered null renders a
  blank draw and a sync that did nothing renders stale pixels, and both are green lanes.
- Coverage.def's GetBufferBindingPoint -> SetShaderBuffers row with BOTH of its PipeFill.cpp
  switch arms and the pairing asserts, shape-only and inert. It lands with the contract package
  because PipeFill.cpp belongs to the contract package for the whole phase - an emitter
  enumerator whose dispatch arm lived in the family's worktree is the merge trap that file's
  own comment was written about.
- FieldOwnership.def re-annotates the six object-class rows plus GetProgramForDispatch to
  "P5e (Espryt unbarriered), P7 (Magma)", and the strict-abort case follows the string, which
  IS the debt entry rather than decoration. kMGPipeMaxBufferBindingPoints is pinned against
  BufferState.h's 84 where both are visible. gen_pipe_field_ownership's refusal count is 8.
2026-09-18 06:40:43 -04:00
swung0x48 287bade924 [MG_Backend] (Disaggregated): P5e id - the NoSession mailbox hop deleted, the twin death moment and the ABA answer written down
- OnFrontendStateObjectDestroyed's split arm loses the mailbox hop
  (CONTRACT-P5E §4.4). It existed for the ONE shape the object_death record
  cannot carry - a transport with no client session at all, i.e. a ServerLoop
  fixture driving a server role with no client, never a real split - and it
  posted a stack struct to the apply thread, which re-entered this function and
  ran DestroyByLifetimeId: a probe AND a Free in the CLIENT'S allocator from the
  apply thread. That is not a read a barrier could ever make safe, because under
  run-ahead there is no wait behind which the allocator stands still. Such a
  fixture's twins die with the backend at Stop, which is what already happened
  for every death raised past Running() == false.
- The frontend-keyed scope this function opened goes with it: the one arm that
  needed it was the hop. Falling through under a transport now means the death
  was raised ON the apply thread - the server backend destroying a frontend
  object it created itself - and those sites carry their own named scope.
- ID-96, ANSWERED BY MEASUREMENT rather than by reading: a probe that aborted in
  exactly the deleted branch (NoSession with a RUNNING server loop) was run over
  the whole unit lane (2204 entries) and the whole integration-split lane (111)
  and NEVER FIRED. The only fixture family that could reach it is
  ServerLoopTest.cpp's ServerFixture / EglServerFixture - the tree's only server
  role with no client session - and its one case that lets a re-keyed frontend
  object die off the apply thread
  (ServerLoopEglTest.FrontendFramebufferDeathDeletesOnTheContextOwner) is already
  refused at its FIRST step by P5c's allocator guard. So the set of fixtures that
  lose death delivery is empty: none rewritten, none deleted.
- ReleaseTwinsForWireObjectDeath gains §4.2's death moment and §4.3's ABA answer
  in its own voice: the ordering is the argument (every record naming {s,g} is
  applied before object_death{s,g}, which is applied before create{s,g+1}) and
  the Gen compare is the proof (forward re-mints, a stale handle resolves to
  null, a backward generation is refused) - so a skipped death is answered by the
  forward-Gen reset alone and no wait is added at any delete.
2026-09-18 06:35:49 -04:00
swung0x48 0d54de62e2 [MG_Backend] (Disaggregated): P5e id - ResolveVaoTwin / ResolveTextureTwin / ResolveProgramTwin by handle
- The three by-handle resolvers the per-family packages call, in the shape
  SamplerImpl::ResolveSamplerCsoTwin already runs (CONTRACT-P5E §4.1/§4.2):
  handle in, THE RECORD FIRST, then AdoptTwinByHandle, then a twin if the slot is
  empty. A handle with no applier record is a seam defect and adopting a slot for
  it would leave a twin nothing can sync, so it is a loud null rather than an
  empty twin; a generation behind the live entry's is refused by
  PipeTwinHandleIsAdoptable rather than dropping the incumbent's driver object.
- WHAT THEY DO NOT DO is the deliverable: no frontend object is touched and the
  client's slot allocator is never probed. They also do not SYNC - which serials
  gate a VAO / texture / program sync, and what the sync reads, belongs to vi,
  tx2 and pg, and a resolver that synced would have to know.
- ResolveProgramTwin resolves through the band-aware PipeShaderCsoRecordForHandle
  and adopts into SlotTables.h's m_band, which is why the band landed in the same
  package: after the rekey a program-pipeline composite's bind is the ordinary
  path through this function.
- Declared beside each family's registry global rather than in the registry class
  region BRIEF-P5E names, so that the three read exactly like the sampler
  resolver they copy. Reported to the integrator as a range widening.
2026-09-18 06:35:24 -04:00
swung0x48 f40a57cc96 [MG_Pipe, MG_Impl, MG_Remote, MG_Backend] (Disaggregated): P5e id - the barriered seam, the allocator guard and the two scopes
- CONTRACT-P5E §2.1's predicate gets its two names in MG_Pipe/PipeApply.h:
  MGPipeBarriered(op, payload, st) and MGPipeApplierCurrentRecordIsBarriered(),
  with MGPipeApplierState::CurrentRecordBarriered as the per-record flag that
  PipeApplier::ApplyOne stamps before every decode. The body answers TRUE for
  every record until ra lands the wait rule, so lockstep is unchanged and this
  package alters no behaviour; ra rebases onto that line rather than adding it.
  Package c0e owns the final declaration of both names - the overlap is one hunk.
- §4.4: MGPipeRefuseAllocatorFromApplyThread now exempts a probe only inside a
  named scope AND while the record being applied is barriered. The client's wait
  is the whole of what makes an apply-thread frontend probe safe; behind an
  unbarriered record the allocator's free list and lifetimeId -> slot map are
  moving under the read, so the value is wrong by construction - there is no
  "count it" arm and MOBILEGL_IPC_STRICT_ERRORS is not consulted.
- MGPipeApplierIsUnbarrieredApply() and
  MGPipeRefuseFrontendKeyedRegistryFromUnbarrieredApply() are the non-allocator
  half of the same rule, for the surfaces that answer from a frontend SharedPtr
  without calling the allocator (SlotTables.h's state note and its reader).
- Ruling 12: MGPipeReverseAnnouncementScope -> MagmaP7AllocatorDebtScope, keyed
  on MG_Config::ActiveBackendType == DirectVulkan. Magma's four apply-thread
  allocator debts move onto it (VulkanRenderer's two hidden-resource shutdowns
  and the named-blit endpoint resolve, ResourceTracker's GPU-write
  announcement); an Espryt probe can no longer borrow Magma's exemption by
  constructing its scope.
- BufferImpl::HandleOfBuffer is Espryt's debt, not Magma's, so it moves to
  MGPipeFrontendKeyedRegistryScope - which the Magma-keyed scope would not have
  exempted at all. It retires when vi/sb carry the handle into
  EnsureBufferResourceForHandle / IsBufferDrawCleanByHandle.
2026-09-18 06:34:48 -04:00
swung0x48 39d1a5d38c Merge branch 'p5c-gt' into feat/disaggregated (P5c gt: role guards, InBarrierWait wired, rsp measured) 2026-09-17 11:21:39 -04:00
swung0x48 ab9250281b [Docs, MG_Backend] (Disaggregated): P5c housekeeping - the death-switch scope comment describes the landed ct shape (the NoSession arm only), and the README counts 79 calls after ct/rv 2026-09-17 11:21:39 -04:00
swung0x48 a0865b00f4 [MG_State, MG_Backend, MG_Remote, MG_Impl, CI] (Disaggregated): P5c gt - the role guards close the phase
Layer 1 arms the texture object surfaces at MipmapStorage (the one point every concrete
texture class and view forwards through): AllocateStorage, TruncateMipmapLevels,
UpdateMipmapSubData, MapMipmapData, MarkStorageDirty(Region), IsStorageDirty,
GetStorageDirtyRegion(s) take Fatal{RoleViolation, texture-legacy-arm} from the apply
thread with an active transport. What the lane then exposed is fixed, not exempted: the
completeness gate answers from the staged store's defined-ness, the two logging reads go
through the descriptor macro, and the remint replay loop keeps its named
Fatal{UnmigratedEmulation} ahead of the guard. Magma's texture sync read path is the one
named exemption (MGPipeTextureLegacyArmScope, P7). Layer 2 wires InBarrierWait as the
client half of the gPipeInputs single-writer rule (RefusePipeInputsTouchWhileApplierOwnsIt:
applier owns it AND this thread not in a barrier wait => Fatal{RoleViolation,
gPipeInputs}; the barrier-off negative control is deferred to its own Fatal), and stale
reads of RECORD-SUPPLIED / APPLIER-DERIVED fields under a server stamp now report
RoleViolation with the field named. The RemoteGuards suite pins all nine texture surfaces
plus HasDefinedContent by name, and a negative control for the fill window. CI gains the
integration-split-strict job: unit lane as the hard gate under MOBILEGL_IPC_STRICT_ERRORS=1,
the scenario lane expected-red with the marker asserted (rewritable to plain green once P7
retires the object-class rows). rsp is per-frame in the stats line and measured on the
locally available traces (bsl in-world 948.5/frame avg over 123 frames, complementary
1591.9, iterationrp 286 until its named remint-pull Fatal); value-class pulls are zero by
rv's pinned list, what remains is the object-class fifteen.

Evidence: unit 2187/2187 (also under STRICT_ERRORS=1); integration-split 111/111; red-once
per layer (the texture guard and the gPipeInputs guard each turned their named death test
red and restored green). CONTRACT-P5C sections 5.4, 6.
2026-09-17 11:20:44 -04:00
swung0x48 04650ca35e Merge branch 'p5c-ct' into feat/disaggregated (P5c ct: applier_reset / object_death control records)
# Conflicts:
#	MobileGL/MG_Backend/DirectGLES/Managers.h
2026-09-17 06:58:45 -04:00
swung0x48 b45bf68101 Merge branch 'p5c-hd' into feat/disaggregated (P5c hd: handle-keyed resolution)
Conflict: VulkanRenderer.cpp's disaggregated include block took both halves.

Merge coordination (integrator, with the evidence inline):

- hd's Fatal{RoleViolation, MGPipeSlots} guard as landed was kind-blind: it fired on the
  G6 frontend-keyed twin registry (texture/VAO/program/sampler resolver probes - P3b/P4b's
  to rekey) and on the families whose handle-carrying records the client does not emit
  until P4b (the buffer binding-point ensures, the GPU-written announcement). Integration-
  split went 104/107 red at the first Clear. Two NAMED, scoped exemptions keep the guard's
  teeth for every other caller (SlotAllocator.{h,cpp}): MGPipeReverseAnnouncementScope
  (buffer ensure + announcement family, P4b/P7) and MGPipeFrontendKeyedRegistryScope
  (the G6 registry family, P3b/P4b; also the mailbox death switch until ct's object_death
  record retires it). ~30 resolver sites wrapped, each naming its debt in the comment.
- ScopedRestartIndexSubstitution needed NO exemption: the EBO resolves from the record's
  IndexBuffer.Res and the bytes read from the server staged shadow - CONTRACT-P5B d1's
  own sentence, implemented.
- Magma's named blit takes a G6 consume arm (frontend FBOs resolved by lifetime id inside
  the scope, VerbBlitNamedConsumed set, loud refusal kept for a failed resolution), so the
  two DirectVulkan.Split.NamedBlit correctness cases stay green; Magma's hidden blit and
  depth-mipmap resources' teardown probes are wrapped and named (P7: give them non-frontend
  storage).
- MG_State gains GLContext::FindFramebufferObjectByLifetimeId (behaviour-neutral accessor
  for the arm above).

Gates on the merged tree: unit 2166/2166; integration-split 107/107 (2 design skips);
hd's RemoteGuards death tests still abort the unwrapped paths by name; PrimitiveRestart
7/7; the two Magma named-blit cases render. CONTRACT-P5C sections 3, 5.4.
2026-09-17 06:57:16 -04:00
swung0x48 a7e55ee62a [MG_Pipe, MG_Remote, MG_Backend, MG_Impl, MG_IntegrationTest] (Disaggregated): P5c ct - the applier_reset and object_death control records
Two appended wire records replace the two cross-role control bypasses:
applier_reset (opcode 77, MGPApplierReset{Uint64 ContextSerial}, kScreen) is emitted by
the GL thread at the FreshlyPrimed make-current edge, before the client-side resets, so
the record's barrier orders the server's MGPipeApplierReset against every verb that
follows; a direct MGPipeApplierReset() from a non-apply thread with a live session is
Fatal{RoleViolation, "g_applier"} (MGPipeApply.cpp carries the layer-2 guard; the
apply-thread and no-session bring-up shapes keep the direct call verbatim).
object_death (opcode 78, reuses MGPipeHandleOnly, kCtxObject) is the framebuffer
family's first wire delete opcode: the client thread resolves the dying object's handle
in its OWN allocator, emits nothing for a handle the server never saw, and EmitAndWaits
otherwise - the wait preserving the death's ordering against in-flight records that
name the handle, the only property the blocking mailbox hop provided. The sink releases
per-kind twins through a handle-keyed ReleaseTwinByHandle (seven kinds, SamplerViewCso's
idempotent second path kept); a null arriving handle is
Fatal{ProtocolCorruption, "ObjectDeath.Handle"}. A documented NoSession fallback arm
delivers a death to a server-only fixture's loop; monolith keeps the mailbox hop and
the FreshlyPrimed direct call character for character.

Evidence: gen_pipe --check/--self-test and gen_pipe_field_ownership --check/--self-test
green; unit 2155/2155; integration-split 111/111 (107 plus four new CtWireScenario
entries, all genuinely run, each with its own log path and an EXPECT_EXIT death case);
red-once - shorting the emission to the direct call turns the four Ct cases red with
Fatal{RoleViolation, "g_applier"} by name, then restores green verbatim.
CONTRACT-P5C sections 1, 5.1-5.2, 7.
2026-09-17 06:08:54 -04:00
swung0x48 7f5bdd3aa5 [MG_Backend, MG_Remote, MG_Impl, MG_State] (Disaggregated): P5c hd - sinks and twins resolve by the handle the record carried
A split-only verb-handle workspace in MGPipeApplierState (written by the sinks before
dispatch, read by the backend within the same verb) carries the record's handles to the
backend entries whose shared function-table signatures cannot grow them without moving
G1. OnBlit resolves ReadFbo/DrawFbo through the FBO twin table by handle (the named arm
of BlitFramebuffer, a loud refusal when the backend does not consume it) and the split
path's ScopedBlitBindings rebinding is deleted; CopyTex resolves MGPCopyFromFramebuffer::Dst;
the mip descriptor check resolves MGPMipPlan::Res; the indirect families resolve their
buffer handles from the records and read the bytes from the server staged shadow with
RequireStagedCoverage. EnsureBufferResourceForHandle answers HasDefinedContent from
Desc.HasDefinedContent OR the staged coverage set (the streaming idiom defines content
through subdata with no new descriptor). The minting GetOrCreate(StatePtr), HandleOf and
the death switch's lifetime-id arms take Fatal{RoleViolation, MGPipeSlots} from the apply
thread, as do the three MGPipeSlots() entry points; the frontend BufferObject legacy
accessors take Fatal{RoleViolation, buffer-legacy-arm}; Magma's four caps reads go to the
server's own backend and the client-mirror fallback arm is a named refusal.

Evidence: unit 2156/2156 (incl. 9 new RemoteF1 + 10 new RemoteGuards death tests pinning
the four Fatal names); monolith smoke green; six production mutations each turned their
named test red and were restored; c1f_redcheck M5 RED then RESTORED GREEN. The mip
descriptor check overlaps tx and is coordinated at the merge (tx's sync rekey wins the
sync body, this handle resolution wins the identity check). CONTRACT-P5C section 3.
2026-09-17 04:55:50 -04:00
swung0x48 4b54a6f902 [MG_Remote, MG_Backend] (Disaggregated): P5c tx - the server's texture staged shadow
StagedTextureStore (MG_Remote/Server/StagedTextureStore.h), the texture twin of R-11's
StagedShadowStore: keyed by the wire handle (a twin-address key would force glGenTextures
at adopt time), coverage = the whole staged run per (uploadTarget, level), defined-ness
tracked from the respecify hook so sparse chains keep their holes. ApplyTextureUpload
adopts the staged bytes at the last instant they are alive (rule C) through three new
disaggregated-only MGPipeResourceOps members; SyncMipmapsToBackend's four arms read the
store and the descriptor instead of the client's MipmapStorage (texels, extent, target,
defined-ness, dirty); Magma's GenerateMipmap marks the server shadow Defined+GpuDirty
instead of writing the client's level storage (T5). Monolith arms reproduce the pre-tx
expressions character for character behind the same macro discipline as P4a.

Evidence: unit 2147/2147 incl. two named-Fatal death tests and the copies/no-copies
difference suite; DirectGLES.Split 104/104 on WSL GPU; red-once - reverting the adoption
to pointer-dropping turns exactly StagedTextureProductionTest red; the two monolith lane
failures reproduce on the base commit (DirectVulkan.IterationRPProgram203Scenario,
DirectVulkan.F1WireScenario.GenerateMipmapPackedFloatPixels). CONTRACT-P5C section 2.
2026-09-17 03:55:13 -04:00
swung0x48 db8b347952 [Fix] (Remote): preserve server ownership and wait for ring retirement 2026-09-16 13:39:50 -04:00
swung0x48 1646049ac9 [Fix, Test] (DirectGLES/Managers, MG_Test/Wire): M-3's two whole-store refusals key on the DESCRIPTOR's HasDefinedContent - content the application supplied (glBufferData(size, data)) must be fully staged by the draw, a gap is a missing record and Fatal{StageSnapshotTooNarrow} by name; a store the application orphaned (glBufferData(size, NULL)) has undefined bytes by its own declaration, so the streaming idiom (orphan, partial glBufferSubData, draw) uploads the staged bytes plus zero-fill exactly as the monolith arm uploads MappedData(); round 2 refused both shapes and aborted six LargeArenaAdoption / ResourceSubsystemControl joint entries by name (hidden under c1 round 2's BlobMissing abort until c1 round 3); two positive gates run the idiom end to end in a forked child through each reader and red on their own string when the refusal is made unconditional again 2026-09-16 10:31:29 -04:00
swung0x48 49fecc1686 [Fix] (DirectGLES/Managers, MG_Backend/Init, MG_Remote/Server): N-7 m-5's freed-base null is transport-guarded like the other two split hunks so monolith transport in a split build changes nothing by construction; N-8 the second consumer-mask check compares MGPipeGetResourceOps() against the table step 2 saw and refuses a replaced table as Fatal{ConsumerMaskLie, resource ops table replaced} (the re-run alone could not see a client-registered table); ServerVerbSink::ReadbackScratchBytes for ID-49's tight-size gate 2026-09-16 10:17:29 -04:00
swung0x48 c9d84e33c5 [Fix] (DirectGLES/Managers): under an active transport a resource_subdata that finds no twin MINTS one (GetOrCreateBufferResourceForHandle) so its bytes reach the server StagedShadowStore - the twin is otherwise lazy until the first draw (D-A2) and the reduced-path VBO bytes were lost, so the milestone frame rendered a shifted store; monolith keeps the lazy twin (R-11/ID-52 item 3) 2026-09-16 08:11:05 -04:00
swung0x48 455b475c5d [Fix] (DirectGLES/Managers, MG_Remote/Server): m-5 nulls a stale hostBytes only when its server shadow is actually gone (StagedShadowStore::HasShadow), not on a twins first-ensure generation sync - the unguarded null dropped a subdatas freshly staged base and made the reduced-path VBO read shifted; HasShadow unit control added 2026-09-16 08:03:52 -04:00
swung0x48 0fde95357c [Fix] (DirectGLES/Managers): under an active transport the server staged copy is the only base - liveHostBase no longer falls back to the client object (M-2); the pool-reuse and whole-store respecify readers go through RequireCoverage (M-3); a twin surviving DropAll has its freed hostBytes nulled (m-5) 2026-09-16 07:45:29 -04:00
swung0x48 377356f8ca [Feat] (DirectGLES/Managers, MG_Remote/Server): R-11 - copy staged bytes into a server-owned StagedShadowStore with exact coverage; Fatal{StageSnapshotTooNarrow} before the flush drain instead of a widened INVALIDATE_RANGE 2026-09-16 05:45:15 -04:00
swung0x48 3dadd4c1e0 [Fix] (DirectGLES): make the extent hostBase is good for a parameter of the flush ladder, so tier 1's widening refusal is live code the moment a SEG_STAGE snapshot is narrower than the queued range 2026-09-11 15:48:28 -04:00
swung0x48 142bf921d4 [Fix] (DirectGLES): retire the probe's last frontend read under split and refuse tier 1 of the flush ladder when the map and the queued range disagree in either direction 2026-09-11 14:31:46 -04:00
swung0x48 03082b8367 [Fix, Test] (clientsp, MG_Pipe, Espryt): produce kMGPipeBindSampler and kMGPipeBindShaderImage where D-A4 places them - nothing set either bit, so ImageBindableHint was always 0, the metadata respecify had no live trigger and the remint pull the hint prevents was neither prevented nor counted (final review M-A); the sampler-view resolution notes SAMPLER, glBindImageTexture's state setter notes SHADER_IMAGE at the bind (so the hint precedes the first sync) and the image walk notes it too, both through a contract door since neither may include TextureEmit.h, and Espryt counts every re-mint of storage it already held as tex-remint-pulls (trp= on the stats line, ROADMAP open question 2's number) 2026-09-09 00:09:30 -04:00
swung0x48 a25b997380 [Fix] (Espryt, Integration): compile the in-place storage-redefinition generation bump under MOBILEGL_PIPE_PUSH - it is Espryt code the pull build shares and G1 keeps the pull library byte-identical to the P4a baseline (0/0/2/0 on 419f9941), so the pull build keeps the pre-P4a hole until the bump lands on dev on its own and the F-3 texture cases decline by name there 2026-09-08 21:11:11 -04:00
swung0x48 ceb190d1c9 [Fix] (Espryt): re-sync a framebuffer's cross-object masks after an attachment's storage is redefined in place - a mutable texture regenerated on its driver id or a renderbuffer re-storaged on its moved neither the FBO memo's frontend versions nor the backend-id generation, so the pre-handle arm kept the widening masks of the storage the object was attached with; the renderbuffer half of the F-3 scenario asserts on the handle arm only, where the resource record closes D-D2 (found by the F-3 scenarios on the 0x1ff, 0 and pull lanes) 2026-09-08 20:50:25 -04:00
swung0x48 e9133d9e4e [Fix, Test] (Espryt): drive a unit's sampler through the CSO's own twin on the handle arm - the record arm looked a content-addressed handle up in the identity-keyed registry and could never hit, so only the pre-handle program pass ever put a glBindSampler'd object on the driver (P4a seam F-4) 2026-09-08 20:29:24 -04:00
swung0x48 9aa17cf7e6 [Fix] (Espryt): stop calling a texture that was never glTexParameter-ed a malformed record - ParamsSerial 0 means no set_texture_params was ever applied, so there is no built-in sampler to push 2026-09-08 18:14:22 -04:00
swung0x48 d4254ff023 [Fix] (Espryt): take the sampler CSO record from the handle the caller carries - a content-addressed record can never be named by the twins own identity handle, so every bound sampler objects parameters were refused on the integrated tree 2026-09-08 18:14:22 -04:00
swung0x48 bb07005fb7 [Fix] (Espryt): close the nine re-review minors - the framebuffer refusal now claims only what it can, the adoption refusals have a reachable caller, the carried region offsets and the sub-data resource byte are cross-checked, the remint-pull marker fires only when a level is owed, and a record-empty point the frontend still holds is refused 2026-09-08 18:14:22 -04:00
swung0x48 9eae68b516 [Fix] (Espryt): drop three #undefs for macros that were never defined and correct the attachment-version note that still called the record-driven walk another package's work 2026-09-08 16:57:36 -04:00
swung0x48 c0d5078298 [Fix] (Espryt): consume the carried region offset, refuse a record whose regions disagree about the level pitch, stop reading the frontend border form on the handle arm, and drop a nested guard that repeats its parent 2026-09-08 16:57:36 -04:00
swung0x48 532abce9fc [Refactor] (Espryt): resolve framebuffer attachments and the four cross-object masks from the record's surfaces, adopting each twin by the handle the record carries, and drop the registry release helper nothing calls 2026-09-08 16:57:36 -04:00
swung0x48 9102cff811 [Fix] (Espryt): allocate texture storage from the pushed descriptor, honour a metadata-only respecify's sticky mask, and arm the server's own re-dirty in the applier's pending set instead of a model the handle arm never reads 2026-09-08 16:57:36 -04:00
swung0x48 6013097a13 [Fix] (Espryt): decode the sub-data target's upload half through the contract's accessor, read the depth-stencil aspect and surface-kind constants c0c minted, and refuse bit 10 without bit 11 2026-09-08 16:57:36 -04:00
swung0x48 6e2e4c295d [Fix] (Espryt): resolve the framebuffer record by the handle it names and refuse before binding, so a DSA blit or clear configures the framebuffer it is about to write instead of one that never got its attachments 2026-09-08 16:57:36 -04:00
swung0x48 c64913307a [Refactor] (Espryt): take the sampler parameters and the program artefacts from the applier instead of the frontend objects 2026-09-08 16:57:36 -04:00
swung0x48 6b7475fea4 [Refactor] (Espryt): sync the driver framebuffer from the pushed record and answer the read buffer from the resolved read surface 2026-09-08 16:57:36 -04:00
swung0x48 e4208541e7 [Refactor] (Espryt): allocate renderbuffer storage from the pushed descriptor and keep the deferred out-of-memory report where it is 2026-09-08 16:57:36 -04:00
swung0x48 24c54bf4d7 [Refactor] (Espryt): drive texture storage, parameters and uploads from the pushed descriptors and take the upload strides from the record 2026-09-08 16:57:36 -04:00
swung0x48 86cfc379de [Refactor] (Espryt): key the texture, renderbuffer, framebuffer, sampler and program twins on the client-minted handle instead of the frontend object 2026-09-08 16:57:36 -04:00
swung0x48 83c8101a9b [Fix] (DirectGLES): record the fp64 narrowing's dropped SyncGpuWrites as a ruled P3a deviation at the site, with its blast radius 2026-09-08 07:00:28 -04:00
swung0x48 2a5e0195b8 [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 2026-09-08 07:00:28 -04:00
swung0x48 afda613bd9 [Fix] (DirectGLES): publish GLESBufferResource::hostBytes under pendingMutex - it was the one member the off-thread SubData/FlushRange arm wrote with neither a lock nor an atomic 2026-09-08 07:00:28 -04:00
swung0x48 9ba5d7ba1e [CI] (scripts, test.yml, DirectGLES): hash FlushPendingRangesFrom as G5's eleventh row - a push build compiles no FlushPendingRangesNow, so the tenth row protected text the shipping build never sees 2026-09-08 06:54:25 -04:00
swung0x48 78ff014547 [Fix] (MG_Impl, MG_State, DirectGLES): give the vertex-elements CSO a backend-neutral death path - the client minted every VAO's slot and only Espryt ever freed one, so under Magma each VAO leaked a slot and a 1.3 KB applier record for the life of the process 2026-09-08 06:49:59 -04:00
swung0x48 3c55e02797 [Fix] (Espryt): republish the live shadow base on the ensure path so a lazily twinned store is not left with none for the readers that hold no frontend object 2026-09-08 05:27:19 -04:00
swung0x48 75ea7ee2df [Fix] (Espryt): ask the frontend object whether the shadow the ensure path is about to upload holds bytes, instead of a descriptor no content call refreshes 2026-09-08 05:27:03 -04:00