Commit Graph
3235 Commits
Author SHA1 Message Date
swung0x48 3e1f1b71f3 Merge commit '01e00bc4' into codex/p5f-wave2 2026-09-19 22:43:51 -04:00
swung0x48 01e00bc495 [MG_Test] (Disaggregated): P5f fm - verify hookless texture staging lifecycle 2026-09-19 22:43:07 -04:00
swung0x48 777f706ca2 [MG_Pipe] (Disaggregated): P5f fm - retain texture staging without buffer backend ops 2026-09-19 22:42:07 -04:00
swung0x48 29ede72346 Merge commit '6a138a52' into codex/p5f-wave2 2026-09-19 22:41:57 -04:00
swung0x48 2d507d5bd4 [MG_IntegrationTest] (Disaggregated): P5f fm - cover bufferless draw and layered copies under role split 2026-09-19 22:41:47 -04:00
swung0x48 6a138a5221 [MG_Backend] (Disaggregated): P5f fm - fence remaining buffer debt and preserve native transfer layouts 2026-09-19 22:40:04 -04:00
swung0x48 d4ae45d6b8 Merge branch 'p5f/fm' of /mnt/c/Users/geekerwan/AndroidStudioProjects/FoldCraftLauncher/.git/modules/MobileGL into codex/p5f-wave2
# Conflicts:
#	MobileGL/MG_Pipe/PipeApply.h
#	MobileGL/MG_Remote/Server/PipeApplier.cpp
2026-09-19 22:36:56 -04:00
swung0x48 eb882ebf18 Merge commit '203f59cc' into codex/p5f-wave2 2026-09-19 22:34:51 -04:00
swung0x48 fec49a54d8 [MG_Backend, MG_IntegrationTest] (Disaggregated): P5f fm - apply bufferless draws and compute from server records 2026-09-19 22:34:28 -04:00
swung0x48 a6223c6509 [MG_Backend] (Disaggregated): P5f fm - order wire image writes and preserve implicit alpha 2026-09-19 22:34:04 -04:00
swung0x48 d9fc45bf4c [MG_Backend] (Disaggregated): P5f fm - use shared image access constant 2026-09-19 22:32:57 -04:00
swung0x48 f37380d0dc [MG_Backend] (Disaggregated): P5f fm - resolve uniform descriptors from server records 2026-09-19 22:32:10 -04:00
swung0x48 2abc561721 p5f fm: cover GPU texture writes and view subresources 2026-09-19 22:29:36 -04:00
swung0x48 277d1a07f0 [MG_Test] (Disaggregated): P5f fm - pin server program overlays and identities 2026-09-19 22:29:33 -04:00
swung0x48 867c5c5efd [MG_Backend] (Disaggregated): P5f fm - expose archive stage and capture-mode queries 2026-09-19 22:27:51 -04:00
swung0x48 31795675f1 p5f fm: build Vulkan samplers from server-owned values 2026-09-19 22:27:43 -04:00
swung0x48 62bf26bf8c [MG_Pipe] (Disaggregated): P5f fm - admit registered server object consumers independently of buffer ops 2026-09-19 22:27:03 -04:00
swung0x48 6ae5944831 [MG_Backend] (Disaggregated): P5f fm - build Magma programs from server archive views 2026-09-19 22:26:23 -04:00
swung0x48 a6283f40f2 [MG_Backend, MG_Impl] (Disaggregated): P5f fm - map texture view attachments through wire identities 2026-09-19 22:23:05 -04:00
swung0x48 203f59ccad [Docs, MG_Backend] (Disaggregated): P5f fe - report carrier retirement and verified gates 2026-09-19 22:20:57 -04:00
swung0x48 4b3afe7840 [MG_Backend] (Disaggregated): P5f fm - retain blit scissor clipping across wire arm 2026-09-19 22:20:53 -04:00
swung0x48 911cc74a57 [MG_Backend, MG_Impl, MG_Remote, CI] (Disaggregated): P5f fm - connect family records and preserve GPU texture writes 2026-09-19 22:18:24 -04:00
swung0x48 31e95b0794 [MG_Backend] (Disaggregated): P5f fe - clarify readback pack-buffer boundary 2026-09-19 22:16:02 -04:00
swung0x48 0ddfd18aac Merge commit '63c2a331' into codex/p5f-wave2 2026-09-19 22:15:14 -04:00
swung0x48 63c2a331a9 [MG_Remote] (Disaggregated): P5f fe - document handle consumers and capture ordering 2026-09-19 22:14:38 -04:00
swung0x48 40f083cfc6 Merge commit '19a4400a' into codex/p5f-wave2 2026-09-19 22:13:37 -04:00
swung0x48 19a4400ae8 [MG_Pipe] (Disaggregated): P5f fe - retain live capture snapshots across make-current 2026-09-19 22:13:14 -04:00
swung0x48 81d20554aa [MG_Test] (Disaggregated): P5f fe - expose capture snapshot loss across make-current 2026-09-19 22:12:36 -04:00
swung0x48 20bbf9647e [MG_Backend, MG_IntegrationTest] (Disaggregated): P5f fm - carry framebuffer copies and exercise Magma wire verbs 2026-09-19 22:11:38 -04:00
swung0x48 8a6e124f12 Merge commit 'b5c60d5a015c68348725ae93297b13a8fff27723' into codex/p5f-wave2 2026-09-19 22:10:26 -04:00
swung0x48 db9f95576e [MG_Test, MG_IntegrationTest] (Disaggregated): P5f fe - close scalar freshness and strict ratchets 2026-09-19 22:09:32 -04:00
swung0x48 b5c60d5a01 [MG_Remote, MG_Test, Docs] (Disaggregated): fix P5f fc wire replies and control-frame guards 2026-09-19 22:03:55 -04:00
swung0x48 a0004db9cb [MG_Pipe, MG_Test] (Disaggregated): P5f fe - derive scalar forwards and ratchet Espryt fatals 2026-09-19 22:02:23 -04:00
swung0x48 4593719a3c [MG_Backend] (Disaggregated): P5f fm - share native depth readback and retain masked clear behavior 2026-09-19 22:01:44 -04:00
swung0x48 036c3a3d5e [MG_Backend, MG_Pipe, MG_Remote] (Disaggregated): P5f fm - route framebuffer verbs through server records 2026-09-19 22:00:14 -04:00
swung0x48 881e050e2c [MG_Pipe, MG_Test] (Disaggregated): P5f fe - verify XFB snapshot fields and preserve spans 2026-09-19 21:58:27 -04:00
swung0x48 07bf8d7ce0 [MG_Pipe, MG_Remote, MG_Backend] (Disaggregated): P5f fe - carry XFB capture snapshots across Begin 2026-09-19 21:57:45 -04:00
swung0x48 fa1e1cc427 Merge commit 'd5ed139cc50f75a6e7f20eb0cff4a36c7e8b46be' into codex/p5f-wave2 2026-09-19 21:52:55 -04:00
swung0x48 85f3104731 [MG_Backend, MG_Remote] (Disaggregated): P5f fe - retire existing-carrier Espryt pulls 2026-09-19 21:52:35 -04:00
swung0x48 7d8c8b04b1 [Docs] (Disaggregated): P5f handoff - where the interrupted session stopped, and how to resume 2026-09-19 21:44:30 -04:00
swung0x48 d5ed139cc5 [MG_Remote, MG_Test] (Disaggregated): P5f fc - the EGL control plane crosses as value frames, not function pointers
The twelve Server* forwarders' one-slot mailbox carried a raw function
pointer plus a void* to a stack-local Args struct (P5c audit row G4);
neither means anything across a process boundary. The slot now carries
one SurfaceControlFrame by value: kind is the op, scalars are the
arguments, and ok/eglMajor/eglMinor come back in the same value. The
blocking handshake, the shadow, the doorbell order and the C2 exit
block are unchanged.

- protocol.fbs: append-only - SurfaceOpKind gains SetSwapInterval=8,
  ReleaseResources=9, SetWindowHandle=10; WindowKind gains MetalLayer=6;
  SurfaceOp gains readSurface and context (the MakeCurrent four-tuple).
  protocol_generated.h regenerated with the pinned flatc.
- Server/SurfaceControlFrame.{h,cpp}: the frame (trivially copyable by
  static_assert) and the op enum - ten wire kinds plus four inproc-only
  kinds (InitCapabilities is answered by CapsSnapshot on the wire,
  SwapBuffers/InitWindowSurface have no production caller - f0-egl F8,
  kept for the inproc test lane).
- Protocol/SurfaceOpCodec.{h,cpp}: the frame <-> SurfaceOp/SurfaceReply
  codec, the explicit WindowBackend <-> WindowKind table, and the wire
  entry ServerApplyWireSurfaceOp whose refusals are named:
  Fatal{UnmigratedSurface, "AndroidNativeWindow@P12"} and
  Fatal{ProtocolCorruption, "SurfaceOp"}.
- ServerLoop: RunOnApplyThread(fn, void*) -> RunSurfaceControlFrame(frame)
  plus the dispatch ApplySurfaceControlFrame; the old per-forwarder Args
  bodies moved into the dispatch unchanged (C7/ID-54, N-3, R-12 included).
  RunProbeOnApplyThreadForTesting is the test seam through the same
  channel (the hook lives in a member, never in the slot).
- Tests: RemoteClientTest/ServerLoopTest migrated to the probe seam; new
  SurfaceControlFrameTest suite (mapping tables, wire round-trips, the
  two named refusals) plus ServerLoopTest's AVoidForwarderCrossesAsOne-
  DispatchedFrame (the frame channel's red-once handle) and
  ServerLoopEglTest's TheInitializeDisplayReplyArrivesThroughTheFrame.
2026-09-19 20:30:21 -04:00
swung0x48 418c765c58 [Docs, MG_IntegrationTest] (Disaggregated): P5f f1 report - the census ratchet's first version (6 pairs), CONTRACT-P5E section 3.2 marked landed, and the gate numbers 2026-09-19 10:39:40 -04:00
swung0x48 cfcc12f73a [MG_Backend, MG_Impl, MG_Remote, MG_Test, MG_IntegrationTest, CI] (Disaggregated): P5f f1 - the dual-block rehearsal: per-role PipeInputs, the MOBILEGL_IPC_ROLE_SPLIT_STATE knob, and the named-Fatal arm that makes the red a census 2026-09-19 09:59:33 -04:00
swung0x48 e75e00cb7a [Docs] (Disaggregated): P5f f0 - the eight-way read-only census reports
Statics, reverse channel, Magma cross-role sites, EGL control plane,
registry rekey, build/gate mechanics, the 15 BARRIER_PULLED fields'
carrier rulings, and the dual-block mechanism's design recon.
2026-09-19 09:08:56 -04:00
swung0x48 8b68b92c76 [Docs] (Disaggregated): P5f section 1 - the pointer fact, and one draw's full lifecycle through gPipeInputs
The section explained what gPipeInputs IS and what breaks under spawn, but not the one fact
that decides the shape of the fix, and not how a call actually reaches the driver through it.
Both are now in the document rather than only in the conversation that found them.

- THE POINTER FACT, now stated first because everything else follows from it: several
  BARRIER_PULLED fields do not hold values, they hold pointers into client-owned objects.
  PipeFill.cpp:274 fills m_textureUnitBase with `&ctx.GetTextureUnitObject(0)` - a raw base
  into the frontend's array - and :245 fills m_programForDraw with a SharedPtr<ProgramObject>.
  PipeInputs.h:669 dereferences it as `m_textureUnitBase[unit]`. PipeFill.cpp:2591-2592 says
  the same of the shader-buffer field: "four raw bases into the frontend's binding-point
  table".
  The consequence gets its own paragraph in 1.4, because it is the step most likely to be got
  wrong: this CANNOT be fixed by moving the block into shared memory. Mapping the same pages
  into both processes does not make a client heap address meaningful in the server, and a
  SharedPtr's refcount does not cross at all. The 15 fields each need a different SOURCE, not
  a shared location.

- NEW 1.2, one draw end to end: glBindTexture marks a tracker bit and sends nothing, because
  push only happens at a verb boundary; glDrawArrays enters MGPipeValidateForVerb
  (PipeFill.cpp:3347) whose four steps are barrier decision, dirty walk, emission (records,
  carrying handles), and the residual fill - which is where BARRIER_PULLED happens; the record
  goes on SEG_CMD; the apply thread dispatches to the backend; PrepareForDraw reads either a
  record-carried handle against the server's own tables, or gPipeInputs; then the real driver
  call. Plus the field lifetime: stamped with verb N's serial, read during verb N's apply,
  Fatal{UnmigratedPipeInput} if read at verb N+1 without a refill - one verb, never longer.

- The same example carries the Espryt/Magma split concretely: the texture binding reaches
  Espryt as a record with a handle (P5e retired GetTextureUnitObject for it) and reaches Magma
  through gPipeInputs into the client's array. That is FieldOwnership.def's own
  "P5e (Espryt unbarriered), P7 (Magma)" made legible, and it is why section 2.1's table has
  eight rows in that state.

Sections renumbered 1.1-1.4. Doc citation lint: 129 citations, 0 problems.
2026-09-19 06:02:28 -04:00
swung0x48 465656843b [Docs] (Disaggregated): P5f - every piece of state on the wire, and P6 is blocked until it is
P6's premise is that it is "only a transport swap". That premise was bought by P5c and has
expired. Measured on this head, the two roles still share state directly, so a spawned server
would have no source for it. P5f is the phase that makes the premise true, and P6 does not
start before it.

WHAT THE MEASUREMENT FOUND

- FieldOwnership.def still carries 21 BARRIER_PULLED rows over 15 distinct fields. That class
  is defined as "the server answers by reading a value the client's residual fill left in THE
  SINGLE SHARED gPipeInputs while the verb barrier holds both threads apart". Eight of those
  fields were retired by P5e for Espryt's unbarriered path only - Magma has not moved at all.
  The strict lane measures 10 live <field>@<verb> pairs today.
- gPipeInputs (MG_Backend/MGPipe/PipeInputs.h:835) is a plain process global,
  `inline PipeInputs& gPipeInputs = *new PipeInputs();` - not a shm segment. The client fills
  it (MG_Impl/Pipe/PipeFill.cpp), the backend reads it. Under spawn the two processes have
  DIFFERENT objects, the 15 BARRIER_PULLED fields have no filler in the server's copy, and
  every read is Fatal{UnmigratedPipeInput}. MG_Impl is not in the server, so "let the server
  fill it" is not available either. The header says this itself at :279 and :902.
- The twelve Server* EGL forwarders do not use the wire at all: they post a function pointer
  plus a stack-local void* through a one-slot mailbox (ServerLoop.cpp:533-568, :645). The
  SurfaceOp / SurfaceReply / WindowKind schema is defined in protocol.fbs and unused.
- Process-level statics with per-context semantics (g_syncedRenderStateParameters,
  ScopedDefaultUnpackState::s_synced) - and the full list is unknown, because this defect class
  is structurally invisible to inproc.
- MGPipeFrontendKeyedRegistryScope is still live at ~12 sites in DirectGLES.cpp, carrying
  P3b/P4b's debt: the registry is still keyed by frontend address / lifetime id.

THE SCOPE RULE

P5f takes the cross-process-blocking subset of P3b/P4b/P7/P8/P9 and nothing else. One test:
does it still hold in another address space? No -> P5f. Yes but slow or ugly -> it stays with
the phase that owns it. So Magma's nine fields and its direct writes into client storage come
here; content-addressed CSO, internal shader baking and the fixed-width rewrite stay P7's. The
reverse channel's asynchrony and ordering stay P9's; only the parts that touch client memory
move. Class C is NOT P5f's - a named refusal behaves identically in two processes.

THE CENTRAL MECHANISM: A TWO-BLOCK REHEARSAL

P5c set the same rule (rule E) and checked it by AUDIT - a human reading 59 lines. P5f checks
it by MACHINE: give each role its own PipeInputs under inproc, and its own copy of every
per-context static, behind a knob. Anything that depends on the two being the same object
becomes Fatal{UnmigratedPipeInput, "<Field>@<Verb>"} with the field and verb named.

That rehearses the process split's SEMANTICS without a second process. It matters because
today "the server read the value the client filled" and "the server read the value a record
carried" are indistinguishable at runtime - which is exactly what P6 would discover on day
one. The package order puts the mechanism (f1) BEFORE the migrations deliberately: let the red
appear first and let it be the worklist, rather than having each package declare itself done
and then looking for a criterion.

Exit gate: the two-block lane green; strict-expected-markers.txt EMPTY with its two-sided
ratchet still armed; zero BARRIER_PULLED rows; rsp reading zero per frame; Magma judged by the
same criteria as Espryt. The negative control is that turning the two-block knob OFF must move
at least one named case from green to red - otherwise the mechanism proves nothing, which is
ID-122's lesson.

ALSO IN THIS COMMIT

- ROADMAP gains the P5f row and the IPC track becomes P5e -> P5f -> P6; P6's status cell
  becomes "blocked on P5f".
- README and CURRENT_STAGE_PROGRESS gain the same, plus the file-map entry.
- Both P6 documents gain a blocked banner naming what is not true yet.

Doc citation lint: 124 citations across docs/Disaggregated/*.md, 0 problems.
2026-09-19 05:32:38 -04:00
swung0x48 7f1d2134c3 [Docs] (Disaggregated): P6 contract draft rewritten in concise wording, 269 -> 181 lines, same rows 2026-09-19 04:39:12 -04:00
swung0x48 e125b75655 [Docs] (Disaggregated): P6 plan rewritten in concise wording, 282 -> 124 lines, same content 2026-09-18 23:40:26 -04:00
swung0x48 aba329cc53 [Docs] (Disaggregated): P6's plan and contract draft; the working notes move from a local directory into the repository
Two things land together: the plan and contract draft P6 needs before it starts, and the
working notes that until now existed on exactly one machine.

1. P6's plan and contract draft (neither started; not one line of code)

     docs/Disaggregated/P6-SPAWN-PLAN.md      the package plan
     docs/Disaggregated/P6-CONTRACT-DRAFT.md  the contract draft (moves to
                                              MG_Remote/CONTRACT-P6.md when c6 lands)

   The three findings that mattered, all written into the documents:

   a. P6 is SMALLER than its roadmap cell suggests. The transport primitives are already in
      the tree and already tested: SocketDoorbell including hangup detection and the two
      lost-wakeup fences (Doorbell.cpp:211-360, four cases in FdPassingTest), SCM_RIGHTS fd
      passing, ShmSegment::Adopt, and the SurfaceOp / WindowKind schema already defined in
      protocol.fbs. inproc uses a real second shm mapping rather than an alias, and
      SessionRings.h:22-28 says that was done so today is not the first time it runs. P6 is
      assembly plus a control plane plus a process, not "write a socket transport".

   b. The evidence for "P6 is only a transport swap" has EXPIRED. It was bought by P5c, whose
      audit found 59 direct memory accesses in a tree that already looked clean. P5e changed
      the tree again. So the first package, a6, is a read-only audit that writes no code, and
      every contract row that depends on it is marked PENDING a6 rather than decided in
      advance.

   c. P6 does not get a game running on the phone. ANativeWindow* is meaningless in the child,
      and protocol.fbs:186-196's own comment says Android transfers the window out of band -
      that band is P12. P6 lands pbuffer / surfaceless / offscreen, which is what HeadlessGL,
      the split-equivalent lane and trace replay need, and which is exactly what P6's own exit
      gate measures. A real window reaching the server is a named refusal. This gets its own
      section because "P6 is done" would otherwise read as "the game runs now".

   The contract adds rule G: a role may not name a process-local handle. It extends P5c's
   rule E (a role may not name the other role's memory) from memory to identity - EGLDisplay /
   EGLSurface / EGLContext / ANativeWindow* / fd number / pid / mapped address either cross as
   a token this contract defines or they do not cross, and a descriptor crosses only through
   SCM_RIGHTS, where the kernel renumbers it.

   What P5e left for P6 gets its own section. The latch semantics are already designed
   (ARCHITECTURE.md:504) and are copied unchanged. What is new is that after run-ahead the
   client no longer waits while the peer process can DIE: the client holds records that were
   published and will never be applied, and Android's freezer suspends the child without
   closing anything. So slow and dead must be distinguishable WITHOUT a timeout threshold.
   That is P6's only new design; everything else is carriage. It shares a predicate with E1's
   outstanding re-specification (ID-122), and the two should be designed together.

   Two gates carried over from P5e's lessons: G2 requires integration-spawn's test-name set to
   match integration-split's name for name, because a differing set means the lane is quietly
   running less; and the arm-proof gate requires every entry to record the child pid and
   transport=spawn in its OWN private log - ID-124 established that this kind of false green
   really happens, and a spawn lane that actually ran monolith would pass every other gate.
   S2's shape must be settled before it is written, and the document says why: E1 is the
   cautionary case.

2. The working notes move into the repository (docs/Disaggregated/notes/, 415 .md files)

   ROADMAP / CURRENT_STAGE_PROGRESS / MEASUREMENTS cite ruling numbers, audit line numbers and
   the provenance of gate figures from ~/w7/notes/, a directory that exists on one machine and
   is under no version control. A record cited hundreds of times that lives only locally is not
   a record, so it moves in whole, with its directory structure intact.

   Only .md moves. Scripts, run logs, census and gate result JSON, patches, APKs and nm dumps
   stay where they are: they are evidence DATA rather than documents - large, regenerated per
   run, and mostly carrying absolute paths and device serials that mean something only on the
   machine that produced them. The mapping and this split are written in
   docs/Disaggregated/notes/README.md.

   Two exceptions are recorded there too: P6's BRIEF has been promoted to a first-class
   document and keeps no copy under notes/, so the two cannot drift apart; and recovered/ holds
   material salvaged from failed workflow runs, which may duplicate the like-named phase
   directories and is kept because a few of those were the only complete version at the time.

   CI's citation lint takes docs/Disaggregated/*.md only (non-recursive), and notes/ is
   deliberately outside it: those notes' file:line citations were written against their own
   code heads, and resolving them against today's HEAD would fail wholesale - which is not an
   error, it is their correct state as a historical record. To check one, use the revision it
   declares (--rev).

3. Inconsistencies fixed in passing

   - README.md's status line still said P5e was in progress while the stage table already said
     closed.
   - CURRENT_STAGE_PROGRESS's next-step item 1 still listed the exit gate as pending, though
     (a) and (b) were run in the previous commit; rewritten to closed plus the one item that
     actually remains (E1).
   - ROADMAP's P6 row still had the pre-phase plan in three of its cells; it now carries the
     package order, the scope boundary and the two new gates.

Checked with check_doc_citations.py: 125 citations across docs/Disaggregated/*.md, 0 problems.
2026-09-18 23:31:39 -04:00
swung0x48 edd0fef5cd [Docs] (Disaggregated): P5e closed - the exit gate run item by item, with one named outstanding item
It said "in progress" because BRIEF-P5E section 3's exit gate had never been RUN, not because
the work was unfinished. It has now been run, item by item, recorded in ROADMAP's P5e
exit-gate cell:

- item 1: unit 2256/2256 under both strict arms.
- item 2/3: integration-split 179/179; the per-entry census has zero Fatal{ and exactly eight
  Admitted{ rows.
- item 4(a): RUN_AHEAD=0 as the PAIRED control, 179/179 green - same server code, same
  records, the only difference is whether the client waits.
- item 4(b): VERB_BARRIER=0 goes red (62/179 in the lane).
- item 4(c): Magma logs, verbatim, "run-ahead requested, server does not publish
  kCapRunAheadApply - running lockstep", and the Espryt control logs "run-ahead ARMED". Both
  taken from each entry's own private log.
- item 5: red-once rerun on the integrated tree, in the form ID-121 reordered it into -
  reverting pa's arm yields GetProgramForDraw@DrawArrays, reverting mv's yields
  GetBoundVertexArray@DrawArrays, EXACTLY ONE NAMED PAIR EACH, and each restores green.
- item 7: MOBILEGL_IPC_AUDIT=1, 179/179.
- item 6's G1 remains CI's to assert (ID-123).

The only item that does not pass is E1's control script itself (ID-122), and the diagnosis is
sharper than before: with its two masking defects fixed it is still red, and the
Fatal{BarrierViolation} it demands appears ZERO times in the whole run - at BATCH_WAITS's
default of 1 that overlap does not happen, and with run-ahead armed VERB_BARRIER=0 also
disarms run-ahead (ID-114), so the arm it produces is neither lockstep nor run-ahead. E1 needs
its falsification target redefined, not its threshold adjusted.

So the status is "closed, with one named outstanding item" rather than an unqualified close:
hiding a control that never passed behind the word "closed" is precisely the class of mistake
this phase kept recording.
2026-09-18 21:54:11 -04:00