Commit Graph
48 Commits
Author SHA1 Message Date
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
swung0x48 0d747da470 [Docs] (Disaggregated): ROADMAP's P5e row had only its status cell updated; the other three were still the pre-phase plan
The previous commit changed the status cell to "twelve packages landed, run-ahead armed" and
left the scope and exit-gate cells saying eight packages, 19 rulings, "the integration commit
flips kMGPipeP5eRunAheadReady", and an exit gate drafted BEFORE the phase started - several of
whose items later proved unexecutable as written. All three cells are rewritten:

- Scope cell: twelve packages in three waves (including fix1 / pa / mv / gl / ra2), rulings
  ID-80..136, both constants flipped. It also names the largest migration (the per-draw
  GetProgramForDraw) as having changed NO wire structure at all - the record already carried
  the per-link ProgramArchive, and what was missing was a reader that still asked the frontend
  object. Links to P5E-RUNAHEAD.md.
- Exit-gate cell: rewritten into what was actually measured (unit 2256, integration-split
  179/179, integration-gpu 1357/1357, three flavours with each arm asserting its EFFECTIVE
  compile define, strict hard green with zero Fatal, the device at VD32 level with monolith and
  +69% p50 against lockstep), plus what has not been executed (the three negative controls, the
  per-package red-once reruns, E1's control failing its own self-check, G1 still asserted by
  CI), plus the criteria that are now VOID (rsp = 0 is empty by construction, rewritten by
  ID-119; VERB_BARRIER=0 may not serve as the paired control, ID-114, because it also disarms
  run-ahead).
- Debt table, rsp row: P5e rewrote what that number means. It now reads as the hard-green lane
  plus eight Admitted rows, and says why the original criterion was empty - CountBarrierPull's
  unbarriered arm sits before ++g_residualPulls and is [[noreturn]].
- Debt table, unmigrated row: client vertex arrays are a named refusal under run-ahead
  (ID-82) and have their own expected-red lane, integration-clientarrays-split (ID-134);
  staging stays P8's.
- Open question 18 added: the two sides of split are unbalanced (at VD32, apply 11-12 ms
  against client 15.7 ms, with the client ~94% saturated). Moving work from client to apply
  lowers the bottleneck directly - meaningless under lockstep, where the two add serially, and
  a lever only because of run-ahead. It needs a fresh profile first: with the wait gone, every
  tail item's denominator has changed.
- The header status line gains the P5E-RUNAHEAD.md link.

Doc citation check: seven files under docs/Disaggregated, 58 citations, 0 problems.
2026-09-18 21:35:38 -04:00
swung0x48 be345d711c [Docs] (Disaggregated): P5e progress, in full - the landed-content table, open items, ruling index and phase report
- New P5E-RUNAHEAD.md: P5e's phase report, a sibling of P5D-INPROC-PERFORMANCE.md. It carries
  the twelve-package list, the three defect classes and the lesson each one cost (a runtime arm
  no gate covered / build flavours no gate covered, where the FIRST gate added for them was
  itself a false green / a guard that could never fire), the profile and both device tiers, the
  unfinished items, and the next opportunity run-ahead unlocked.
- CURRENT_STAGE_PROGRESS.md: the stage table's P5e row becomes twelve packages + run-ahead
  armed + ID-80..136; new section 2.7, the P5e landed-content table, in the same shape as
  P5c's and P5b's; section 2.5 retitled as historical; two sections both numbered 4 fixed; five
  P5e entries added to the open items; next-step item 1 rewritten from c0e to the evidence the
  close still lacks; the ruling index extended from ID-79 to the load-bearing entries of
  ID-136.
- ROADMAP.md: the P11 row gains P5e's correction - retiring the draw lockstep did NOT need
  gPipeInputs versioning, because that race was in the metadata scalars. The row still holds
  for the general case, and contract section 3.2's per-role stamp storage is still unlanded.
- README.md: the status line gains P5e and run-ahead, and "next is P6" becomes "P6 comes after
  P5e".

Doc citation check: 3 problems, all pre-existing entries in CONTRACT-P5.md, none related to
this change.
2026-09-18 21:30:29 -04:00
swung0x48 45664725f8 [Docs] (Disaggregated): P5e - the render-distance 32 comparison, where inproc draws level with monolith
Section 11's matrix ran at VD12, where BOTH monolith and run-ahead hit the 120 Hz panel
ceiling - so that section answers "can it reach the ceiling", not "which is faster". At render
distance 32 the load rises to ~3550 draws/frame (4.2x) and neither arm is near any cap (the
game's own enableVsync:false / maxFps:260, and the measured max is only 37-71). That is the
comparable round.

- Five runs per arm, interleaved, CPU clocks pinned (checked before AND after, both PINNED),
  GPU held at pwrlevel 0, fan on; 75-150 s in-world settle before a 40 s window - VD32's chunk
  streaming runs far longer than VD12's and reusing the 20 s settle would have counted loading
  as steady state.
- monolith p50 median 58.5 (range 56.3-67.9), inproc run-ahead p50 median 59.9 (range
  56.8-61.1), client CPU 16.19 vs 15.72 ms/frame. Level, run-ahead marginally ahead, and with
  half monolith's spread.
- Against the lockstep it replaces: p50 +69%, client CPU -40%, apply CPU -43%. The heavier the
  load the more it is worth, which is what the mechanism predicts: rendezvous count follows
  draw count, ~900 per frame at VD12 and ~3600 at VD32.
- Both arms are client-thread saturated (~94%), so the client ms/frame column is each arm's
  real bottleneck and the two are directly comparable.

New section 11.1 records an OPPORTUNITY rather than a defect: apply spends 11-12 ms against
the client's 15.7 ms, so the two sides are unbalanced and moving work from client to apply
lowers the bottleneck directly. Under lockstep that was meaningless (the two sides add
serially); run-ahead is what turns it into a lever. Left to a later phase.

options.txt restored from .p5e-backup to renderDistance:12; the device is unpinned, fan off,
GPU back to governed.
2026-09-18 16:00:46 -04:00
swung0x48 8943af73e6 [Docs] (Disaggregated): P5e wave 3 - the strict lane goes hard green, run-ahead is armed, the device matrix is written back
- CURRENT_STAGE_PROGRESS.md gains section 2.6: the four packages (pa / mv / gl / ra2), the
  admission rule's three disjuncts and which real entry forced each one, coverage going from
  116 to 179 entries plus 1357, the race the flip exposed and its root cause, and the finding
  that a hard-green strict lane is necessary and NOT sufficient (ID-132). Code head is now
  25fba0d5.
- MEASUREMENTS.md gains section 11: the device matrix. The section leads with clock pinning
  because the first matrix was run without it and had to be thrown away - monolith's OWN arm
  moved 4.43 -> 7.07 ms/frame between two runs, and the SLOWER run was the COOLER one: the
  governor had dropped policy0 from 2745 to 748 MHz. It records pin_redmi.sh's write order and
  read-back verification, and why pin_device.sh refusing to guess this machine's serial is
  correct rather than a gap. Conclusion: at both pinned tiers monolith and run-ahead each hit
  the 120 Hz panel ceiling and only lockstep cannot reach it.
- ROADMAP.md's P5e row and status line now say twelve packages landed, run-ahead armed.

The phase is NOT closed: which arm is faster ABOVE the panel ceiling is unanswered (this
device cannot hold a higher clock), and BRIEF-P5E section 3's three negative controls and
section 5's per-package red-once reruns have been reordered by ID-121 to after the lane goes
green, so they have not been executed yet.
2026-09-18 14:57:36 -04:00
swung0x48 7c6f6886ff [Docs] (Disaggregated): P5e 进度、monolith 回归与设备验证写回
- CURRENT_STAGE_PROGRESS.md 新增 2.5 节:八包落地情况、设备验证发现的 monolith SIGSEGV 及其
  根因/覆盖漏洞/修复(ID-107 -> fix1 -> ID-109/ID-110)、头 3cc4e1ec 的逐门数字、三臂设备结果。
  代码头更新为 3cc4e1ec。
- MEASUREMENTS.md 新增 10 节:主机门在 44f91c74 与 3cc4e1ec 的对比(integration-gpu 1157/1294
  -> 1294/1294 是本阶段最重要的一个数:那 137 个 SEGFAULT 当时没有任何门禁步骤会看到)、
  设备四行、以及本轮与上一轮的测量纪律四条。
- ROADMAP.md 的 P5e 行与状态行标注八包全落地与当前头。

阶段未收官:kMGPipeP5eRunAheadReady / kMGPipeP5eClientWaitRuleLanded 仍为 false,翻转门是
BRIEF-P5E 3 节(strict 硬绿)与 4 节(设备出口)。
2026-09-18 10:11:19 -04:00
swung0x48 6ee4c0979b [CI, Docs] (Disaggregated): P5e ra - the strict lane becomes one step with two arms, and §11/§14/§17 say what landed
- CONTRACT-P5E §7. integration-split-strict was an EXPECTED-RED control: every entry
  aborts on its first BARRIER-PULLED read, so the step gated on the run failing for
  that reason. After the flip it is a HARD GREEN GATE - an unbarriered record's pull is
  Fatal whatever the knob says (§3.3), so strict adds only the barriered rows, and those
  are a short named allowlist of <field>@<verb>. A revert of any handle arm in
  vi/sb/pg/tx2/fb then goes red HERE, by field and verb, instead of in a picture.
- THE ARM IS CHOSEN BY THE TREE. The step greps kMGPipeP5eRunAheadReady out of
  MG_Backend/Init.cpp, which is the one constant the integration commit flips and is
  exactly the fact the lane's expectation depends on. A lane whose flip is a separate
  human step is a lane that is wrong for as long as that step is outstanding - and the
  pre-flip arm is unchanged, so this commit moves no CI verdict today.
- The allowlist names the package that retires each row: readbacks and the pack PBO
  (P8/P9), the CopyTex endpoint and GenerateMipmap (tx2), set_storage_block_binding
  (pg), XFB (P3b/P4b/P9), resource_copy_region's GL names (the declared P5b debt). A
  row leaves it by deletion, never by widening. The lane also warns on a non-zero rsp,
  which after P5e can only be a barriered row.
- The allowlist is built with printf rather than a heredoc: a quoted heredoc's
  terminator has to start at column 0, which inside a YAML block scalar would end the
  scalar instead of the heredoc.
- ARCHITECTURE §11.6: the wait rule is the generated WaitClass column now, not the call
  class, and it REPLACES the BatchWaits skip; glFinish stops being a no-op under
  run-ahead; the forced waits (EGL forwarders, the map/readback family) and glGetError's
  named window are listed. §11.7: the P9 plan is code - the producer blocks, the drain
  clears AND rings, the client's parks break on the latch, and two named refusals remain
  for the impossible cases. §14: the present credit is client-minted, 1-based, one per
  swap, paid before the encode. §17.7: what P5e is, in one section - the predicate, rule
  F, gPipeInputs' ownership, the latch and the control arms.
- 附 A gains MOBILEGL_IPC_RUN_AHEAD and moves MOBILEGL_IPC_PRESENT_CREDIT out of the
  "P6+" line: a knob listed as not-yet-effective while it paces the frame is how an A/B
  stops being one.
2026-09-18 08:22:49 -04:00
swung0x48 b4cf9b0527 [Docs, MG_Remote] (Disaggregated): P5e c0e - the contract lands, and the roadmap row
- MG_Remote/CONTRACT-P5E.md: the draft edited into its landed form. The nineteen rulings are
  as the integrator decided them (ID-80..98) and are restated here rather than referenced,
  because a package reads this file and not the brief. The "draft" wording is gone and every
  file:line was re-resolved at this head.
- FOUR PLACES WHERE THE PLAN WAS WRONG AND THE CODE IS RIGHT, each argued where it sits: the
  descriptor has no spare byte so MGPProgramDesc grew 192 -> 200; the applier's per-class
  windows are ShaderBufferStart/Count/WritableMask, not bare Start/Count/WritableMask; the
  three suppressor slots are named per Class; and the wire codec's layout carries three tails
  now, because set_program_bindings has three and the third one's offset is derived from the
  first two.
- One finding the contract now carries rather than leaves for sb to discover: MGPShaderBuffers'
  WritableMask is a Uint32 and the window is 84, so the mask can only describe the first 32
  points of a class. sb asks for the ruling; it is a wire field and not a package's to pick.
- A new section 10 lists, by name, every symbol c0e put in the tree and what each package
  compiles against - plus the three red-once evidence lines.
- ROADMAP.md gains the P5e row after P5d (status, the eight packages in dependency order, the
  integration gate and the device exit) and the two lines that said P6 was next now say P5e is.
  CURRENT_STAGE_PROGRESS.md section 1 gains its row and section 6 its next-step entry.
2026-09-18 06:49:46 -04:00
swung0x48 2fde70341d [Docs] (Disaggregated): P5d round 3 close-out - the report, the measurements section and the roadmap row
- P5D-INPROC-PERFORMANCE.md: the round-2 diagnosis is corrected against the
  symbolized call graph (the apply thread's mutex time was the idle poll, not
  the backend pendingMutex), the four round-3 packages and the two race fixes are
  described, the numbers table carries the two device caveats (monolith is
  120 Hz vsync-capped in most runs; the kernel ignores thread affinity, so the
  client thread runs on a mid core), and the lockstep-feasibility research says
  why the deferred draw barrier waits for P3b/P4b and P11.
- MEASUREMENTS.md section 9: the per-arm table with per-thread CPU ms/frame as
  the primary metric, the interleaved session and the wait/park counters.
- ROADMAP.md: the P5d row is the three-round shape; P11 gains the gPipeInputs
  versioning item the research points at.
- CURRENT_STAGE_PROGRESS.md, README.md, ARCHITECTURE.md (env table: the
  generate_mipmap exception to batched waits, the calibrated spin, the affinity
  readback): head 1f8de61b, the gate numbers and ruling ID-79.
2026-09-18 04:30:38 -04:00
swung0x48 85362a856d [Docs] (Disaggregated): P5d close-out - the inproc performance report and its roadmap row
P5D-INPROC-PERFORMANCE.md states what the phase set out to do (inproc frame
rate comparable to monolith at VD12 without touching wire semantics or the
correctness gates), what the two landed commits did (cb06538c, 56a77348:
7-13 -> 63-65 fps against monolith 110-118, pmap 25 MB/frame -> 0.23
MB/frame), and what is explicitly not done - the backend sync mutex complex
(~48% of the apply thread's own time), the R-1 serialization (P11's
versioned inputs), the emutls/set-hash small items, and the verification
debt (79-trace set, Redmi retest window, arm64-only design note, the
uncommitted FCL-side test plumbing).
2026-09-18 02:29:36 -04:00
swung0x48 cb06538c06 [MG_Remote, MG_Pipe, MG_Impl, MG_Test, MG_IntegrationTest, Docs] (Disaggregated): inproc performance package - dirty-driven persistent-map push, batched barrier waits, spin-clock batching
VD12 Minecraft on the Redmi (FCL, DirectGLES): the split's in-world frame rate
13 -> 60-66 fps against monolith's 110-114, and persistent-map wire bytes
25 MB/frame -> ~0.23 MB/frame. The residual split-specific costs are named at
the end, not hidden: the R-1 serialization (WaitForApplied ~12%, P11's
versioned-inputs design) and a split-only mutex complex still under
investigation.

Persistent-map push, three arms picked per buffer at map time:
- mprotect dirty tracker: the mapped range's page-aligned interior is
  protected PROT_READ; the app's next write faults, the SIGSEGV handler marks
  the page in the slot's bitmap and unprotects, and the push ships one 64 KB
  block per block containing a faulted page. Ownership is three tests -
  SEGV_ACCERR only (a userspace raise and an unmapped page chain verbatim),
  inside a live tracked range, and not a refault on a still-set bit (a write
  we unprotected succeeds, so that is a non-write access and it crashes
  honestly). The alignment is INWARD: an outward-aligned edge page holds
  foreign bytes, and a signal-blocking worker thread faulting on one is a
  process kill - that was the ctest-only SmallRing segfault. Edge spans
  (at most two per map) are hashed per push and ship their containing block
  only on change (unconditional edges measured 112 MB/frame). Re-arm is one
  mprotect per contiguous run. The first push ships everything once.
- hash-suppress arm (MOBILEGL_IPC_PERSISTENT_HASH_SUPPRESS, default 1):
  per-block XXH3 against the last push's hashes; untracked buffers only.
- PushDrawConsumers: only the buffers the upcoming draw/dispatch can read
  (VAO attribs/element, indexed binding points, indirect/parameter slots,
  TexBuffer backing - the last also retires the per-frame-cadence cloud
  twitch), plus the fault-epoch skip: an unmoved epoch proves no interior
  byte changed, tracked edges are hashed in place, and any hash-arm member
  vetoes. The membership map caches the tracker slot pointer (a 64-slot
  rescan per buffer per draw was measured and removed).

MOBILEGL_IPC_BATCH_WAITS (default 1; MOBILEGL_PIPE_VERIFY forces 0): a
value-class record (kCtxState/kCtxCso/kCtxObject with no reply slot) is
published without waiting for its own apply; the barrier is taken at the next
pull-reading verb, the only place BARRIER-PULLED fields are read, so the R-1
fence posts are untouched and only the round trips between them change. Two
consequences are pinned rather than argued: kCtxObject verbs the tests read
synchronously get explicit fences (GenerateMipmapFieldsCross,
FramebufferDeathCrosses), and a frontend object whose last SharedPtr drops on
the apply thread - impossible before batching - now enqueues its
(kind, lifetimeId) on the deferred destroy queue and the GL thread replays
the DestroyAndFree helper at the verb hooks (CopyImageLayeredScenario aborted
Fatal{RoleViolation, MGPipeSlots} without it).

Doorbell::Wait's spin reads the clock once per 64 yields: on the workload
device a steady_clock read is a real syscall (no vDSO) and the per-iteration
reads were ~20% of the whole process at ~1000 waits/frame.

Gates: gen_pipe --check/--self-test green; unit 2188/2188;
integration-split 110/111, the one red being GenerateMipmapDepthPixels whose
DirectGLES and DirectVulkan MONOLITH siblings flake identically with every
code path of this package provably inert (PushIsArmed false, no ClientSession,
deferral's monolith early-out).
2026-09-18 01:58:59 -04:00
swung0x48 7cdc8d775e [Docs] (Disaggregated): refresh the P5c close-out status lines - README and ARCHITECTURE section 17.6 were still describing P5c as planned, and the code head is the triage head b88e8487 everywhere 2026-09-17 18:57:14 -04:00
swung0x48 36176b9dbc [Docs, MG_Remote] (Disaggregated): close out P5c - the inproc split's direct cross-role access is zeroed
ROADMAP marks P5c closed at the triage head and P6 next; CURRENT_STAGE_PROGRESS carries
the current-head gate table (unit 2187/2187, integration-split 111/111, the census
classification with every newly-red entry evidenced by its Fatal name, the three named G1
resizes, the 0xDD audit, the per-frame rsp measurements, and the two items deliberately
not done locally: the Redmi retest and the 79-trace census); MEASUREMENTS gains section 8
with the per-gate evidence. CONTRACT-P5C takes the amendments ratified at gt's landing
and at the regression triage: per-level extent is retired at the sites rather than
guarded on the accessor, the strict CI lane is two-sided (unit green gate plus
expected-red scenario lane with the marker asserted), the drain points are two classes
(the EGL RPC returns beside EmitAndWait), and oversized writebacks are client-sliced at a
quarter of the event ring.
2026-09-17 13:15:57 -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 11ac3de6f9 [Docs] (Disaggregated): plan P5c - audit the inproc split's remaining direct cross-role memory access (59 sites at a79a0af6) and schedule its zeroing before P6 as texture staged shadow, SEG_EVENT producers, handle-keyed resolution, control records, residual-value records and role guards 2026-09-17 00:51:40 -04:00
swung0x48 a79a0af69d [Docs] (Disaggregated): consolidate the five documents at the P5b close - drop superseded narrative, the -O0 device tables and process history, renumber MEASUREMENTS by phase, correct the catalogue and emit-table counts to the head, and record the Redmi pin profile 2026-09-16 23:08:39 -04:00
swung0x48 ea34bccb63 [Docs] (Disaggregated): close out P5b - record the completed host gate and merged census at 348d22a4, the review addendum's pinned results, and the Redmi exit at 82683d4a (correctness 8/8, first barrier-tax measurement, iris-bsl fixture-limit supplement); next is P6 spawn transport 2026-09-16 22:24:56 -04:00
swung0x48 c77831e0fa [Docs] (Disaggregated): rewrite the staged-progress log as a concise current-state document and link it from the roadmap's status line 2026-09-16 20:45:35 -04:00
swung0x48 ef35ea0ce5 [Docs] (Disaggregated): move the integrator's running progress log into the tree as CURRENT_STAGED_PROGRESS.md 2026-09-16 20:43:56 -04:00
swung0x48 696acce5d7 [Docs] (Disaggregated): record the P5b inproc verb migration - the class-C census, the five package families and what each removed, and the first Minecraft traces to render on the apply thread 2026-09-16 20:24:08 -04:00
swung0x48 cc0d56e464 [Docs] (Disaggregated): record P5 final gate stop and scoped control evidence 2026-09-16 13:39:46 -04:00
swung0x48 a48bc46ec1 [Docs] (Disaggregated): document the landed P5 inproc milestone 2026-09-16 10:32:58 -04:00
swung0x48 c3e736a343 [Docs] (Disaggregated): SEG_REPLY is 16 MiB in eight 2 MiB slots (ID-47) - the segment table still said 8 MiB with 4 KiB slots 2026-09-16 07:14:26 -04:00
swung0x48 3089ce8c1a [Merge] (MGPipe, P5): integrate package b1 2026-09-11 15:57:13 -04:00
swung0x48 d9ade1e7cd [Feat, Docs] (PipeStats, MEASUREMENTS): wire persistent-map-push to the bytes the client ships, rewrite the inventory line that called it unwired, and correct the persistent-map census from 20 to 21 2026-09-11 14:31:46 -04:00
swung0x48 97df377381 [Docs] (Disaggregated): record the field-ownership generator and correct the two stale 61-field lines - the generated assertion has said 63 since P1 2026-09-11 14:12:32 -04:00
swung0x48 0648b0d979 [Docs] (Disaggregated): record P4a as landed - the fourteen family calls and six re-keyed kinds, the seven contract corrections and the defect each one closed, the three-arm A/B on a pinned Adreno 830 with active cooling, the upload shape that did not move, and the seam taxonomy the next brief has to carry 2026-09-11 11:37:08 -04:00
swung0x48 37da3c3a07 [Docs] (Disaggregated): record the P3a landing - the five-part gate on the finished tree, the three seam defects the real-path round found, the Track H census, the two-device three-arm A/B on Release APKs (pull / P2-only 0x7f / P3a) with the P2 -O0 erratum, DriverBench T1/T2 against the 0x7f arm, the exit-order UAF closure, and the rulings (ID-13/15/17) 2026-09-08 10:23:59 -04:00
swung0x48 c036900d72 [Docs] (Disaggregated): add the Oppo Mali half of the P2 paired A/B - 16 rows per device, Espryt +8-18% and Magma +10-11% per-thread CPU over the pull baseline, plus the harness single-sample pidof kill recorded as a dev-side follow-up 2026-09-08 02:20:24 -04:00
swung0x48 44c2b5cf3a [Docs] (Disaggregated): record the P2 landing - the five-part gate results, the two-device paired A/B protocol with all 16 Xiaomi rows, DriverBench T1/T2 with the CSO control, the push-side counters, and the 2026-09-08 rule that performance is recorded against the pull baseline rather than gated 2026-09-08 01:40:51 -04:00
swung0x48 2d690754dd [Tooling] (DeviceBench): verify the two campaign devices' pin profiles and add a pin helper that works on them
- bench.sh's pin_freqs writes /proc/ppm and /proc/gpufreq, which exist on neither 35d0befa
  (SM8750) nor 3B159D009VZ00000 (MT6993 dropped both for /proc/gpufreqv2); the guard the
  PROFILE_VERIFIED key exists for was about to be defeated on the device its own comment
  guessed was safe
- pin_device.sh pins big/little/GPU through the nodes each device actually has (Xiaomi:
  policy6 1958400 / policy0 1555200 / kgsl pwrlevel 0; Oppo: policy4 2000000 + policy7
  2000000 / policy0 1600000 / gpufreqv2 fix_target_opp_index 0), checks only against its own
  pins because ColorOS moves stock maxima by itself, and refuses to call a zero-key read a verdict
- both profiles are PROFILE_VERIFIED=1 on 30 s pinned windows with zero drift; the evidence and
  the two things not verified (Oppo GPU held at DVFS-request level only, no full bench window)
  are in docs/Disaggregated/devices/pin-verification-2026-09-07.md
2026-09-07 23:43:11 -04:00
swung0x48 e7a6a72f6a [Docs] (Disaggregated): record the P1 landing and what its verify lane found
- README status, the ROADMAP P1 row with the measured site and accessor counts, and the
  ARCHITECTURE correction from 293 to the 277 arrow sites the tree actually has
- MEASUREMENTS gains the P1 scale table, the two classes of finding the verify lane
  produced (nine missing fill rows, three fields a backend moves inside its own verb) with
  the push-on-mutation decision and its three hooks, and the acceptance numbers
2026-09-06 06:17:12 -04:00
swung0x48 5635e33ffe [Docs] (Disaggregated): record the P0.5 landing
- README status, the ROADMAP P0.5 row (measured outcome, the 8-includer correction, the
  DynamicBackendParameters exception) and the ARCHITECTURE note on which header gate A asserts
2026-09-05 23:22:15 -04:00
swung0x48 6e0e3df372 [Docs] (Disaggregated): point the history note at commit hashes only
- the retired drafts stay in git history; the README no longer names or characterises them
2026-09-05 21:58:28 -04:00
swung0x48 bee22f9d26 [Docs] (Disaggregated): separate the dirty-surface totals from the immediate-publish subset in MEASUREMENTS
- the sentence read as if 836 of the 92 immediate calls were RecordError; 836 is RecordError's share of all 926 calls, and most of the 92 immediate ones are RecordError
2026-09-05 21:57:11 -04:00
swung0x48 8952b14024 [Docs] (Disaggregated): rewrite the MGPipe plan into a design and architecture set - README, ARCHITECTURE, ROADMAP, MEASUREMENTS - and retire PLAN.md and REVIEW.md to git history
- README.md: what MGPipe is, the one-paragraph architecture, the P0 status line, the file and code map, and the commit range where the design competition and the three adversarial review rounds live
- ARCHITECTURE.md: the design as decided, one reason per decision - handles and generations, the 71-call catalogue by class with flags and cap bits, record and payload conventions, the tracker, texture subdata and dirty ownership, shader state and the P0.5 header extraction, the reverse channel, the backend strangler, the server side and the index host mirror, the transport as landed in MG_Remote, the persistent-map tiers as measured, roundtrips, present and threads, process and platform delivery, build shapes and purity gates, the five-part verification gate, and the knob tables marked landed versus planned
- ROADMAP.md: P0..P13 as one table of what lands, the gate and the dependency, the two tracks and milestones, the day-43 GO/NO-GO checklist with both exits, the re-baseline checkpoints, and the questions still open after P0
- MEASUREMENTS.md: spike A on both devices, the spike B tier matrix, the four-trace boundary-counter baselines on both backends, the desktop and corpus facts, and the harness traps with the exact commands
- every file:line kept is verified at 458ccde1 and the citation lint is clean; everything else cites a symbol plus a file
- dropped on purpose: the v1/v2 revision archaeology, rejected alternatives, per-subsystem day estimates, the Feat/CS-Delta-IPC reuse audit and the reviewer back-and-forth
2026-09-05 21:56:31 -04:00
swung0x48 87ee17c68c [Docs] (Disaggregated): fold the P0 measurements and corrections into the plan
- GL_COMPUTE_WORK_GROUP_SIZE is answered by MG_Impl from ProgramObject::GetComputeLocalSize, not by a backend; only the compute limits are caps, and the two dead table entries (GetInteger64i_v, GetProgramiv) were retired in P0
- the glRenderbufferStorage OOM-probe idiom appears in 0 of 41 fixtures, so kNeedsAck is carried by glBufferStorage only
- FramebufferSrgb/DepthClamp: six readers of a constant false and zero readers respectively, no fixture enables either; recorded as a decision to take before the render-state chunk table freezes
- the call catalogue is 68 unique records (screen 10, ctx-query 6, CSO 13, kCtxState 17, kCtxObject 9, kCtxVerb 13); PipeCalls.def is the single source of truth and the wire opcode is a line's position
- measured layouts (MGPDrawInfo head 56 B, RenderStateParameters 1168 B, ResidualValueBlock 1248 B, MGPipeContext 464 B ...), the 926/73 MG_Impl mutator surface, the first per-draw accessor numbers on lavapipe (Espryt 20.65, Magma 15.54), the EndTransformFeedback null-as-capability trap, and the host-side spike results
2026-09-05 20:29:30 -04:00
swung0x48 8349babe90 [Docs] (Disaggregated): consolidate into a single MGPipe plan and drop the replica plan
- docs/Disaggregated/PLAN.md is now the one plan: the MGPipe design with the transport, control-plane, present, threading, EGL/process, monolith/build chapters inlined as real chapters (7-13) instead of references, sections renumbered 0-17 + appendices, every internal citation updated
- the replica-GLContext plan and its review record are removed at the user's request; REVIEW.md is the MGPipe design-competition and adversarial-review record only, with the comparison verdicts dropped and the remaining finding text reworded to the new section numbers
- day-43 GO/NO-GO now names its two outcomes (continue / shrink to headless tooling or re-evaluate) without any rollback path
2026-09-05 14:06:24 -04:00
swung0x48 1794ac94b1 [Docs] (Disaggregated): land plan B - MGPipe, a gallium-style explicit frontend/backend interface with a backend-owned state machine (client-allocated {slot,gen} handles, CSOs keyed on the pipeline subset with dynamic state pushed separately, set_* catalogue derived from the twins the two backends already keep, per-verb validate with aggregate generations, reverse channel as ten named callbacks plus a pull terminator, strangler migration behind PipeInputs with per-verb poison and a field-wise verify harness, three purity gates replacing byte identity), the item-by-item comparison against the replica plan A (memory, copies, drift surface, monolith benefit vs 4x effort and 7x later first frame) with a day-43 GO/NO-GO hedge, and the round-2 design-competition and adversarial-review record; mark plan A as superseded except for its inherited transport sections 2026-09-05 13:05:43 -04:00
swung0x48 8b31de2f8d [Docs] (Disaggregated): land the two-process split plan - server runs the unchanged backends against a replica GLContext driven by mutator replay, the client is the sole originator of every implicit-publish semantic (persistent-map push, MarkGpuWritten, texture dirty clear, XFB accounting, generated-mip allocation), SPSC shm ring with FlatBuffers structs on the hot path and tables on the control socket, two-way doorbells, present credit 1, spawn-only shipping build with an inproc CI variant, and a P0-P9 schedule gated on the existing unit/integration/retrace/CTS suites; plus the design-competition and adversarial-review record 2026-09-05 09:21:58 -04:00
swung0x48 77bd03d962 [Chore]: remove unnecessary doc 2026-07-30 21:56:17 -04:00
swung0x48 1b0be9a997 [Docs] (android-plugin): specify POST format capability tables 2026-07-15 22:36:56 -04:00