Merge branch 'codex/p5f-close' of /mnt/c/Users/geekerwan/AndroidStudioProjects/FoldCraftLauncher/.git/modules/MobileGL into codex/p5f-final

This commit is contained in:
2026-09-20 01:35:35 -04:00
17 changed files with 729 additions and 176 deletions
+2 -2
View File
@@ -346,7 +346,7 @@ make-current and teardown do to it — the column `ARCHITECTURE.md` does not hav
| the ten `MG_Impl/Pipe` `*Instance()` singletons | `fable-seam-audit.md:120-135` | client | **Client-exclusive.** One correction carried forward: the texture **drain list `m_drain` is process-wide**, not per-context as D-D4 claims; the audit already booked "one drain per client context" as a P5 item. | `FreshlyPrimed` (`PipeFill.cpp:2414-2440`) resets them on make-current; leak at exit (ID-8). |
| `ScopedDefaultUnpackState::s_synced` + **six** value shadows | `Managers.cpp:5490-5496` | backend | **Server-exclusive — the sixth global the four→two census missed.** Latent rather than live in P5 only because the client role never touches GL on the reduced path. (`Managers.cpp:5491-5496` is six `GLint`s, not five: `s_skipImages` at `:5496` is the one usually dropped.) | **Never reset on context death** — `OnBackendContextDestroyed` resets the rings and the binding caches and not this. Benign while a lost context returns the driver to GL defaults; not benign the day a server re-attaches to a context something else moved. Register it now. |
| `pActiveBackendObject` | `GlobalObjects.cpp:23` | `MG_Backend::Init()` | **Client installs `BackendObject_Remote`; the server's `BackendObject_DirectGLES` is held privately by `ServerLoop`.** No thread-keyed shim, and therefore `MOBILEGL_BUILD_DISAGGREGATED_INPROC` needs none — but the cost is **seven** backend-internal reads across **six** functions, not the one the scout reported: `BackendObject_DirectGLES.cpp:815`, `:819` (`ClampSamplesToBackendSupport`) and `Utils.cpp:74`, `:82`, `:126`, `:220`, `:260`. All seven are format-capability lookups, so "pass the format cache down" still works. **`DirectGLES.cpp:12446` is NOT `ClampSamplesToBackendSupport`** — it is `Present()`'s fence poll, and `DirectGLES.cpp` contains no `pActiveBackendObject` reference at all. | `GetFormatCapabilities()` is **non-virtual** (`BackendObject.h:594`), so the remote object must **fill** `m_formatCapabilities` rather than override the accessor. Teardown: `pActiveBackendObject.reset()` (`MobileGL/Init.cpp:68`) runs `~BackendObject_DirectGLES` → `DestroyEGLContext()`, so under split it must be a **blocking** request onto the apply thread. |
| `gBackendFunctionsTable` | `GlobalObjects.cpp:24`, assigned `Init.cpp:44` | `MG_Backend::Init()` | **Client = the emit table (R-4); the server holds its real table directly and never goes through this global.** | cleared at `MobileGL/Init.cpp:91`. |
| `gBackendFunctionsTable` | `GlobalObjects.cpp:24`, assigned `MG_Backend/Init.cpp:63` | `MG_Backend::Init()` | **Client = the emit table (R-4); the server holds its real table directly and never goes through this global.** | cleared at `MobileGL/Init.cpp:91`. |
**Teardown order**, `ARCHITECTURE.md:537` plus the sentence it omits:
@@ -521,7 +521,7 @@ every lane: `AdvertisedLimitsScenario.ComputeWorkGroupLimitsAreTheCapsBlocksAnsw
`glGetIntegeri_v` give one number.
This settles the census's sharpest finding: `GetIntegeri_v` is reached by the **first
`glCompileShader` of every context** (`CompileEnv.cpp:134-138` ← `Core.cpp:39`), not by any verb,
`glCompileShader` of every context** (`CompileEnv.cpp:134-138` ← `MG_State/GLState/Core.cpp:39`), not by any verb,
so an all-`Fatal` table would abort every scenario before it drew anything — and an emitter for
it would be a round trip for six constants the snapshot already carries.
+60 -22
View File
@@ -1,6 +1,6 @@
# 当前阶段进度
分支 `feat/disaggregated`;代码头 `25fba0d5`(2026-09-18,P5e wave 3:strict 硬绿 + run-ahead 武装;P5d 收官头 `1f8de61b`,P5c 收官头 `b88e8487`)。本文随每次落地更新。ID-1..75 的逐条裁定长文在 git 历史(`ef35ea0c` 之前版本的本文件)。
**P5f 已收官(2026-09-20)**。最终行为验收头:WSL `cfca93c7885fd8db1e881f91189ba59090ae9c52`,Windows `c42577a4` 等价;本次整合来自 `codex/p5f-close`,主分支合入记录见 [`notes/p5f/close-report.md`](notes/p5f/close-report.md)。P6 的 P5f 前提已解除,a6 / c6 / spawn 尚未实施。以下 §2 为当前验收;其后的 P5c/P5d/P5e 数字与性能章节保留为历史,不替代当前结果。
## 1. 阶段状态
@@ -12,10 +12,50 @@
| **P5c** `inproc` 共享内存读点归零 | **已收官(2026-09-17)** | `11ac3de6..b88e8487` + triage 修复;契约 `MobileGL/MG_Remote/CONTRACT-P5C.md`;审计 `~/w7/notes/p5c/p5c-audit-v1.md` |
| **P5d** `inproc` 性能专项 | **已收官(2026-09-18,三轮)** | `cb06538c`、`56a77348`、`1f8de61b`;报告 [`P5D-INPROC-PERFORMANCE.md`](P5D-INPROC-PERFORMANCE.md);`MEASUREMENTS.md` §9 |
| **P5e** 退役 Espryt draw path 的 lockstep | **已收官(2026-09-19)**,附一条具名未决(E1 对照,ID-122) | 契约 `MobileGL/MG_Remote/CONTRACT-P5E.md`;计划 `~/w7/notes/p5e/BRIEF-P5E.md`、裁定 `~/w7/notes/p5e/INTEGRATOR-DECISIONS-P5E.md`(**ID-80..136**);**十二个包已全部落地合并**(§2.7),`kMGPipeP5eRunAheadReady` 与 `kMGPipeP5eClientWaitRuleLanded` 均已翻。strict 车道硬绿 179/179、`integration-gpu` 1357/1357、三个构建 flavour 全绿;设备上 VD32 已与 monolith 齐平。报告 [`P5E-RUNAHEAD.md`](P5E-RUNAHEAD.md),未完成项见 §5 |
| **P5f** 一切状态上 wire | **计划已起草(2026-09-19)**,未开工 | 计划 [`P5F-WIRE-COMPLETENESS.md`](P5F-WIRE-COMPLETENESS.md)。插在 P6 之前:跨角色的直接共享尚未归零(`BARRIER_PULLED` 21 行 / 15 字段,其中八个 Magma 未动;EGL 控制面仍走函数指针邮箱;per-context 语义的进程级静态量) |
| **P6** spawn transport | **阻塞于 P5f**;计划与契约草稿已起草 | 计划 [`P6-SPAWN-PLAN.md`](P6-SPAWN-PLAN.md)(a6 只读审计 → c6 契约 → so / sm / cp / st / t6 并行);契约草稿 [`P6-CONTRACT-DRAFT.md`](P6-CONTRACT-DRAFT.md)。传输原语(`SocketDoorbell`、SCM_RIGHTS fd 传递、`ShmSegment::Adopt`、`SurfaceOp` schema)**已在树上且有测试**;缺的是进程、控制面,以及 P5e 留下的“不等待的客户端 + 会死的服务端” |
| **P5f** 一切状态上 wire | **已收官(2026-09-20)** | f0 / f1 / fc / fe / fm / fs / fr / fv 及分类收口均已完成;零 BARRIER_PULLED、两份 marker 空表、逐帧 rsp=0。主机全门、Claude 异族终审两项修复及 red-once、Redmi 六 clean-boot 臂通过。见 [`close-report`](notes/p5f/close-report.md)、[`close-review`](notes/p5f/close-review.md)、[`device-report`](notes/p5f/device-report.md) |
| **P6** spawn transport | **前提已解除,尚未实施** | 计划 [`P6-SPAWN-PLAN.md`](P6-SPAWN-PLAN.md)、草稿 [`P6-CONTRACT-DRAFT.md`](P6-CONTRACT-DRAFT.md);下一步 a6 核验进程/链接边界,再 c6 和 spawn 包。传输原语与 P5f 值控制帧、静态世代/角色隔离已在树上;待做的是进程装配、socket 传输、握手/EOF/device-lost 等,不再重做已落地的控制帧与静态量 |
## 2. P5f 最终验收
| 门 | 总条目 | PASS | skip | failed / 结论 |
|---|---:|---:|---:|---|
| unit | 2310 | 2300 | 10 | 0 |
| integration-gpu | 1377 | 1118 | 259 | 0;既有功能/驱动/专属车道 skip 不计 PASS |
| ordinary / strict integration-split(各自) | 180 | 176 | 4 | 0;strict 三类 marker 均为零 |
| 双块 split + magma | 212 | 206 | 6 | 0;发现集合与 JUnit 完整核对,skip 名称和原因精确匹配 |
| integration-p5f-rsp | 2 | 2 | 0 | GLES、Magma 各一条真实执行,每帧 rsp=0 |
| Redmi 六个 clean-boot 臂 | 66 | 60 | 6 | 0;六个不同 boot-id,36 个统计窗口 rsp=0 |
字段表为 **41 RECORD_SUPPLIED / 6 APPLIER_DERIVED / 0 BARRIER_PULLED / 16 FATAL**。
`strict-expected-markers.txt` 与 `dualblock-expected-fatals.txt` 均为空集合,两侧棘轮仍有效;
空结果、漏跑、重复/notrun/disabled 或额外 skip 不得判绿。双块精确保留以下六个 skip:
- `DirectGLES.Split.TriangleScenario.TheServerStampedAVerbBoundaryOnThisDrawingFrame`
- `DirectGLES.Split.SmallRing.TriangleScenario.TheServerStampedAVerbBoundaryOnThisDrawingFrame`
- `DirectGLES.Split.PersistentCoherentMapScenario.TheMapLandsInTheArmItsLaneDeclares`
- `DirectGLES.Split.SmallRing.PersistentCoherentMapScenario.TheMapLandsInTheArmItsLaneDeclares`
- `DirectVulkan.Split.Fm.ClipDistanceScenario.ADisabledClipDistanceRemovesNothing`
- `DirectVulkan.Split.Fm.ClipDistanceScenario.TheEnablesAreIndependentPerDistance`
前四项是 strict-arming / counting 专属车道的 sibling;后两项是已知 Magma clip-distance
逐项开关限制,原因同样参与校验。独立 RSP 门不允许任何 skip。
pull / push 实际构建及生效宏通过;**G1** `.text` **10806051 → 10806051**、defined symbols
**27815 → 27815**、**0 added / removed / resized / renamed**;**G2** 两者各 **3016** 个测试名,
集合相同;**G14** f1 **3646 → 3744**,没有删除。生成器/闭包门与逐包 red-once 均已执行。
Claude 异模型族终审的 P1(结果集可伪绿)与 P2(callback owner 错投)均修复并实际红转绿,
见 [`close-review.md`](notes/p5f/close-review.md)。
设备门使用最终库在指定 Redmi `2f7cbe2e` 上重跑 GLES/Magma 的 monolith、role0、role1
六臂;仅为本阶段可执行子集的正确性与 rsp 验证,性能只记录,不代替 P5e 的 MC/FPS 实测。
原始身份、skip 原因与运行边界见 [`device-report.md`](notes/p5f/device-report.md)。
Magma 仍不发布 `kCapRunAheadApply`,已由同一双块/strict 判据证明可达子集;P7 应用 buffer /
native-format、P8 client arrays、P12 真窗口到达等具名边界继续保留。
## 2.1 历史实测:P5c / P5d 收官头
以下表格是当时的验收记录;包括当时未做的设备项与非零 rsp,不表示 P5f 当前状态。
## 2. 当前头实测
| 门 | 结果 |
|---|---|
@@ -70,7 +110,7 @@
两臂截图为同一视角同一世界,画面正确。monolith 这一次未被 120 Hz vsync 封顶(与 P5d 的 205.8 那次同类),故**不与 inproc 直接比大小**——本轮问的是"改完还能不能正常跑",不是配对性能。inproc 的 136-140 与 ID-107 记的 140.0 / 144.9 同档,说明 fix1 触到的那行(臂选择本身,两臂都读)没有拖慢 split 臂。库版本以符号探针确认(`texture-handle-arm` 等四个字符串在 APK 的 `lib/arm64-v8a/libMobileGL.so` 内),不看游戏内的 `GIT@` 戳记——增量构建下它是旧的。
## 2.6 P5e wave 3:strict 硬绿、run-ahead 武装(头 `25fba0d5`)
## 2.6 历史:P5e wave 3,strict 硬绿、run-ahead 武装(头 `25fba0d5`)
四个包:**pa**(program 家族,逐 draw 的那次拉取)、**mv**(multi-draw 的 VAO 读点 + 五个档位的门禁条目)、
**gl**(门禁机制本身 + 两处潜伏崩溃)、**ra2**(翻开开关后暴露的竞态)。裁定 ID-111..136。
@@ -160,7 +200,7 @@ flaky 是竞态**。根因(ra2 实测,推翻了我 ID-132 的机制猜测)
**尚未回答的**:VD12 下面板上限之上谁更快。本机定不住更高的频率,而未定频的一次高频窗口里 monolith p50 201 / run-ahead
p50 181(约 1.10 倍)——那一次不可配对,只能作为方向性提示。要回答它需要关掉 vsync 或换一台上限更高的设备。
## 2.7 P5e 落地内容
## 2.7 历史:P5e 落地内容
| 波 | 包 | 内容 | 效果 |
|---|---|---|---|
@@ -178,7 +218,7 @@ p50 181(约 1.10 倍)——那一次不可配对,只能作为方向性提
| 3 | gl | 生成式采纳谓词、strict 旋钮的第三态、车道两侧棘轮、`ResourceCopyRegion` 等待类、Magma 车道切分;以及两处潜伏崩溃(ID-111 的盖章、ID-112 的编译期绊线) | 车道成为可被脚本判定的硬绿 |
| 3 | ra2 | 翻开开关后暴露的竞态(守卫把"关于未来的断言"当豁免依据);`BoundDrawIndirectBufferId` 退役并撤回升级 (iii)(ID-136) | 翻开开关后 `isplit` 112→179 |
## 3. P5c 落地内容
## 3. 历史:P5c 落地内容
| 包 | 内容 | 效果 |
|---|---|---|
@@ -192,7 +232,7 @@ p50 181(约 1.10 倍)——那一次不可配对,只能作为方向性提
| gt | 纹理九表面 layer-1 守卫(挂 MipmapStorage 汇聚点);`InBarrierWait` 接线成 gPipeInputs 单写者规则的 client 半边;strict CI 车道(unit 绿门 + 场景预期红);rsp 按帧实测 | 每层守卫 red-once 按名验证 |
| triage 修复 | 默认 FBO 格式事件的第二类排空点(EGL RPC 返回);大 writeback 的客户端切片(环 1/4);XFB scatter 改读 server staged shadow | 普查三个真回归修复 |
## 4. P5b 落地内容
## 4. 历史:P5b 落地内容
| 包 | 迁移的槽 / 内容 | 效果 |
|---|---|---|
@@ -206,7 +246,7 @@ p50 181(约 1.10 倍)——那一次不可配对,只能作为方向性提
| r1 / r2 | P5 收官审查 13 项(coherent-map 服务器侧绕过、FBO 死亡在 client 线程、`PACK_SWAP_BYTES`、`RingOverrun` 等待、CI 对照九项) | — |
| 收官审查修复 | 索引 span 上界(`Count × IndexSize` 必须装进声明的 run)、fence wait 预算、`Fatal{ReplyStatusInvalid, "ReadPixels"}` | P5b 审查 0 blocker |
## 4.1 真实负载(inproc,独立 apply 线程)
## 4.1 历史:P5b 真实负载(inproc,独立 apply 线程)
- `DrawElements` 不再是阻塞:d1 普查时 77 个 Minecraft 后端用例中 28 个渲染通过(SSIM ≥ 0.99995)。
- blit + mip 之后:`improved-transparency-minecraft-26.3` DirectGLES SSIM 1.0 / DirectVulkan 0.999914;`minecraft-1.21.4-fabric-iris-bsl-in-world` DirectVulkan 0.997324、DirectGLES 0.997496;OpenRA 双后端 1.0。
@@ -218,35 +258,33 @@ p50 181(约 1.10 倍)——那一次不可配对,只能作为方向性提
| 项 | 证据 / 去向 |
|---|---|
| `SEG_STAGE` 默认 32 MiB 装不下目标负载的单次 128 MiB 上传;**决定 = 默认不改**,普查与 Redmi 显式 `MOBILEGL_IPC_STAGE_MB=256`;分块 / 专用 carrier 留 P8(`ROADMAP.md` 开放问题 11) | `p5b-results/blit-codex-v1.md`;`MEASUREMENTS.md` §7.2 |
| Magma(DirectVulkan)split compute/image 路径:89 个错答中 82 个 | `p5b-results/i1-v1.md` |
| Magma 应用 buffer、placeholder/native-format 等 P7 功能广度 | P5b 的“89 个错答中82个”是历史普查计数;P5f 已验证无应用 buffer 的 draw/compute、sampler/image record 子集,后续按新语料重新点名,不能继续把旧计数当当前失败数 |
| rd12 GLES `InitialBytesNotCarried/resource_respecify`、rd12 VK `BarrierTimeout/Present`、`iris-bsl-esc-menu-854` GLES、三条 `texture-remint-pull` 仿真槽、`create-indirect` VK 内存膨胀 | 79 trace 普查 `counts.json` / `trace-transitions.json` |
| RGB 三通道 CPU mip 回退仍是具名 Fatal | `p5b-results/mip-codex-v1.md` |
| ~~`inproc` 仍有 59 处不经 wire 的直接内存访问~~(2026-09-17 审计) | **P5c 已收官归零**:四族修复(tx/ev/hd/ct/rv/gt)+ 普查 triage 三真回归修复;剩余为具名债——两个豁免 scope(通告家族 P4b/P7、G6 registry 家族 P3b/P4b)内的只读探测与对象类 15 行 BARRIER-PULLED,全部可 grep、有退役阶段 | `MobileGL/MG_Remote/CONTRACT-P5C.md`;`MEASUREMENTS.md` §8 |
| ~~P5c 历史跨角色清单与对象类残余~~ | **P5f 已全部收口**:双块空棘轮、零 BARRIER_PULLED、两后端逐帧 rsp=0;旧指针 accessor 以 FATAL 保持边界,未伪标为 record-supplied。见 [`close-report`](notes/p5f/close-report.md) |
| 27 个 P5 inproc 错答:22 纹理读回走 client-shadow 回退、3 query、1 inspection、1 FBO/RBO 删除后生命期 | P4b / P7 / P6 债 |
| `rsp` 残余输入;`SEG_REPLY` 2 MiB 单槽上限;GetCaps 两个 blobref 的载体;PACK-PBO 读回真实形式 | P3b/P4b、P6+ |
| `SEG_REPLY` 2 MiB 单槽上限;GetCaps 两个 blobref 的载体;PACK-PBO 读回真实形式 | P6+ / P9 的协议广度;`rsp` 残余读取已由 P5f 关闭,不再与这些功能债并列 |
| 15 个 class-C 槽(query / sync 尾 / `GetTexImage` / `SetSwapInterval` 等)无负载命中,仍具名拒绝 | P9 / P10 |
| Redmi 定频行只在树外 `~/w7/notes/p2/devices/pin_device.sh`;钉频口径 2026-09-16 起 1100 MHz(原 1050) | `devices/pin-verification-2026-09-07.md` |
| `test.yml` / `apk.yml` 的 `feat/disaggregated` 触发器是临时的,合入 dev 前必须移除 | — |
| **P5e:BRIEF §3 的三条阴性对照与逐包 red-once 重跑未执行**(ID-121 已把后者重排到车道变绿之后,现在可跑) | `~/w7/notes/p5e/FLIP-CHECKLIST.md` phase C |
| **P5e:`split_negative_controls.sh` 的 E1 对照自检失败**,且索要的 `Fatal{BarrierViolation}` 在 `BATCH_WAITS=1` 下不可能触发——一个永远打不响的对照比没有对照更坏 | ID-122 |
| ~~P5e:契约 §3.2 的 per-role stamp 存储未落地~~ **P5f f1 已落地**(双块臂:server 块即 applier 私有存储,client 的 clear 重指到自己块,SetIdentity 由 `MGPipeServerBlockNoteIdentity` 落 server 侧);§8 修正 8 仍 UNLANDED | ID-135 已由 f1 关闭 / ID-120 仍开着;`CONTRACT-P5E.md` |
| ~~P5e:BRIEF §3 的三条阴性对照与逐包 red-once 尚未重跑~~ | 当期后续已执行,结果保留在历史 §2.6 与 P5e 报告;E1 自检债单列保留,不与执行完成混同 |
| **P5e 历史债:`split_negative_controls.sh` 的 E1 对照定义/自检**,原 `BATCH_WAITS=1` 组合下索要的 `Fatal{BarrierViolation}` 无法触发 | ID-122;仍需重新定义其证伪对象。P5f 的双块开绿/关红、RSP 硬门与逐包 red-once 不代替修复这条旧脚本 |
| ~~P5e:per-role stamp 存储未落地~~ | **P5f f1 / fs 已完成**:server 私有 stamp/identity/liveness、client 独立块与角色本地诊断。旧契约的历史 UNLANDED 注记不再作为当前施工状态 |
| **P5e:VD12 面板上限之上谁更快未答**(本机定不住更高频);VD32 那一轮回答了一般性问题 | `MEASUREMENTS.md` §11 / §11.1 |
| **新机会(非缺陷)**:VD32 下 apply 11-12 ms 对 client 15.7 ms,两侧不平衡;把工作从 client 挪到 apply 会直接降瓶颈——lockstep 下无意义,run-ahead 才解锁 | `P5E-RUNAHEAD.md` 末节 |
## 6. 下一步
0. P5d 的遗留(`P5D-INPROC-PERFORMANCE.md` "什么没完成"):R-1 序列化留给 P3b/P4b → P11(`gPipeInputs` 版本化已写进 P11 行);线程放置记录;小项随 P3b/P4b 顺手。
1. **P5e 已收官**(2026-09-19,报告 [`P5E-RUNAHEAD.md`](P5E-RUNAHEAD.md)):出口门已逐条跑过(逐项结果记在 `ROADMAP.md` 的 P5e 出口门格):unit 两臂 2256/2256、`integration-split` 179/179 零 `Fatal{`、三条阴性对照按预期、逐包 red-once 各得恰好一个具名对。**剩下的只有 E1 对照**(ID-122):修掉它两个遮蔽性缺陷后仍红,而它索要的 `Fatal{BarrierViolation}` 在整次运行里出现 0 次,需要重新定义它证伪什么而不是调阈值。契约 §3.2(per-role stamp 存储)与 §8 修正 8 仍标为 UNLANDED,随后续阶段;G1 仍由 CI 断言(ID-123)。
2. **P5f 一切状态上 wire**([`P5F-WIRE-COMPLETENESS.md`](P5F-WIRE-COMPLETENESS.md)):插在 P6 之前。`f0` 普查已落(`notes/p5f/` 八篇),`f1` 双块机制已落(报告 [`notes/p5f/f1-report.md`](notes/p5f/f1-report.md)):`MOBILEGL_IPC_ROLE_SPLIT_STATE=1` 给两个角色各一份 PipeInputs,`integration-dualblock-split` 车道与 `dualblock-expected-fatals.txt` 棘轮已立,红清单即 fm/fs/fr/fv 的工作量。下一步是 `fm`(Magma 的 9 个字段)等逐包消红。
3. **P6 spawn transport**(阻塞于 P5f):计划与契约草稿已起草([`P6-SPAWN-PLAN.md`](P6-SPAWN-PLAN.md)、[`P6-CONTRACT-DRAFT.md`](P6-CONTRACT-DRAFT.md)),**下一步是跑 `a6` 那次只读审计,不写代码**:“P6 只是传输替换”这句话的证据是 P5c 时代的,P5e 之后已经过期。审计要点名去查:进程级静态里语义属于 context 的那一类(`s_synced` / `g_syncedRenderStateParameters` 是已知的两个,问题是还有几个——这类缺陷`inproc` 永远看不见);十二个 EGL forwarder 对 `SurfaceOpKind` 缺几个枚举;server 是否真能不链 `MG_Impl`。
3. 剩余首阻塞一轮(Magma compute/image、rd12、RGB mip、`texture-remint-pull` 仿真槽)。
4. P5e 出口门(`~/w7/notes/p5e/BRIEF-P5E.md` §3 / §4):`integration-split-strict` 转硬绿车道、三条阴性对照、Redmi 四臂(monolith / lockstep / credit 1 / credit 2)。P6 出口门:P5b 的完整渲染路径在 `spawn` 下绿;OpenRA 在 Adreno 830 上 split SSIM ≥ 0.99。
5. Redmi 四臂复测(P5c 的记录项,需设备窗口);79 trace 普查重跑(需全集语料)。
1. **P6 a6 尚未执行**:按 [`P6-SPAWN-PLAN.md`](P6-SPAWN-PLAN.md) 核验 P5f 的 wire-only 结论在独立进程装配中成立,重点是角色链接闭包、段映射/句柄传递与生命周期边界;控制帧、静态世代与对象字段不重新施工。
2. a6 后推进 **c6 契约与 spawn 实现**:SocketTransport、ServerMain、握手、EOF / device-lost 及子进程身份门。`integration-spawn` 应与现有 split 同名,且日志证明真正在子进程执行;这些代码和验收尚未实施。
3. P7/P8/P9 的 buffer、格式/placeholder、client arrays、大 blob、异步回读等功能债继续按阶段推进;79 trace 全集重新普查后再引用首阻塞,P5b 历史清单不当作当前结果。
4. **保留 P5e E1 历史债(ID-122)**与 VD12 面板上限、线程放置/负载平衡等测量问题。P5f 设备正确性通过不改写 P5e 的性能结论,也不声称解决上述性能问题。
## 7. 记录位置
| 内容 | 位置 |
|---|---|
| P5f 收官、异模型族终审、最终设备门 | [`close-report`](notes/p5f/close-report.md)、[`close-review`](notes/p5f/close-review.md)、[`device-report`](notes/p5f/device-report.md);分包报告位于 `notes/p5f/` |
| P5 brief / 契约 / 前言 | `~/w7/notes/p5/BRIEF-P5.md`、`MobileGL/MG_Remote/CONTRACT-P5.md`、`~/w7/notes/p5/PACKAGE-PREAMBLE.md` |
| P5 包报告与审查 | `~/w7/notes/p5/p5-results/`(`joint-v1.md` 全门记录、`ab-v1.md` 设备 A/B、`p5-close-codex-review.md`) |
| P5b brief / 契约 / 报告 | `~/w7/notes/p5b/BRIEF-P5B.md`、`MobileGL/MG_Remote/CONTRACT-P5B.md`、`~/w7/notes/p5b/p5b-results/` |
+24 -19
View File
@@ -1,15 +1,15 @@
# P5f — 一切状态上 wire:跨进程前的最后一次归零
> 基线 `feat/disaggregated @ 7f1d2134`。路径在 `MobileGL/` 下。
> **进度**:`f0` 普查已落(`notes/p5f/` 八篇);`f1` 双块机制已落(报告
> [`notes/p5f/f1-report.md`](notes/p5f/f1-report.md):旋钮 `MOBILEGL_IPC_ROLE_SPLIT_STATE`、
> 车道标签 `integration-dualblock-split`、棘轮 `Harness/dualblock-expected-fatals.txt`);
> `fc` 控制面帧已落(报告 [`notes/p5f/fc-report.md`](notes/p5f/fc-report.md):§2.3 的函数指针邮箱
> 退役为 `SurfaceControlFrame` 值帧,schema 缺口补齐,wire 入口具名拒绝就位)。
> **波次 2 已集成**:fc / fe / fm 完成,双块 210 条零失败、两份 marker 棘轮为空;
> 仍有 fs / fr / fv、13 个 BARRIER_PULLED 字段的分类收口与设备门。见
> [`notes/p5f/wave2-report.md`](notes/p5f/wave2-report.md) 与最新 HANDOFF-P5F。
> **P6 在 P5f 之前不开工**:P6 的前提"只是传输替换"今天不成立,§2 是不成立的清单。
> **已收官(2026-09-20)**:f0 / f1 / fc / fe / fm / fs / fr / fv、字段归属收口、
> 主机出口门、Redmi 双后端六个 clean-boot 臂与跨模型族终审均完成。
> 最终行为验收头 `cfca93c7`;[`收口报告`](notes/p5f/close-report.md) 为当前结论,
> [`交接`](notes/p5f/HANDOFF-P5F.md) 为下一阶段入口。P6 的 a6 / c6 / spawn 尚未实施。
> 当前字段:41 RECORD_SUPPLIED / 6 APPLIER_DERIVED / **0 BARRIER_PULLED** / 16 FATAL;
> 两份 marker 棘轮为空,双后端逐帧 `rsp=0`。旧指针 getter 保持 FATAL,不以改名消债。
>
> 以下 §0–4 保留立项背景与设计,§1–2 的读点、行号及 15 字段数字均是
> **历史基线 `feat/disaggregated @ 7f1d2134`**,其中“今天”“尚未”等不代表当前状态。
> 路径在 `MobileGL/` 下;各包报告保留其提交时快照,后续闭环见收口报告。
---
@@ -253,18 +253,18 @@ P5f 的每一条都靠同一个机制证伪,而不是靠审计:
---
## 5 包(波次 2 已完成;ID-137 分工)
## 5 包(全部完成;ID-137 分工)
```
f0 普查(只读):§2.4 的完整静态清单 + §2.6 的逐站点清单 + 每个 BARRIER_PULLED 字段的载体判定
└─ f1 双块机制 + 旋钮 + 车道(§4),此时预期大面积红,红就是清单
f0 普查(已集成):§2.4 的完整静态清单 + §2.6 的逐站点清单 + 字段载体判定
└─ f1 双块机制 + 旋钮 + 车道(已集成;初始红清单已全部退役)
├─ fe Espryt 字段读者 + XFB 快照 + 共用记录接线(已集成)
├─ fm Magma 的 9 个字段 + T5 + Magma 侧跨角色读写(已集成)
├─ fc 控制面帧(§2.3,已集成)
├─ fs 静态量分区(§2.4)
├─ fr registry 按句柄重键(§2.5)
└─ fv 反向通道触碰 client 内存的部分(§2.6)
└─ 收口:strict 允许表清空,双块车道转硬绿
├─ fs 静态量按角色/世代分区、XFB lifetime、server liveness(已集成)
├─ fr frontend registry / allocator 无 apply-side 豁免(已集成)
└─ fv 反向事件 callback 所有权与 frontend fallback 退役(已集成)
└─ 收口(完成):字段归属零残余、两份空棘轮、逐帧 rsp 门、设备及异族审查
```
`f1` 先落是故意的:**让红先出现,再逐包消红**,而不是各包自称做完之后再找一个判据。
@@ -273,6 +273,10 @@ f0 普查(只读):§2.4 的完整静态清单 + §2.6 的逐站点清单
## 6 出口门
**七项均已完成**,数字与原始证据路径见 [close-report.md](notes/p5f/close-report.md)。
双块 212 项为 206 PASS + 6 个按名称和原因锁定的既有 skip;RSP 独立门必须为
双后端 2 PASS / 0 skip。缺失、重复、未运行的 JUnit 条目或额外 skip 均不能过门。
1. 双块车道(§4)`integration-split` 全绿。
2. `MOBILEGL_IPC_STRICT_ERRORS=1` 下 `strict-expected-markers.txt` **为空**,且两侧棘轮仍在
(空表 + 出现任何一对即红)。
@@ -290,8 +294,9 @@ f0 普查(只读):§2.4 的完整静态清单 + §2.6 的逐站点清单
## 7 与 P6 的关系
P5f 收官后,P6 的"只是传输替换"才第一次成立,而且是**被机器证明过的**,不是被引用的。
P6 的 `a6` 只读审计随之缩小为一次核验,而不是一次发现。
P5f 已完成跨角色内存依赖归零的机器门,P6 的前置条件解除。
P6 的 `a6` 仍须核对独立进程的启动、句柄/映射和配置边界;本阶段的 inproc 演练不代替
spawn 实现与跨进程设备验证。P6 尚未开工。
`P6-SPAWN-PLAN.md` 与 `P6-CONTRACT-DRAFT.md` 里凡写"`PENDING a6`"的行,
其中属于 §2 的部分改由 P5f 回答。
+46 -20
View File
@@ -1,11 +1,13 @@
# CONTRACT-P6 (DRAFT) — the backend runs in a second process
> **⏸ Blocked on P5f** (2026-09-19): this draft assumes P6 is only a transport
> swap, which is not true today - 15 `BARRIER_PULLED` fields are still filled by the
> client into a shared `gPipeInputs`, and Magma has not moved at all. See
> [`P5F-WIRE-COMPLETENESS.md`](P5F-WIRE-COMPLETENESS.md).
> **P5f prerequisites completed** (2026-09-20): field ownership has zero
> `BARRIER_PULLED` rows; the dual-block and strict gates, context/lifetime work,
> registry and reverse-channel guards, closing review fixes, and final Redmi
> paired runs have passed. See [`P5F-WIRE-COMPLETENESS.md`](P5F-WIRE-COMPLETENESS.md),
> the [closing review](notes/p5f/close-review.md) and [device report](notes/p5f/device-report.md).
>
> **Draft, written before its own audit.** Package `a6` ([`P6-SPAWN-PLAN.md`](P6-SPAWN-PLAN.md) §5)
> **P6 has not started:** `a6`, `c6`, and spawn implementation remain unstarted.
> This remains a draft written before its own audit. Package `a6` ([`P6-SPAWN-PLAN.md`](P6-SPAWN-PLAN.md) §5)
> is a read-only audit whose output is this file's input. Rows that depend on it are marked
> **`PENDING a6`**. `c6` moves this file to `MobileGL/MG_Remote/CONTRACT-P6.md`, where it becomes
> normative.
@@ -13,7 +15,7 @@
Authority once landed: this file, beside `CONTRACT-P5.md` (table 0, byte carriers, R-1…R-17),
`CONTRACT-P5B.md` (class-C slots), `CONTRACT-P5C.md` (rule E, SEG_EVENT, the guards) and
`CONTRACT-P5E.md` (rule F, the barriered predicate, the wait rule). Disagreements: this file is
newer and wins; §9 lists them. Base `feat/disaggregated @ f23fbc1b`; every `file:line` re-resolves
newer and wins; §9 lists them. Historical planning base `feat/disaggregated @ f23fbc1b`; every `file:line` re-resolves
at `c6`'s head. Paths under `MobileGL/` unless they start with `docs/`.
Changes go through the integrator, in `c6`'s copy. Packages compile against these rows from day one.
@@ -66,7 +68,11 @@ other gate here.
1. **The child must not be able to become a client.** Both required: (a) `MOBILEGL_TRANSPORT` and
every role-selecting `MOBILEGL_IPC_*` removed from the child's envp; (b) the child's config
forced to `Monolith` regardless. Either alone fails as a fork bomb.
cannot recursively select a client transport. The original plan expressed (b) as forcing
`Monolith`. **`PENDING a6`**: separate that anti-recursion decision from backend server-role
selection. P5f's record consumers currently select their server arm with an active transport;
blindly forcing `Monolith` would select frontend glue. Preserve both anti-recursion controls
while retaining the server-owned record path; `c6` must settle the concrete selector.
2. Image lookup: `MOBILEGL_IPC_SERVER_PATH` (already parsed, `Config.h` `IpcTable::ServerPath`),
then `dladdr` to find `libMobileGLServer.so` beside the loaded library. **An unresolvable path
is a named refusal, never a monolith fallback** — `ConfigLoader.cpp:315-317` names that accident.
@@ -127,14 +133,30 @@ other gate here.
## §6 Process-lifetime statics (`st`)
`g_syncedRenderStateParameters` (`MG_Backend/DirectGLES/DirectGLES.cpp:4586`) and
`ScopedDefaultUnpackState::s_synced` are process-level statics with per-context semantics, recorded
as P6's by `CONTRACT-P5C.md:538-539`. In a server process reused across client contexts they hand
the next context the previous one's synced state.
**Implemented by P5f `fs`; P6 inherits and verifies it.** The statics recorded as P6 debt in
`CONTRACT-P5C.md:538-539` no longer carry unqualified synced state between contexts. The
[fs report](notes/p5f/fs-report.md) records the full census, lifecycle rules and red-once evidence.
**Rule: any static whose meaning is per-context or per-session is keyed by the context generation
and reset at `applier_reset`.** **`PENDING a6`** for the complete list (audit item 2); the two above
are the known members. This class is structurally invisible to `inproc`.
- `ContextEpoch` combines native ES context generation, served-context serial and backend
execution arm (monolith / transport server). `ScopedDefaultUnpackState` republishes defaults
when that key changes; render-state invalidates its shadow before the version fast path.
Identical parameter bytes or versions cannot make a new epoch inherit an old sync result.
The transport raw-depth sampler owns a native sampler and rebuilds it on native generation change.
- XFB state is role-local; the server map is keyed by the record's non-reused
`BoundStreamOutputLifetimeId`, including virtual name 0, with capture-local scatter scratch.
**A served-context serial change / `applier_reset` is not object destruction.** Current binding
state is reset, but still-live paused/pending spans survive and `set_context_values` selects
their lifetime identity again; returning to a context does not emit another Begin. Native
context generation change discards the old native ids/spans, and context destruction clears them.
- Server liveness follows successful make-current and the control lifecycle. Release-current,
release-resources, context/backend destruction and loop stop clear it. Surface creation alone
is not a current context, and a verb stamp cannot revive a released server context.
`a6` checks these established ownership/lifetime rules against the new process/session boundary;
`st` verifies their socket/spawn lifecycle wiring and G5 controls. It does not introduce a new
“clear every object at every reset” policy or reopen the P5f implementation work. Additional
process/session lifetime findings, if any, remain **`PENDING a6`**; P6 still does not add multi-context
support (§9.2).
## §7 Unchanged by P6
@@ -149,7 +171,8 @@ Beyond the five-part gate (`docs/Disaggregated/ARCHITECTURE.md` §13.2):
1. G1 — pull build 0/0/0/0, `.text` unchanged.
2. G2/G14 — `integration-spawn`'s name set identical to `integration-split`'s.
3. `integration-spawn` green at the same count as `integration-split` (today 179/179).
3. `integration-spawn` green at the same count as `integration-split` (179/179 on the historical
draft baseline; `c6` refreshes the actual discovery and result sets).
4. Process tree, mechanical — child count before and after every entry: exactly one while
running, zero after. `HeadlessGL`'s fork pre-check leaves no orphan.
5. **Arm proof (ID-124)** — every spawn entry records the child pid and `transport=spawn` in its own
@@ -168,7 +191,7 @@ Negative controls, each run red once:
| S1 | `MOBILEGL_IPC_SERVER_PATH=/nonexistent` | named refusal, not a silent monolith fallback (§3.2) |
| S2 | `kill -9` the server mid-frame | §5.1's latch; the client never hangs and never keeps submitting |
| S3 | child envp not scrubbed | §3.1's second safety catches it, by name |
| S4 | `st`'s generation reset disabled | a second context inherits the first's synced state (§6) |
| S4 | inherited P5f epoch invalidation disabled in spawn lifecycle wiring | a replaced context inherits stale synced state; returning to a still-live XFB lifetime must retain its paused span (§6) |
| S5 | `WindowKind::AndroidNativeWindow` reaches the server | named `Fatal`, not a black screen (§4.3) |
S2's shape is settled before it is written. E1 demanded a `Fatal` that occurs zero times in the
@@ -176,8 +199,9 @@ entire run (ID-122); S2 must falsify *"the client can tell slow from dead"*.
## §9 Amendments to the earlier contracts
1. `CONTRACT-P5C.md:537-539` — the EGL forwarders' control plane and the `s_synced` /
`g_syncedRenderStateParameters` resets are discharged here, §4 and §6.
1. `CONTRACT-P5C.md:537-539` — EGL value framing was discharged by P5f `fc`, and the unpack /
render-state epoch work by P5f `fs`. P6 carries the existing frames over the socket (§4) and
verifies the inherited lifecycle rules in the second process (§6).
2. `CONTRACT-P5C.md:56` says P6's multi-context shape reads `MGPApplierReset::ContextSerial` for
real. **Declined**: P6 stays single-context, multi-context moves to P12 where the Service
lifecycle makes it concrete, and the assertion stands unchanged.
@@ -189,8 +213,10 @@ entire run (ID-122); S2 must falsify *"the client can tell slow from dead"*.
Real window arrival and the `android:process=":mgl"` Service (P12); multi-context (P12, §9.2);
chunked readback and the reply-slot pool (P9, §9.3); `DynamicBackendParameters` fixed-width rewrite
(P7); `MOBILEGL_IPC_POLL_ESCALATE` (P10); object-class BARRIER-PULLED rows and the frontend-keyed
twin registry (P3b/P4b, P7); Windows `pipe:` / `unix:` (§2.6); the 511 class-C entries (§7).
(P7); `MOBILEGL_IPC_POLL_ESCALATE` (P10); remaining monolith-only frontend-object / twin-registry
glue cleanup (P3b/P4b) and named P7 functionality debts; Windows `pipe:` / `unix:` (§2.6); the 511
class-C entries (§7). P5f already eliminated `BARRIER_PULLED` ownership and transport frontend-keyed
registry access; those are completed prerequisites, not debts to carry forward.
E1's re-specification (ID-122) is **not** discharged by P6 and does not become P6's because P6
starts. It appears here only because §5.3 argues it shares a predicate.
+16 -16
View File
@@ -1,10 +1,10 @@
# P6 spawn transport — 包计划
> 基线 `feat/disaggregated @ f23fbc1b`。路径在 `MobileGL/` 下,行号以该头为准。
> 历史规划基线 `feat/disaggregated @ f23fbc1b`。路径在 `MobileGL/` 下,旧行号在 `c6` 落地时重核。
> 契约草稿 [`P6-CONTRACT-DRAFT.md`](P6-CONTRACT-DRAFT.md),`c6` 落地时移为 `MobileGL/MG_Remote/CONTRACT-P6.md`。
> **⏸ 阻塞于 P5f**(2026-09-19):本计划假定“P6 只是传输替换”,而那句话今天不成立——`BARRIER_PULLED` 还有 15 个字段靠 client 填共享的 `gPipeInputs`,Magma 一条未动。先跑 [`P5F-WIRE-COMPLETENESS.md`](P5F-WIRE-COMPLETENESS.md)。
> **P5f 前提全部完成**(2026-09-20):零 `BARRIER_PULLED` 分类、双块 / strict 门、静态状态世代与生命周期、registry / 反向通道边界均已收口;阶段审查修复及最终 Redmi 六个 clean-boot 臂也已通过。见 [`P5F-WIRE-COMPLETENESS.md`](P5F-WIRE-COMPLETENESS.md)、[收口审查](notes/p5f/close-review.md)和[设备报告](notes/p5f/device-report.md)。
>
> **未开工。** 标 `待 a6` 的条目由审计确认,现在不下结论。
> **P6 尚未开工:`a6`、`c6` 与 spawn 实现均未启动。** 下文保留历史包规划;标 `待 a6` 的 P6 进程边界事项仍需审计确认,P5f 完成不等于 P6 已实现。
---
@@ -28,9 +28,9 @@
1. `SocketTransport`。`ClientSession.cpp:468` 目前硬拒非 `InProcess`。
2. `ServerMain`。今天的 `MobileGLServer`(`CMakeLists.txt:923`)是 P0 spike 桩(`tools/spikes/server_stub/main.cpp`),Android-only、默认 OFF。
3. 进程机制:fork/execve;envp 剔除 + 子进程强制 monolith(双保险);`dladdr` 兜底;有界重试握手;EOF 即退;不留孤儿。
3. 进程机制:fork/execve;envp 剔除 + 子进程禁止递归选择 client transport(双保险);`dladdr` 兜底;有界重试握手;EOF 即退;不留孤儿。原“子进程强制 monolith”的具体实现**待 a6**:P5f 的 server record 臂依赖 active transport 选路,必须区分反递归与 backend server 角色选择,不能因此回到 frontend glue。
4. 控制面帧。**P5f 包 fc 已把帧化本身落地**:forwarder 改发 `SurfaceControlFrame` 值帧(`MG_Remote/Server/SurfaceControlFrame.h`),schema 缺口(3 枚枚举 + `readSurface`/`context` 字段 + `WindowKind::MetalLayer`)已按 append-only 补齐,wire 编解码与具名拒绝在 `MG_Remote/Protocol/SurfaceOpCodec.cpp`(`ServerApplyWireSurfaceOp`)。P6 的 `cp` 只剩传输:client 侧 `EncodeSurfaceOpFrame` 上 socket、server 泵进 `ServerApplyWireSurfaceOp`、`SurfaceReply` 回程与 §4 的死亡接线。P5c 审计 G4 行,原记 P6。
5. `g_syncedRenderStateParameters`(`MG_Backend/DirectGLES/DirectGLES.cpp:4586`)与 `ScopedDefaultUnpackState::s_synced` 按 context 世代重置(`CONTRACT-P5C.md:538-539`)。
5. 静态状态 / 生命周期的 spawn 验证,**不是重做 P5f fs**。unpack / render shadow 已按 native generation、served-context serial、执行臂组成的 `ContextEpoch` 失效;raw-depth sampler 按 native generation 重建。XFB 按 server lifetime id 隔离,served-context reset 保留仍活着的 paused/pending span,native context 销毁才清对象;server liveness 由控制生命周期持有。`st` / `a6` 核这些语义在第二进程与 socket 接线下仍成立,见草稿 §6 与 [fs 报告](notes/p5f/fs-report.md)。
6. 死亡语义,见 §4。
## 3 边界:P6 不做真窗口
@@ -39,7 +39,7 @@
- P6 落 pbuffer / surfaceless / 离屏:够 `HeadlessGL`、等价 split 车道、trace replay,也正是 P6 出口门量的东西。
- 真窗口的管道(令牌、`SurfaceOp`、`SurfaceReply`)落,但到达 server 时具名拒绝。
- **P6 之后手机上能跑的是 trace 和离屏,不是游戏。**
- **P6 新增的手机 spawn 臂只承诺 trace 和离屏;真窗口游戏接入归 P12。** 现有 monolith / inproc 运行能力不因此改变。
## 4 P5e 留下的:不等待的客户端 + 会死的服务端
@@ -62,21 +62,21 @@ a6 (只读审计,不写代码)
└─ c6 (契约 + 惰性线上行,行为零变化)
├─ so (SocketTransport)
├─ sm (ServerMain + fork/exec + 进程纪律)
├─ cp (控制面:12 个 forwarder → 帧)
├─ st (静态量按 context 世代重置 + G5)
├─ cp (已有控制帧的 socket 传输 + 回程)
├─ st (验证 P5f epoch / lifetime 的 spawn 接线 + G5)
└─ t6 (spawn 车道 + 阴性对照 + CI)
└─ 集成 commit:ConfigLoader 不再拒绝 spawn
```
**a6**(先跑)。"P6 只是传输替换"的证据是 P5c 时代的;P5e 之后树变了(by-handle resolver、server 角色内存、不等待的路径)。产出:逐行清单,形状照 `~/w7/notes/p5c/p5c-audit-v1.md`(现 `notes/p5c/`)。点名查:
**a6**(先跑,尚未启动)。以 P5f 已完成的双块、身份守卫、生命周期、反向通道及设备证据为输入,核验从同进程双角色变为真实进程后的新增边界,不重复领取已完成的迁移。产出:逐行清单,形状照 `notes/p5c/p5c-audit-v1.md`。点名查:
1. 仍过线的裸指针 / 进程局部句柄。
2. **进程级静态中语义属于 context 或 session 的**——§2.5 是已知的两个,问题是还有几个。这类缺陷 `inproc` 结构性看不见。
3. `gPipeInputs` 在 spawn 下的归属(P5e 的 ID-135 结论要重验)。
4. 十二个 forwarder 对 `SurfaceOpKind` 七个枚举,缺几个。预期缺 `SetSwapInterval` / `ReleaseResources` / `SetWindowHandle`(`SwapEGLBuffers` 走记录、`InitCapabilities` 走 `CapsSnapshot`、`InitWindowSurface` 是客户端 no-op)——待 a6 确认。
2. **进程级静态中语义属于 context 或 session 的**——以 `notes/p5f/f0-statics.md` 与 fs 全清单处置为基线,验证 §2.5 的 epoch / lifetime 规则与新 process/session 退出边界;不可把每次 `applier_reset` 解释为清空所有对象。
3. `gPipeInputs` 在 spawn 下的角色归属,以及禁止子进程递归当 client 时仍选中 server record 臂的机制。
4. 复用 fc 已补齐的 `SetSwapInterval` / `ReleaseResources` / `SetWindowHandle` 等 schema 与 wire codec,核 socket 对接与 inproc-only op 的边界(`SwapEGLBuffers` 走记录、`InitCapabilities` 走 `CapsSnapshot`、`InitWindowSurface` 是客户端 no-op),不重复追加已落地枚举。
5. server 能否不链 `MG_Impl`(`MG_Backend/MGPipe/PipeInputs.h` 如此声称)。做不到就记账。
**c6**:契约;`protocol.fbs` 追加枚举(只追加);令牌类型;新旋钮(`ARCHITECTURE.md:639` 已登记的 P6+ 项,`POLL_ESCALATE` 归 P10);跨包接缝的声明 + 未落地断言体;`MobileGLServer` 真目标。
**c6**:契约;复用 fc schema,只有 a6 确认的新缺口才 append-only 扩展;令牌类型;新旋钮(`ARCHITECTURE.md:639` 已登记的 P6+ 项,`POLL_ESCALATE` 归 P10);跨包接缝的声明 + 未落地断言体;`MobileGLServer` 真目标。
**so**:`SocketTransport`。**必须在第二个进程出现之前就绿**——一次 `socketpair()` + 两个线程跑 `InProcessTransportTest` 全套,含 `BUFFER_TOO_SMALL` 留帧语义。理由同 `SessionRings.h:22-28`。
@@ -88,7 +88,7 @@ a6 (只读审计,不写代码)
1. G1 pull 构建 0/0/0/0,`.text` 不变。
2. **G2/G14**:`integration-spawn` 用例名集合与 `integration-split` 逐名相同。
3. `integration-spawn` 全绿,数字与 `integration-split` 一致(今天 179/179)。
3. `integration-spawn` 全绿,数字与 `integration-split` 一致(历史草稿基线 179/179;`c6` 重核实际发现 / 执行集合)。
4. **进程树门(机检)**:每条用例前后数子进程,运行中恰好多一个,运行后为零;`HeadlessGL` fork 预检无孤儿。
5. **臂证明门**:每条用例在自己的私有日志里留下子进程 pid 与 `transport=spawn`。ID-124 已证明假绿会发生,而一条实际跑了 monolith 的 spawn 车道能通过 1–4。
6. 逐包 red-once(R-16),各一条具名对。
@@ -102,7 +102,7 @@ a6 (只读审计,不写代码)
| S1 | `MOBILEGL_IPC_SERVER_PATH=/nonexistent` | 具名拒绝,非静默回落 monolith |
| S2 | 运行中 `kill -9` server | 客户端能区分慢与死;不挂起、不继续提交 |
| S3 | 子进程 envp 未剔除 | 第二道保险挡住递归 spawn 并具名 |
| S4 | 关掉 `st` 的世代重置 | 第二个 context 拿到上一个的同步状态 |
| S4 | 临时关闭 spawn 接线中继承的 P5f epoch 失效 | 替换 context 错用旧同步状态;返回仍活着的 XFB lifetime 必须保留 paused span |
| S5 | `WindowKind::AndroidNativeWindow` 到达 server | 具名 Fatal |
S2 的形状先想清楚再写:E1 索要的 Fatal 在整次运行里出现 0 次(ID-122)。
@@ -119,7 +119,7 @@ S2 的形状先想清楚再写:E1 索要的 Fatal 在整次运行里出现 0
## 9 不属于 P6
真窗口与 `android:process=":mgl"` Service(P12);多 context(P12,`CONTRACT-P5C.md:56` 原写 P6,本计划改判);chunked readback 与 reply-slot 池(P9);`DynamicBackendParameters` 定宽重写(P7);`POLL_ESCALATE`(P10);对象类 BARRIER-PULLED 行与 frontend-keyed twin registry(P3b/P4b、P7)。
真窗口与 `android:process=":mgl"` Service(P12);多 context(P12,`CONTRACT-P5C.md:56` 原写 P6,本计划改判);chunked readback 与 reply-slot 池(P9);`DynamicBackendParameters` 定宽重写及已具名拒绝的功能债(P7);`POLL_ESCALATE`(P10);剩余 monolith-only frontend-object / twin-registry glue 清理(P3b/P4b)。`BARRIER_PULLED` 分类与 transport 前端身份访问已由 P5f 归零,不能继续列成未偿的 P6 前提债。
## 10 开工顺序
+14 -13
View File
@@ -1,6 +1,6 @@
# MGPipe 路线图
> 状态:**P0、P0.5、P1、P2、P3a、P4a、P5、P5b、P5c、P5d、P5e 已收官**(P5c:2026-09-17,代码头 `b88e8487`;P5d:三轮,2026-09-18,代码头 `1f8de61b`)。当前头、逐门数字、开放项与下一步见 **[`CURRENT_STAGE_PROGRESS.md`](CURRENT_STAGE_PROGRESS.md)**;设计见 `ARCHITECTURE.md`;逐阶段实测见 `MEASUREMENTS.md`;P5d 报告见 [`P5D-INPROC-PERFORMANCE.md`](P5D-INPROC-PERFORMANCE.md),P5e 报告见 [`P5E-RUNAHEAD.md`](P5E-RUNAHEAD.md)。**P5e 已收官**(退役 Espryt draw path 的 lockstep,契约 `MobileGL/MG_Remote/CONTRACT-P5E.md`;十二包已全部落地合并,**run-ahead 已武装**,头 `25fba0d5`;strict 车道硬绿 179/179、`integration-gpu` 1357/1357、三个构建 flavour 全绿;设备上 inproc 已与 monolith 齐平,见 `CURRENT_STAGE_PROGRESS.md` §2.6 与 `MEASUREMENTS.md` §11);出口门逐条已跑,唯一未过的是 E1 对照脚本本身,ID-122)。**当前在 P5f**(一切状态上 wire,计划 [`P5F-WIRE-COMPLETENESS.md`](P5F-WIRE-COMPLETENESS.md))——它插在 P6 之前,因为“P6 只是传输替换”今天还不成立;P6 计划 [`P6-SPAWN-PLAN.md`](P6-SPAWN-PLAN.md)、契约草稿 [`P6-CONTRACT-DRAFT.md`](P6-CONTRACT-DRAFT.md),均尚未开工)。
> 状态:**P0、P0.5、P1、P2、P3a、P4a、P5、P5b、P5c、P5d、P5e、P5f 已收官**。P5f 于 2026-09-20 完成主机门、Redmi 六个 clean-boot 臂、跨模型族审查及修复验证;最终验收代码为 WSL `cfca93c7885fd8db1e881f91189ba59090ae9c52`(Windows `c42577a4` 等价)。证据见 [`notes/p5f/close-report.md`](notes/p5f/close-report.md)、[`close-review.md`](notes/p5f/close-review.md)、[`device-report.md`](notes/p5f/device-report.md)。**P6 的 P5f 前提已解除,a6 / c6 / spawn 实施尚未开始**。逐门数字、主分支合入记录和下一步见 [`CURRENT_STAGE_PROGRESS.md`](CURRENT_STAGE_PROGRESS.md) 与收官报告;设计见 `ARCHITECTURE.md`。P5e 的历史性能与 E1 对照债保留在阶段行、[`P5E-RUNAHEAD.md`](P5E-RUNAHEAD.md) 和 `MEASUREMENTS.md`,不由 P5f 的新对照代为关闭。
## 通用纪律(每个 commit)
@@ -29,22 +29,22 @@
| **P5c** `inproc` 共享内存读点归零 | ✅ `11ac3de6..b88e8487` | server 端纹理 staged shadow(`StagedTextureStore`,句柄为键、整段覆盖、defined-ness 追踪);`SEG_EVENT` 三个 producer + `kEventGlError`(反向通道零裸指针);sink / twin 按记录句柄解析(blit 具名臂经 verb 句柄工作区,Magma 走 G6 消费臂);`applier_reset` / `object_death` 控制记录(opcode 77/78,framebuffer 首个 wire delete);`set_context_values`(79)退役全部值类 BARRIER-PULLED 行,三 shutter 自答;双层 `Fatal{RoleViolation}` 守卫 + `InBarrierWait` 接线;两个具名豁免 scope(通告家族 P4b/P7、G6 registry 家族 P3b/P4b)承接未到期的债 | 角色守卫开启下 unit 2187/2187(strict 下同绿)、`integration-split` 111/111、每层守卫 red-once 按名变红;纹理 `0xDD` audit 在 bsl / complementary 两条 in-world trace 零 Fatal;rsp 按帧实测(bsl 948.5/帧,残留全为钉住的对象类 15 行);G1 三个认定 resize(SwapchainObject::Create / CopyTexSubImage2D / ScopedRestartIndexSubstitution,均已具名)+ `.text` −16 B、pull 构建零 MG_Remote 符号;G5 保护区字节一致;双生成器 --check/--self-test 绿 | P5b |
| **P5d** `inproc` 性能专项 | ✅ `cb06538c`、`56a77348`、`1f8de61b` | 一二轮:persistent-map 推送三级臂(mprotect 脏页追踪 + 哈希抑制 + 绑定过滤 `PushDrawConsumers`)、barrier 批处理 `MOBILEGL_IPC_BATCH_WAITS` + 延期销毁队列、自旋时钟 64 合 1、零页注册 + shadow 页对齐分配。三轮(按符号化 profile 逐项切,四包 + 一份 lockstep 可行性研究):apply 空转轮询零锁(控制邮箱原子影子位)、`Doorbell::Wait` 校准自旋稳态不读时钟、wait/park 计数进 stats;`OnApplyThread()` 内联为线程指针比较、三个 scope 深度计数器退掉 `thread_local`;shadow 分配尺寸补页、追踪范围向外对齐、边块哈希消失、脏页排空修复;image unit 高水位、残余填充 memo、server stamp 常量表;`generate_mipmap` 不再免等(apply 读残余输入)、death 测试围栏 | 三轮设备(Redmi,CPU 定频):inproc **64.3 → 103-106 fps**(p50),client 线程 CPU 15.0 → 9.2 ms/帧、apply 12.4 → 7.0-7.4;monolith 同场景 115(120 Hz vsync 封顶的运行)/ 206(一次未封顶,渲染线程 5.0 ms/帧 大核);配对比较以逐线程 CPU/帧为主,见报告"数字"节;unit 2203/2203、`integration-split` 111/111(两条曾 flaky 的用例复跑 6/6);双生成器、include 闭包、dirty-surface、doc 引用绿。未完成:R-1 序列化(研究结论:留给 P3b/P4b 后的 P11 `gPipeInputs` 版本化)、线程放置(内核忽略亲和)、`SetHashSuppressor` 哈希等小项。报告:[`P5D-INPROC-PERFORMANCE.md`](P5D-INPROC-PERFORMANCE.md) | P5b |
| **P5e** 退役 Espryt draw path 的 lockstep | ✅ **已收官(2026-09-19)**,附一条具名未决:E1 对照需按 ID-114 重新定义 | 契约 `MG_Remote/CONTRACT-P5E.md`(规则 F:**未设障**记录的 apply 不得读任何 client 内存;ID-84 限定它只约束未设障记录);裁定 **ID-80..136**(`~/w7/notes/p5e/INTEGRATOR-DECISIONS-P5E.md`)。**十二个包,三波**:wave 1 **c0e**(契约 + 线上行:`PipeCalls.def` 第五列 `WaitClass`、`set_program_bindings` opcode 80、`kCapRunAheadApply` 位 10 仅 DirectGLES 臂、`kDrawClientArrays`、子系统位 13、两个旋钮)→ **id**(registry 按 `{slot, gen}` 重键、by-handle resolver、分配器守卫);wave 2 **vi / sb / pg / tx2 / fb** 五个 per-draw 家族 ∥ **ra**(等待规则、present credit、`gPipeInputs` 变 server 角色内存),加 **fix1**(设备发现的 monolith 臂回归,ID-107);wave 3 **pa**(program 家族离开前端)、**mv**(multi-draw + 五个档位的门禁条目)、**gl**(门禁机制本身 + 两处潜伏崩溃)、**ra2**(翻开关后暴露的竞态)。**`kMGPipeP5eRunAheadReady` 与 `kMGPipeP5eClientWaitRuleLanded` 均已翻**。最大的那次迁移(逐 draw 的 `GetProgramForDraw`)**没有改动任何线上结构**:记录早就带着逐 link 的 `ProgramArchive`,缺的是仍去问前端对象的读者。报告 [`P5E-RUNAHEAD.md`](P5E-RUNAHEAD.md) | 出口门已逐条跑过(BRIEF-P5E §3,2026-09-19 在集成树上,run-ahead 已武装):**item 1** unit 在 strict 两臂均 **2256/2256**;**item 2/3** `integration-split` **179/179**、逐条普查零 `Fatal{`、`Admitted{` 恰为八行;**item 4(a)** `RUN_AHEAD=0` 作为配对对照 **179/179 绿**;**item 4(b)** `VERB_BARRIER=0` **变红**(车道 62/179);**item 4(c)** Magma 逐字记下 `run-ahead requested, server does not publish kCapRunAheadApply - running lockstep`,而 Espryt 对照记下 `run-ahead ARMED`;**item 5** 在集成树上重跑 red-once(ID-121 重排后的形式):倒掉 pa 的臂得 `GetProgramForDraw@DrawArrays`、倒掉 mv 的臂得 `GetBoundVertexArray@DrawArrays`,**恰好各一个具名对**,还原后各自转绿;**item 7** `MOBILEGL_IPC_AUDIT=1` **179/179**。**唯一未过的是 E1 对照脚本本身**(ID-122):已修掉它两个遮蔽性缺陷(选中了一个在本车道永远跑不起来的阳性对照用例;ctest 与日志助手对“谁被选中”意见不一致),但它索要的 `Fatal{BarrierViolation}` 在整次运行里 **出现 0 次**:`BATCH_WAITS` 默认值 1 下那个重叠不发生,而 run-ahead 武装后 `VERB_BARRIER=0` 还会顺手关掉 run-ahead(ID-114),它产生的那条臂**既不是 lockstep 也不是 run-ahead**。E1 需要重新定义它要证伪什么,不是再调阈值;在想清楚之前不动它的计数规则,否则只是换一种伪绿。G1 仍由 CI 断言(ID-123) | P5d |
| **P5f** 一切状态上 wire | 📝 **计划已起草(2026-09-19)**,未开工 | 计划 [`P5F-WIRE-COMPLETENESS.md`](P5F-WIRE-COMPLETENESS.md)。**P6 的前提“只是传输替换”今天不成立**,本阶段把它变成成立:`FieldOwnership.def` 的 **21 行 / 15 个 `BARRIER_PULLED` 字段**归零(其中八个 P5e 只为 Espryt 退役、**Magma 一条未动**);十二个 EGL forwarder 的控制面帧(P5c 审计 G4,原记 P6);per-context 语义的进程级静态量;`MGPipeFrontendKeyedRegistryScope` 的约 12 个站点;反向通道中直接触碰 client 内存的部分。中心机制是**双块演练**:`inproc` 下给两个角色各一份 `PipeInputs`,把拆进程的语义在不拆进程的前提下先跑一遍 | 双块车道 `integration-split` 全绿;`strict-expected-markers.txt` **为空**且两侧棘轮仍在;`FieldOwnership.def` 零 `BARRIER_PULLED` 行、`rsp` 逐帧读零;Magma 与 Espryt 跑同一套判据;关掉双块必须有具名用例由绿转红 |
| **P6** spawn transport | ⏸ **阻塞于 P5f**;计划与契约草稿已起草(2026-09-19) | `SocketTransport`(socketpair + fork/execve,envp 剔除 + 强制 monolith 双保险);`ServerMain`;`MOBILEGL_IPC_SERVER_PATH` + `dladdr` 兜底;有界重试握手;EOF 即时退出;device-lost latch;EGL forwarder 的控制面帧;P5c 留下的 `s_synced` / `g_syncedRenderStateParameters` 按 context 世代重置。包与依赖序见 [`P6-SPAWN-PLAN.md`](P6-SPAWN-PLAN.md):**a6**(只读审计,先跑)→ **c6**(契约 + 惰性线上行)→ **so / sm / cp / st / t6** 并行。契约草稿 [`P6-CONTRACT-DRAFT.md`](P6-CONTRACT-DRAFT.md)(规则 G:**角色不得指名进程局部句柄**)。**落地边界**:P6 只落 pbuffer / surfaceless / 离屏(够跑 `HeadlessGL`、等价 split 车道与 trace replay);`ANativeWindow*` 在子进程里无意义,**真窗口的到达是 P12**,到达 server 时具名拒绝。新设计只有一处:P5e 之后客户端不再等待,而对端进程会死——闩锁语义照抄 `ARCHITECTURE.md:504`,新的是“慢与死如何区分”(不得用超时阈值) | P5b 的完整渲染路径在 `spawn` 下绿;进程树只多一个子进程;`HeadlessGL` fork 预检无孤儿;OpenRA 在 Adreno 830 上 split SSIM ≥ 0.99;**G2**:`integration-spawn` 的用例名集合与 `integration-split` 逐名相同(名集合不同即意味着偷偷少跑);**臂证明门**:每条用例在自己的私有日志里留下子进程 pid 与 `transport=spawn`(ID-124 已证明这类假绿真会发生,而一条实际跑了 monolith 的 spawn 车道能通过其余所有门);性能只记录不阻塞,但 **socket 门铃相对 inproc condvar 的代价必须真采到**(P6 唯一预期的回归) |
| **P3b / P4b** 深化(Espryt) | 待排 | 按存储属主键控的发射游标与 view 索引重映射;`g_fboTextureSyncList`;`ResolvedTextureBindingMemo` / `SamplerPassMemo` / image sweep / program registry 重键;XFB scatter 搬到 client;删 fragColor 重推导 workaround 与 `g_broadcastMemo*`;raw-depth-fetch sampler 原生化;回读 / pack state;P4a 记下的 R-3 / R-4 / R-5 / R-7 / R-10 / R-11;`ProgramArtifacts.h` 的 NDK 尺寸钉 | 纹理 / program 场景;CTS `texture_*` / `shader_image_*` / `packed_pixels` 在 0.5 pp 内;每一个 Iris trace;`TextureUploadShapeScenario` 升级成门 |
| **P5f** 一切状态上 wire | ✅ **已收官(2026-09-20)**;验收代码 Windows `c42577a4` / WSL `cfca93c7885f` | f0 普查、f1 双块、fc 控制帧、fe Espryt 字段、fm Magma record consumers、fs 静态世代/角色及 liveness、fr registry、fv 反向回调均已合并。字段归属 **41 RECORD_SUPPLIED / 6 APPLIER_DERIVED / 0 BARRIER_PULLED / 16 FATAL**;strict / dualblock 预期 marker 集合均空。控制帧与静态量工作已完成,不再列为 P6 待实现项 | unit **2310 = 2300 PASS + 10 skip**;GPU **1377** 零失败;ordinary / strict split **180 = 176 PASS + 4 skip**;双块 **212 = 206 PASS + 6 精确具名 skip**;双后端 RSP 门 **2 PASS / 0 skip**、逐帧 rsp=0。G1 `.text` 10806051、symbols 27815 恒等且 0/0/0/0;G2 3016 同名;G14 3646→3744 无删名。逐包与收官修复均有 red-once;Claude 异族终审 P1/P2 已修;Redmi 六 clean-boot 臂 **60 PASS / 6 skip / 0 failed**、36 个窗口 rsp=0。详见 [`close-report`](notes/p5f/close-report.md) |
| **P6** spawn transport | **P5f 前提已解除,尚未实施**;a6 / c6 待开始 | `SocketTransport`(socketpair + fork/execve,envp 剔除 + 强制 monolith 双保险);`ServerMain`;`MOBILEGL_IPC_SERVER_PATH` + `dladdr` 兜底;有界重试握手;EOF 即时退出;device-lost latch。消费 P5f 已落地的值控制帧与 server-owned 状态,不重做 EGL 帧化或静态世代隔离。依赖序见 [`P6-SPAWN-PLAN.md`](P6-SPAWN-PLAN.md):**a6**(核验进程装配/链接边界)→ **c6**(契约)→ **so / sm / cp / st / t6**。契约草稿 [`P6-CONTRACT-DRAFT.md`](P6-CONTRACT-DRAFT.md)。边界仍为 pbuffer / surfaceless / 离屏;真窗口到达归 P12。需区分不等待的 client 与已死亡的 server,不以超时阈值代替 device-lost 判定 | P5b 的完整渲染路径在 `spawn` 下绿;进程树只多一个子进程;`HeadlessGL` fork 预检无孤儿;OpenRA 在 Adreno 830 上 split SSIM ≥ 0.99;`integration-spawn` 与 `integration-split` 名集合一致;每条私有日志证明子进程 pid 与 `transport=spawn`;socket 门铃代价实际测量,性能只记录 |
| **P3b / P4b** 深化(Espryt) | 待排 | 按存储属主键控的发射游标与 view 索引重映射;`g_fboTextureSyncList`;`ResolvedTextureBindingMemo` / `SamplerPassMemo` / image sweep / program registry 重键;XFB scatter 搬到 client;删 fragColor 重推导 workaround 与 `g_broadcastMemo*`;raw-depth-fetch sampler 的 monolith 清理(transport 原生臂已由 P5f fs 落地);回读 / pack state;P4a 记下的 R-3 / R-4 / R-5 / R-7 / R-10 / R-11;`ProgramArtifacts.h` 的 NDK 尺寸钉 | 纹理 / program 场景;CTS `texture_*` / `shader_image_*` / `packed_pixels` 在 0.5 pp 内;每一个 Iris trace;`TextureUploadShapeScenario` 升级成门 |
| **P7** DirectVulkan(Magma)全量迁移 | 待排 | 其余 10 个子系统:`SetupDrawSnapshot` 探测字段塌成 dirty mask;占位纹理原生化;具名 UBO host payload(D-B8);内部 shader 烘焙;`VertexInputStateFactory` 内容寻址 CSO;D18 容器纪律保留 | 集成 + trace 在 Magma 的 push 与 split 下全绿;verify 零分歧;`nm -D libMobileGLServer.so \| grep glslang` 为空;CTS 0.5 pp 内。**再基线检查点:中点完成子系统 < 40% 立即重定基线** |
| **P8** emulation 下放 + 索引宿主镜像 + 协议广度 | 待排 | `MG_Impl/Pipe/HostResolve.cpp`(client 数组范围、最大索引扫描、`*IndirectCount` 解析,逐站点 reconcile);`Server/IndexHostMirror`;CopyImage 镜像搬到 client;viewport-array 回放验证;`generate_mipmap` 计划 + CPU 回退纹素;大 blob carrier(开放问题 11);无 present fence tick;`kCapDriverOrderedXfbCapture` | `'^DirectGLES\.Split\.'` 与 `'^DirectGLES\.'` 逐名相同;trace split 双后端 SSIM ≥ 0.99 含两个 `coherent_as_flush` fixture;`ClientArrayAfterComputeWriteScenario`;`create-indirect` 上 `roundtrips-per-frame` 读零;`index-mirror-bytes` 逐用例发布 |
| **P9** 反向通道 | 待排 | `SEG_REPLY` 异步 slot 池;PBO 回读 fire-and-forget;`OnGpuWritten` 收窄;`OnBufferWriteback` 批处理 + epoch 排序;`OnXfbScatterReady`;`OnTextureWriteback`;`OnMipLevelsGenerated`;纹理拉取四条缓解 + 终止符;`OnGlError` 有序;`OnSurfaceChanged`;`OnLog` 分级;`SEG_EVENT` 溢出策略;class-C 的 readback 尾 | 回读 / XFB 场景在 split 下绿;`TextureRemintPullScenario`(含无解用例);拉取计数逐 trace 发布;两条故障注入 |
| **P10** sync / query / present 节奏 | 待排 | client 铸造 query handle;轮询入口成门铃点 + `MOBILEGL_IPC_POLL_ESCALATE`;fence 完成度来自逐 fence 退休;非 present fence tick;`present` 1:1;credit 默认 1;roundtrip 计数器与输入延迟直方图;class-C 的 query / swap-interval 尾 | query / XFB / `AsyncCompile` 场景在 split 下绿;trace 上 draw / state / upload 路径 roundtrip 读零;零 timeout 轮询有界退出;配对 A/B 记录 |
| **P11** persistent map 与 ≥16 MiB 采纳 | 待排 | POST 探针档位选择(T0 主攻,Adreno 可选 T1,T2 回退);`SEG_ADOPT` 生命周期绑 `completedFrameSerial`;**`gPipeInputs` 版本化 / 双缓冲**(P5d 研究:draw barrier 延后一个 verb 的前提,须在 P3b/P4b 的句柄键控 twin 表之后)。**P5e 的更正**:P5e 退役 draw lockstep **没有**需要它——ra2 实测证明字段**值**已由 `SuppliedFieldMask` 分区,当时那次竞态在**元数据标量**上,修法是让守卫测事实而非断言未来(ID-135)。本行对一般情形仍然成立,且契约 §3.2 的 per-role stamp 存储仍未落地 | `LargeArenaAdoptionScenario` 在所选档下绿;26.3 与两个 Create fixture SSIM ≥ 0.99;Adreno 830 上 p99 帧时与峰值 RSS 对采纳基线(163→21 ms / 40→115 fps / ~400 MB)回归不超过 10% |
| **P11** persistent map 与 ≥16 MiB 采纳 | 待排 | POST 探针档位选择(T0 主攻,Adreno 可选 T1,T2 回退);`SEG_ADOPT` 生命周期绑 `completedFrameSerial`;**`gPipeInputs` 版本化 / 双缓冲**(P5d 研究:draw barrier 延后一个 verb 的前提,须在 P3b/P4b 的句柄键控 twin 表之后)。**P5e 的更正**:P5e 退役 draw lockstep **没有**需要它——ra2 实测证明字段**值**已由 `SuppliedFieldMask` 分区,当时那次竞态在**元数据标量**上,修法是让守卫测事实而非断言未来(ID-135)。本行保留采纳存储的一般版本/时序问题;契约 §3.2 的 per-role stamp 已由 P5f 落地,不再是待办 | `LargeArenaAdoptionScenario` 在所选档下绿;26.3 与两个 Create fixture SSIM ≥ 0.99;Adreno 830 上 p99 帧时与峰值 RSS 对采纳基线(163→21 ms / 40→115 fps / ~400 MB)回归不超过 10% |
| **P12** Android 生产窗口路径 | 待排 | `android:process=":mgl"` Service 收 Java `Surface`;server 生命周期绑 Activity;FCL env 与 plugin APK 开关表接线 | Minecraft 经 FCL 在 spawn 模式下于 Adreno 830 双后端入世界;杀 server 产生干净 device-lost latch |
| **P13** 退役 pull 路径 | 待排 | 删 `SnapshotFromGLContext()` 非 verify 分支、`MGB_CTX`、`MOBILEGL_PIPE_PUSH`、`MOBILEGL_PIPE_LEGACY_MEMOS`;保留 `MOBILEGL_PIPE_VERIFY`;MGPipe recorder;删 `set_residual_value_state`;在计数器活着的情况下重调幸存缓存容量 | `static_assert(sizeof(ResidualValueBlock) == 0)`;三道纯度门在非 verify 构建上转绿;recorder 金标建立;monolith 逐线程 CPU 不差于 P0 基线 |
CTS 周转单独计价(`gl44to46` 约 56,271 例):逐阶段只跑该阶段可能影响的具名块;完整 caselist 只在架构边界与合并 `dev` 之前跑,放 CI 不放关键路径。
## P5c 计划:`inproc` 的共享内存读点归零(审计头 `a79a0af6`,2026-09-17)
## 历史:P5c 计划与审计(`inproc` 共享内存读点;审计头 `a79a0af6`,2026-09-17)
**为什么插在 P6 之前**:P5 / P5b 的 `inproc` 只把 verb 记录、`SEG_STAGE` blob、reply 与 caps 快照做成了 wire。对 `a79a0af6` 的只读静态审计(`~/w7/notes/p5c/p5c-audit-v1.md`,59 行清单,逐条在该头上重新解析)证明两个角色之间仍有一批**不经任何载体的直接内存读写**,靠 verb barrier 与同一地址空间才正确。它们不是传输问题:`spawn` 换掉的只是 ring 的传递方式,而这些读写在另一个进程里根本没有对应内存。P5c 的目标是让 `inproc` 诚实——两线程之间除 `SEG_CMD` / `SEG_STAGE` / `SEG_REPLY` / `SEG_EVENT` / caps 快照 / 控制帧之外零直接访问——从而 P6 只是传输替换。**本节只是计划,尚未实现。**
**为什么插在 P6 之前**:P5 / P5b 的 `inproc` 只把 verb 记录、`SEG_STAGE` blob、reply 与 caps 快照做成了 wire。对 `a79a0af6` 的只读静态审计(`~/w7/notes/p5c/p5c-audit-v1.md`,59 行清单,逐条在该头上重新解析)证明两个角色之间仍有一批**不经任何载体的直接内存读写**,靠 verb barrier 与同一地址空间才正确。它们不是传输问题:`spawn` 换掉的只是 ring 的传递方式,而这些读写在另一个进程里根本没有对应内存。P5c 的目标是让 `inproc` 诚实——两线程之间除 `SEG_CMD` / `SEG_STAGE` / `SEG_REPLY` / `SEG_EVENT` / caps 快照 / 控制帧之外零直接访问——从而 P6 只是传输替换。**本节保留 P5c 启动时的计划与审计语境;P5c 已收官,后续对象类、控制帧、静态量与反向通道的收口结果以 P5f 报告为准。**
### 审计清单(按家族;`file:line` 以 `a79a0af6` 为准,完整 59 行见报告)
@@ -70,7 +70,7 @@ CTS 周转单独计价(`gl44to46` 约 56,271 例):逐阶段只跑该阶段
| G3 | C→S 写 | 六种前端对象死亡:栈上结构体指针经 mailbox 送到 apply 线程(framebuffer 没有 wire delete opcode) | `DirectGLES/Managers.cpp:206-228` | 阻塞 + 同地址空间 | 无 | `object_death` wire 记录 |
| G4 | C→S 控制 | 十二个 `Server*` EGL forwarder 经 one-slot mailbox 传**函数指针 + `void*` 栈局部** | `MobileGL/MG_Remote/Client/BackendObject_Remote.cpp:125-264`;邮箱本体在 fc 前的 HEAD 上是 `ServerLoop.cpp:533-568`(PumpControlRequest)+ `:645-707`(RunOnApplyThread)——本行原引 `:543-598`,f0-egl F9 修正 | 阻塞 | `Fatal{ApplyThreadNotRunning}` | **已由 P5f 包 fc 帧化**(原记 P6):`SurfaceControlFrame` 纯值帧走同一阻塞通道(`Server/SurfaceControlFrame.h`、分发 `ApplySurfaceControlFrame`),wire 编解码与具名拒绝在 `Protocol/SurfaceOpCodec.cpp`;报告 `notes/p5f/fc-report.md` |
| G5 | C→S 读 | `ServerLoop::OnApplyThread()` 每条 routed 记录读;bring-up 直接读 `loop.Backend()` / `MGPipeGetResourceOps()` | `MobileGL/MG_Remote/Client/WireTables.cpp:71`;`MobileGL/MG_Backend/Init.cpp:100`、`:145`、`:164-170`、`:247` | 同进程 | — | client 本地角色标志;caps 快照的 cap 位(P6 顺手) |
| G6 | shared | 前端地址 / lifetime-id 键控的 Espryt twin registry;持前端裸指针的 memo(`ResolvedDrawBuffers::Entry::frontend`、三张 texture sync list);server 读 `pDefaultFramebufferInfo`;`g_rawDepthFetchSamplerState`;`ScopedDefaultUnpackState::s_synced` 从不按 context 世代重置 | `DirectGLES/Managers.h:309-377`、`:1185`;`DirectGLES/DirectGLES.cpp:61-62`、`:1958-1987`、`:2846`;`DirectGLES/Managers.cpp:5806-5812` | barrier / server 私有 | — | P3b/P4b 的 twin 表重键与 D-C1;`s_synced` 按 context 世代重置归 P6 |
| G6 | shared | 前端地址 / lifetime-id 键控的 Espryt twin registry;持前端裸指针的 memo(`ResolvedDrawBuffers::Entry::frontend`、三张 texture sync list);server 读 `pDefaultFramebufferInfo`;`g_rawDepthFetchSamplerState`;`ScopedDefaultUnpackState::s_synced` 从不按 context 世代重置 | `DirectGLES/Managers.h:309-377`、`:1185`;`DirectGLES/DirectGLES.cpp:61-62`、`:1958-1987`、`:2846`;`DirectGLES/Managers.cpp:5806-5812` | barrier / server 私有 | — | 历史移交给 P3b/P4b / P6;transport registry 与 `s_synced` 世代问题已由 P5f fr / fs 收口 |
| A1 | — | barrier 的 client 半边断言从未接线:`InBarrierWait()` 零调用点,只有 `ApplyThreadIsInsideApplier` 在 emit 时检查 | `MobileGL/MG_Remote/Client/ClientSession.cpp:880`、`:748-753` | — | — | 接上,或删掉契约里的这句声明 |
已确认 wire-clean、不进 P5c:buffer 全家族(`Ops_H_*` 只拿句柄 + 记录 + `SEG_STAGE` 字节,`StagedShadowStore::Adopt` 复制,`Fatal{StageSnapshotTooNarrow}` 六处);`resource_respecify` 初始字节双向拒绝;persistent map 仿真档按块过 `SEG_STAGE`,`Fatal{RoleViolation}` 挡住 apply 线程;`CreateShaderState` 归档是一个 blob;caps 的格式表与 renderer 字符串走 `CapsSnapshot` 控制帧(`GetCaps` 记录本身已死,只是卫生项);tight ReadPixels;`DrawVbo` 用户索引;fence 家族;`gMGPipeSegmentResolver` 与 `gBackendFunctionsTable` 的角色划分。
@@ -98,9 +98,9 @@ CTS 周转单独计价(`gl44to46` 约 56,271 例):逐阶段只跑该阶段
5. **Redmi 四臂复测**(记录,不设门):writeback / gpu-written 改走事件后 barrier tax 重新记录。
6. G1 0/0/0/0、G2 / G14、G5 照旧。
### 留给后续阶段的(P5c 不碰)
### 历史移交项(P5c 当时不碰)
对象类 BARRIER-PULLED 行与 twin registry 的前端键(P3b/P4b、P7);XFB scatter / `OnXfbScatterReady`、`OnTexturePullRequest` 与终止符、`OnGlError` 有序化(P9);EGL forwarder 的控制面(原记 P6,**P5f 已收回为包 fc 并落地**,见 G4 行);`copy-image-shadow-mirror` 与 CopyTex 纹素回写(P8 / P9);`s_synced` / `g_syncedRenderStateParameters` 的 context 世代重置(P6)。
P5c 当时移交的对象类 BARRIER-PULLED、transport registry 前端键、EGL 控制面、`s_synced` / `g_syncedRenderStateParameters` 世代与反向通道跨角色访问,已在 P5f 收口。P9 的异步化/排序、P8/P9 的协议广度与仿真功能仍按各阶段推进;不要把这份历史清单重新当成 P6 的帧化或静态量施工单。
## 里程碑
@@ -108,6 +108,7 @@ CTS 周转单独计价(`gl44to46` 约 56,271 例):逐阶段只跑该阶段
- **P3a / P4a 出口(2026-09-08)**:各 1 天,远低于 27 / 39 天的再基线绊线,未触发重定基线。
- **P5 出口(2026-09-16)**:缩减路径首个 IPC 帧;最终全门在 E3(a) 停止;红米四臂的 split 均停在索引 draw,barrier tax 未测(归 P5b)。
- **P5b 出口(2026-09-16,已达成)**:主机全门 `348d22a4` complete;79 trace 72/6/1;设备源头 `82683d4a`(APK `p5bcodex2`)Redmi 正确性 8/8——四条 A/B trace 双后端首次在设备上 inproc 渲染;barrier tax 首测 split−push 逐线程 CPU p50 +5.9% – +18.2%。
- **P5f 出口(2026-09-20)**:双块和 strict 空棘轮、逐帧 rsp=0、零 BARRIER_PULLED、主机全门、异模型族审查修复和 Redmi 六 clean-boot 臂全部完成;P6 前提解除,实施未开始。
- 仍是方向、不据此伪造新日历:全功能 split(P8 之后)、纯度门在非 verify 构建上转绿(P13)。
再基线检查点仅剩一条:**P7 中点完成子系统 < 40% 立即重定基线**(P3a 的检查点发现不了 Magma 特有的超期)。
@@ -117,14 +118,14 @@ CTS 周转单独计价(`gl44to46` 约 56,271 例):逐阶段只跑该阶段
| 债务 | 去向 / 当前口径 |
|---|---|
| P5 的 27 个普通 inproc wrong-answer(历史计数) | 22(14 layered + 3 packed depth/stencil + 5 framebuffer recycle)→ P4b/P7 texture readback;3 → P7 query;1 inspection → P6;1 FBO/RBO delete 用例在 r1 定向验证中通过,完整像素因果未隔离。最终计数以 `MEASUREMENTS.md` §7.2 的同名比对为准 |
| `rsp` residual inputs | **P5e 已重写这条的口径**:`integration-split-strict` 现为硬绿车道(逐条普查 179/179、`Fatal{` 为零、`Admitted{` 八行,均有退役相)。原先的“未设障记录 `rsp` = 0”**按构造就是空的**:`CountBarrierPull` 的未设障臂在 `++g_residualPulls` 之前且 `[[noreturn]]`,所以 `rsp` 只数**设障**的 pull;ID-119 改写为“`rsp` 只数被采纳的设障 pull,且等于被采纳标记的计数”。剩余八行分属 P7 / P8 / P9 / P3b•P4b |
| `rsp` residual inputs | **P5f 已关闭残余读取**:字段归属 41 record / 6 derived / 0 barrier / 16 fatal;strict 与双块 marker 表均为空,双后端逐帧 RSP 门 2 PASS / 0 skip,Redmi 36 个统计窗口 rsp=0。P5e 的“rsp 只计被采纳设障 pull”是历史计数规则,八对 admitted 的历史观察不再是当前允许集合 |
| `SEG_REPLY` 2 MiB 单槽 payload cap | 更大 readback 需要 P6+ chunking 或专用 carrier(ID-47) |
| `GetCaps` 的两个 blobref | 目前不骑 record;一旦运输,必须有 server→client carrier rule,不能套 `SEG_STAGE` |
| PACK-PBO readback | P5 具名拒绝;真实形状是 server 写 buffer resource、client `MarkGpuWritten`,P6(ID-57) |
| ABI fingerprint | 不混 segment sizes;改变 8/32/16 MiB + 256 KiB ledger 时仍欠这项 |
| 默认 32 MiB staging | 目标负载单次 128 MiB 上传装不进默认 stage;普查 / Redmi 显式 256 MiB profile,默认不改;分块 / 专用 carrier 归 P8(开放问题 11) |
| P5b 的 inproc 依赖 | 具名 blit 的 scoped client binding + barrier;mip descriptor 的 registry 身份查询依赖 barrier-held object;FBO death 的 inproc mailbox。P6 必须替换 |
| 未迁移与仿真路径 | 15 个 class-C 槽(query / sync 尾 / `GetTexImage` / `SetSwapInterval`)→ P9 / P10;client vertex arrays、multi-draw client indices、RGB 三通道 CPU mip、renderbuffer copy endpoint、未绑定 named clear、`texture-remint-pull` 仿真保留具名拒绝 → P8 / P9;Magma split compute / image 路径 82 个错答 → P7 | **P5e 补**:client vertex arrays 在 run-ahead 下是**具名拒绝**(ID-82,`Fatal{UnmigratedVerb, "DrawArrays+CLIENT_ARRAYS"}`),并有自己的预期红车道 `integration-clientarrays-split`(ID-134);staging 仍归 P8
| P5b 的 inproc 依赖 | 历史的 scoped client binding、mip registry 查询与 FBO death mailbox 已经 P5c/P5f 改为记录、句柄和控制/事件路径;P6 核验并装配已有载体,不再重做这些迁移 |
| 未迁移与仿真路径 | 15 个 class-C 槽(query / sync 尾 / `GetTexImage` / `SetSwapInterval`)→ P9 / P10;client vertex arrays、multi-draw client indices、RGB 三通道 CPU mip、renderbuffer copy endpoint、未绑定 named clear、`texture-remint-pull` 仿真保留具名拒绝 → P8 / P9;Magma split compute / image 的“82 个错答”是 P5b 历史普查计数,不是当前失败清单;P5f fm 的无应用 buffer draw/compute、sampler/image record 子集已通过,应用 buffer、placeholder/native-format 等剩余功能广度仍归 P7 | **P5e 补**:client vertex arrays 在 run-ahead 下是**具名拒绝**(ID-82,`Fatal{UnmigratedVerb, "DrawArrays+CLIENT_ARRAYS"}`),并有自己的预期红车道 `integration-clientarrays-split`(ID-134);staging 仍归 P8
| E2 wire 内容控制 | draw-drop 是 OpenRA 的有效控制(758 draws,SSIM 0.000036);clear-drop 被全屏 overdraw 掩盖,不能作控制 |
| max record bytes | 实测 reduced / OpenRA `maxrec=784 B`,默认 cap 4 MiB;只代表所测负载,后续索引 / indirect 尾仍须记录 |
| 树外脚本 | 普查跑器、`wsl_p5_gate.sh`、Redmi 定频行都在 `~/w7/notes/`,git merge 不会传播 |
+48 -83
View File
@@ -1,94 +1,59 @@
# P5f 会话交接(波次 2 已集成)
# P5f 交接:已全部收官
> 2026-09-19 续跑更新。主 worktree:
> 2026-09-20。交付 worktree:
> `C:/Users/geekerwan/AndroidStudioProjects/FoldCraftLauncher/MobileGL-disagg`,分支 `feat/disaggregated`。
> 计划:`docs/Disaggregated/P5F-WIRE-COMPLETENESS.md`。
> 完整结果见 [close-report.md](close-report.md),设备见 [device-report.md](device-report.md),
> 阶段终审见 [close-review.md](close-review.md)。最终行为验收头 `cfca93c7`,之后仅文档/复现工具。
## 0. 三十秒版
## 0. 当前结论
**fc / fe / fm 已完成并按序集成。不要再按旧交接的“fe/fm 从未开工”重开。**
**P5f 已全部完成。不要重开 fe / fm 或 fs / fr / fv,也不要重复设备六臂。**
P6 的 P5f 前提解除;P6 的 a6 审计、c6 契约冻结和 spawn 实现均未开工。
| 包 | 状态 / 分支头 |
| 包 | 完成证据 |
|---|---|
| f0 | 已合入 `e75e00cb`,八份普查保留 |
| f1 | 已合入 `cfcc12f7` + `418c765c` |
| fc | 已集成 `p5f/fc @ b5c60d5a`,含控制帧复审修复 |
| fe | 已集成 `p5f/fe @ 203f59cc` |
| fm | 已集成 `p5f/fm @ 3cc397d3`;行为代码 `552ade5b` |
| fs / fr / fv | 尚未开工,见 §3 |
| P5f 收口 / 设备 / 异模型族终审 | 尚未完成,P6 继续阻塞 |
| f0 | `e75e00cb`,八份历史普查 |
| f1 | `cfcc12f7` + `418c765c`;[f1-report.md](f1-report.md) |
| fc | `b5c60d5a`;[fc-report.md](fc-report.md) |
| fe | `203f59cc`;[fe-report.md](fe-report.md) |
| fm | `3cc397d3`,行为代码 `552ade5b`;[fm-report.md](fm-report.md) |
| fs | `863fd1f5`;[fs-report.md](fs-report.md) |
| fr | `bf5ad470`;[fr-report.md](fr-report.md) |
| fv | `4cc4504b`,行为代码 `1153c561`;[fv-report.md](fv-report.md) |
| 字段 / 逐帧 RSP / 结果集门 / 回调终审修复 | 已集成到 `cfca93c7`;[close-report.md](close-report.md) |
| Redmi / 跨模型族终审 | 六个 clean-boot 臂完成;审查两项 P1/P2 均真实红转绿,无未决项 |
验收代码头 `78ec3b67`,其后只补报告/注释。完整证据见
[波次 2 集成报告](wave2-report.md)、[fe 报告](fe-report.md)、[fm 报告](fm-report.md)。
- 字段归属 **41 record / 6 derived / 0 barrier / 16 fatal**。遗留指针 getter 被禁止,
消费者读 server records;8 个 whole-field refusal 保留,未用重标分类掩盖指针。
- unit **2310:2300 PASS + 10 skip**;GPU **1377:1118 PASS + 259 skip**;均零失败。
- 普通 / strict split **180:176 PASS + 4 skip**;双块 **212:206 PASS + 6 skip**。
两份 marker 棘轮为空;strict 的 Fatal / Admitted / ESCALATED 均零。
- 双后端独立逐帧 RSP 门 **2 PASS / 0 skip**;Redmi 六臂 **60 PASS / 6 既有 skip / 0 failed**,
36 个 stats windows 全部 `rsp=0`。设备 skip 仅 Magma 两个既有 clip-distance 限制各跑三臂。
- G1 `.text +0`、symbols 0/0/0/0;G2 **3016 == 3016**;G14 **3646 → 3744,+98 / -0**。
- unit **2286 条零失败**(2276 PASS、10 skip)。
- GPU **1375 条零失败**(1118 PASS、257 既有功能/驱动/专属车道 skip)。
- 普通 / strict split **179 条零失败**(175 PASS、4 skip)。strict 三类 marker 为零。
- 双块 split + magma **210 条:204 PASS、6 skip、0 failed**;Magma 部分 31 条、29 PASS。
- strict 与 dualblock 两份预期集合均已清空,双向棘轮通过;f1 机关开绿/关红实测通过。
- pull/push 构建通过;G1 `.text +0`、symbols 0/0/0/0;G2 名集合相同;G14 新增70、删除0。
## 1. 下一阶段需要知道的边界
这些结论不等于 P5f 收官:字段表仍有13个 BARRIER_PULLED 字段,静态量和反向通道尚有任务。
- Magma 仍不发布 `kCapRunAheadApply`;可达路径已经在 role-split + strict 下验证,
lockstep 没有 frontend registry/allocator 豁免。P7 buffer/native-format 等功能仍具名拒绝。
- P8 client arrays、P12 window/present 到达语义等路线图债保留;不是未完成的 P5f 包。
- server context 的 unpack/render shadow 按 native generation / served serial / role 核键。
XFB 以 lifetime id 分区;served context 切换保留暂停 span,native context 销毁才废弃旧
driver objects。不要把 P6 的 reset 设计写成“所有 reset 都清所有活对象”。
- P6 a6 要核查进程启动和配置边界。P5f 不声称已经运行两个 OS 进程。
控制帧、静态量迁移、反向回调归属已经落地,不应再列为 P6 待实现项。
## 1. 本轮关键变化
## 2. 环境与复现
fe:Espryt readback、copy、storage-block binding 改读服务端记录;Begin XFB 扩为携带
program handle / lifetime id / 四组 buffer range 的快照。make-current 只清当前绑定,保留
未结束 span,已有 context-values 记录恢复绑定身份。XFB scatter 的身份也随之转为 archive/handle。
fm:原交接“draw/dispatch 全部不可达”的结论不成立。基线 gl_VertexID 无 buffer draw 真正
通过了像素断言,因此本轮补上 server ProgramArchive / uniform / sampler / image 消费和
无应用缓冲 draw/compute。FBO、copy、mipmap、纹理 view 与 staged bytes 全走服务端记录;
独立 family caps 不再借 buffer consumer 位。带应用 buffer 的既有 P7 拒绝保留,不能假宣称已迁移。
fc:除原值帧化外,集成了 wire 序号、void 成功回复、MetalLayer 拒绝、无指针成员机械检查、
并发/重入 probe metadata 的修复。分包报告均有真实 red-once。
## 2. 已解决的集成接缝
- `PipeApply.h` 同时保留 XFB span 状态与 Magma mip 工作字段。
- CopyImageEndpoint / storage-block program 使用双方相同的 handle 定义与 sink 接线。
- `PipeApply.cpp` 同时保留 XFB reset 生存期与无 buffer ops 的纹理 staged 接收/重定义/销毁。
- 棘轮为双方退役结果的交集:fc 后6对155红 → fe 后1对2红 → fm 后0对0红。
- P8 client-array escalation 仍在自己的具名车道。strict 主车道的空表是实测结果,
不代表 P8 已实现;两条 baseline-stale 行已有 f1 独立证据并已删除。
## 3. 下一步:波次 3
按 ID-137 包边界继续;先重核本轮已改变的站点,不照 f0 旧行号重复施工。
- **fs,静态量/世代**:输入 `f0-statics.md`。`ScopedDefaultUnpackState::s_synced`、
`g_syncedRenderStateParameters` 同 tuple 而 context 换代、`XfbImpl::g_xfbObjects` 的世代。
XFB 值内的跨角色身份已随 fe 改道,仍需核静态容器。补核 f1 §8 的 `PipeInputs::IsLive`
仍读 client LiveContext,决定 server liveness 的清除点。Espryt per-draw memo 已有双键自失效。
- **fr,registry**:输入 `f0-registry.md`。原 resource_copy_region / storage-block 两项入口
已被 fe/fm 的句柄接线改动,先核剩余 scope;13站中原本11站不可达的 P3b/P4b 债不扩范围。
继续核 `GetBackendProgramId` 疑似死代码。
- **fv,反向通道**:输入 `f0-reverse-channel.md`。XFB scatter 的 program/target 身份已有
fe snapshot/archive/handle 路线,核余下边;主要仍是 RecordError 绕 callback table、
`ResourceTracker.h` 找不到 GPU-written handle 时的 client fallback。字节面不重做。
## 4. 收口门与仍保留的债
1. 双块主车道已硬绿,继续保持两份空棘轮;新增字段 marker 必须失败。
2. `FieldOwnership.def` 的13字段/17行 BARRIER_PULLED 分类与逐帧 rsp 零,仍需逐项收口。
不可把 legacy 指针 getter 改标 record-supplied 来消表。
3. Magma 不发布 `kCapRunAheadApply`,理由及不由 lockstep 掩盖缺陷的证据在 fm 报告 §4。
4. PackedFloat mipmap 的原基线功能失败保留为 `integration-magma-p7-known-red`;CI 必须
真正运行唯一用例并核对 `Magma:mipmap-native-format@P7`,不能跳过该检查。
5. G1/G2/G14、逐包 red-once 照旧。文档 strict 引用仍有两处基线 basename 歧义。
6. Redmi `2f7cbe2e` 设备门未执行。本次 adb 只见 `10AG930MXC002B3 unauthorized`。
7. ID-66 的阶段收官异模型族审查尚未做。本轮分包复审不代替它;P6 不开工。
## 5. 环境与复现
- 现有 Windows 包树 `../MobileGL-p5f-{fc,fe,fm}` 均保留;WSL 为 `~/w7/p5f-{fc,fe,fm}`。
集成验证树 `~/w7/p5f-int`,分支 `codex/p5f-wave2`。不要重建或 reset 参考树 `~/w7/pipe` / `~/w7/base`。
- 门脚本 `~/w7/notes/tools/p5f_gate.sh int <step>`;最终日志 `~/w7/p5f-logs/int-final-*`。
脚本某些步骤末尾 grep 的退出码不代表 ctest/build 状态,要核真实日志或 JUnit。
- strict / dualblock / GPU 共用私有日志,必须串行。双块旋钮为
`MOBILEGL_IPC_ROLE_SPLIT_STATE=1 MOBILEGL_IPC_STRICT_ERRORS=1`。
- Windows → WSL 使用 gitdir 的完整 `refs/heads/p5f/...` fetch,并核完整 SHA;先提交再同步。
build-pull 未跟踪目录是构建产物,勿混入提交。既有 DiligentCore 子模块 gitdir 噪音不修。
- 主 Windows 树原有 `build.gradle`、`android-plugin/app/build.gradle.kts` 两项未提交设备构建
配置与 `.trace-work/`、`Testing/` 保留;不是本轮产物,不要清理或打包提交。
- Windows 收口树 `../MobileGL-p5f-close`,分支 `codex/p5f-close`;WSL 集成树
`/home/swung/w7/p5f-int`,分支 `codex/p5f-final`。各包参考树保留,不 reset。
- 原始主机日志 `/home/swung/w7/p5f-logs/`;最终前缀 `exit-reviewed-*`。
门脚本 `/home/swung/w7/notes/tools/p5f_gate.sh int <step>`。脚本末尾 grep 不能替代
实际构建退出码或 JUnit;strict / dualblock / GPU 共用私有日志,必须串行。
- 设备最终证据 `C:/Users/geekerwan/.codex/tmp/p5f-redmi-exit-cfca93c7/`;库 hash 与
六个 boot-id 已钉在设备报告。工具已入仓 `tools/device_bench/p5f/`。
- Windows → WSL 从 Windows gitdir fetch 完整 ref;WSL → Windows 用 bundle。
不用 Linux git 直接操作含 Windows 绝对 `.git` 路径的 worktree。
- 主 Windows 树原有 `build.gradle`、`android-plugin/app/build.gradle.kts` 未提交配置,
以及 `.trace-work/`、`Testing/`,均保留,未混入 P5f。WSL `build-pull/` 为构建产物。
既有 DiligentCore 子模块 gitdir 噪音不在本次范围。
@@ -0,0 +1,109 @@
# P5f 收口报告
**状态:DONE,2026-09-20。** f0 / f1 / fc / fe / fm / fs / fr / fv 已全部集成,
字段归属、主机出口门、Redmi 设备门与跨模型族阶段审查均完成。P6 前置条件解除,
其 a6 / c6 / spawn 仍未实施。本报告取代各分包报告中的阶段中间状态。
最终行为验收头 **`cfca93c7885fd8db1e881f91189ba59090ae9c52`**(WSL `codex/p5f-final`),
包含 Windows 收口头 `c42577a4` 的全部修复;之后仅补文档与设备复现工具。
交付分支为 `feat/disaggregated`。包提交与环境入口见 [HANDOFF-P5F.md](HANDOFF-P5F.md)。
## 1. 完成的行为
波次 2 的 fc / fe / fm 已把 EGL 控制面、Espryt 对象读点、XFB Begin 快照与 Magma 可达
资源/渲染路径改成值帧、server archive / handles / staged bytes。波次 3 完成剩余边界:
- **fs**:unpack/render shadow 按 native generation、served context serial 和角色核键;
XFB server namespace 以 lifetime id 索引,包括 name 0 的 native 对象隔离。served context
切换保留仍活着的 paused span,native context 销毁清旧世代。raw-depth sampler 走纯 native
对象;server liveness 只由控制生命周期提供,verb stamp 不会复活它;双块诊断位按角色持有。
- **fr**:apply-side frontend registry / allocator 不再允许任何旧 scope 豁免;wrapper 在
选择 legacy 臂前拒绝。无调用的前端 program-name helper 从 D-P 编译中移除,pull 不变。
- **fv**:错误经保留 message 的 OnGlError 发到事件环;callback 安装/关闭/重接受和单 owner
CAS 有明确生命周期。旧 GPU-written object fallback 在解引用前拒绝,Magma transport
初始化不再构造两组隐藏 frontend 资源。四个 callback 统一投递实际 active session。
字段机器表最终为 **41 RECORD_SUPPLIED / 6 APPLIER_DERIVED / 0 BARRIER_PULLED / 16 FATAL**。
带 client 指针的旧 getter 为 FATAL;消费者直接读取 server records,没有把句柄记录谎称为
“供给整个旧指针字段”。`EmittedCallSuppliesTheWholeField` 的 8 个拒绝保留。
生成器拒绝任何 production BARRIER_PULLED 行,历史 debt 仅在 synthetic admission fixture
中测试。即使伪造 fresh stamp,FATAL getter 也必须拒绝;sticky forwards 同样执行归属。
新 `EachWireFrameHasZeroResidualPulls` 在两后端各注册独立 RSP 车道:连续三个改变 uniform
的帧逐个断言像素、真实 applied verbs 和 `rsp=0`。Magma 的 draws stat 尚未实现,绘制证据
取实际变化的像素,未以缺少 draws 计数假称执行过 draw。
## 2. 七项出口门
| 出口 | 最终结果 |
|---|---|
| 1 双块车道 | **212:206 PASS / 6 既有 skip / 0 failed**;两后端,同一归属与拒绝机制 |
| 2 strict / 棘轮 | ordinary / strict split **180:176 PASS / 4 skip / 0 failed**;Fatal、普通 Admitted、ESCALATED 均零;strict 与 dualblock 两份 expected 文件为空 |
| 3 字段 / 逐帧 RSP | production **0 BARRIER_PULLED**;`integration-p5f-rsp` **2 PASS / 0 skip**;设备 36 windows 全零 |
| 4 两后端能力声明 | GLES run-ahead ARMED;Magma 明确不发布 capability、运行 lockstep;理由如下,无 frontend 豁免 |
| 5 G1 / G2 / G14 | pull `.text` **10806051 → 10806051**,defined symbols **27815 → 27815**,added/removed/resized/renamed **0/0/0/0**,data/bss/rodata 不变;pull/push CTest **3016 == 3016**;f1 名集合 **3646 → 3744,+98 / -0**,无重复名 |
| 6 red-once | 逐包控制均真红后还原绿;f1 双块 knob=1 绿 / knob=0 真断言红;fresh FATAL、结果集完整性、非 singleton callback 修复均各有真实红转绿 |
| 7 Redmi | 指定 `2f7cbe2e`,六个不同 boot-id,同一最终库,两后端 role0/role1 clean-boot 配对及 monolith sanity;**60 PASS / 6 skip / 0 failed** |
Magma 不发布 run-ahead 的原因仍是 P7 buffer/native-format 功能边界,以及 wire render-pass
提交后等待 GPU 再退休对象的现有生命周期/性能契约。role-split 下 server 块没有 client
指针,lockstep 不能掩盖这种读;registry/allocator guard 对 barriered 记录同样拒绝。
fs/fv/字段收口已经完成,不再用这些已解决事项作为不发布 capability 的理由。
## 3. 主机完整验证与门的可信性
| 检查 | 结果 |
|---|---|
| split / pull / push 构建 | 全部通过 |
| unit | **2310:2300 PASS / 10 既有 skip / 0 failed** |
| GPU(审查修复后的最终代码) | **1377:1118 PASS / 259 既有功能、驱动、专属车道 skip / 0 failed** |
| field generator | check 通过;**19 个 negative controls + 13 个 synthetic admission controls** |
| pipe / dirty-surface / include closure | check 与现有 self-test 通过;include closure 4 probes、0 skipped / 0 problems |
| 文档引用 | 两处旧 basename 歧义改为完整路径,strict 检查通过 |
双块 gate 不只检查“空观测集合等于空预期集合”:必须有非空 discovery,JUnit 与发现集合
完整且一一对应,missing / extra / duplicate / notrun / disabled 均失败;绿和 skip 条目也
扫描 marker,GLES/Magma 私有日志均核所有权。CI 空 expected 表要求 ctest rc=0。
六个允许 skip 按**确切名称和原因**锁定:四个专属计数车道的 sibling,两个 Magma clip
功能限制。任何额外 skip 都失败;RSP 另有不可 skip 的双后端独立门。
P7 已知红 `integration-magma-p7-known-red` 真实执行唯一用例,**1 failed / 0 skip**,
退出码 8,具名 `Fatal{UnmigratedVerb, "Magma:mipmap-native-format@P7"}`。
这是保留的功能边界,不计入 PASS。旧 readback fixture 也已补完整 FBO/pack/context/sampler
records,在无 residual fill 时通过,`DstSize=80` / tight reply `48` 断言未放松。
## 4. 阶段审查与设备
跨模型族审查通过只读 Claude Code 完成,结果记录 `claude-opus-5[1m]` /
`claude-haiku-4-5`,实现方为 GPT 系列。发现 P1 结果集可不完整、P2 三个 callback 投错
singleton,均已修复并真跑红转绿;没有遗留本次审查 P0/P1/P2。详情、原文及局限见
[close-review.md](close-review.md)。
最终库 SHA256 `764a790d024fbe1b83ebdec5d896cc77ecda4f4a2698d63d2b2d16239f40e74c`,
六臂都核主机/设备 hash 一致。GLES 每臂 11 PASS;Magma 每臂 9 PASS + 两个既有
per-distance clip-enable skip。全部 36 个 stats windows `rsp=0`;两 inproc GLES 臂各
`vbs=72`,Magma 各 `vbs=68`,monolith 为 0。实际 backend、strict/role 和 capability
日志均核对,不以环境回显代替运行证据。
设备 runner 使用公开 GL/EGL、AImageReader native window:clip distance 3 项、layered copy
6 项、mipmap 2 项。没有把 host 私有 F1/Ct/DualBlock 测试冒称 Android 覆盖。
suite 时间只记录一次 clean-boot 样本,不作为 MC/FPS 性能结论;数值与全部 boot-id 见
[device-report.md](device-report.md)。复现工具位于 `tools/device_bench/p5f/`。
## 5. 证据索引与边界
主机证据根 `/home/swung/w7/p5f-logs/`:
- `exit-reviewed-{unit,gpu}.log/xml`:审查修复后的完整主机结果。
- `exit-reviewed-{strict,dualblock,negctl}-gate.log`:最终 marker、双块与机关控制。
- `exit-reviewed-g1.log`、`exit-reviewed-name-gates.log`:二进制与测试名门。
- `exit-rsp.log/xml`、`exit-rsp-lane.json`:双后端逐帧 RSP;`exit-known-red.log/xml`:P7 拒绝。
- `close-fresh-{red,green}.log`、`exit-review-gate-{red-once,green}.log`、`fv-review-*.log`:收口修复控制。
- 各分包报告列出该包独立门与 red-once;中间计数不替代本文最终计数。
设备证据 `C:/Users/geekerwan/.codex/tmp/p5f-redmi-exit-cfca93c7/`;审查原始结果
`C:/Users/geekerwan/.codex/tmp/p5f-final-review-de78f47d/result.json`。
P7 的 Magma buffer/native-format 等功能、P8 client arrays、P12 window/present 到达,
以及 P5e 历史 E1 对照设计条目继续按其原阶段跟踪。它们保留具名边界,不是未完成的 P5f。
本次不启动 P6,也不宣称两进程 spawn 已实现。
@@ -0,0 +1,78 @@
# P5f 阶段末跨模型族审查
实现方为 GPT 系列;审查通过本机 Claude Code 只读 CLI 执行,限定 Read/Glob/Grep、无 MCP,
没有修改文件或运行 shell。审查头 `de78f47d`,基线 `e75e00cb`。CLI 成功返回;模型记录含
`claude-opus-5[1m]` 与 `claude-haiku-4-5`,与实现方错开模型族。原始结果保存在
`C:/Users/geekerwan/.codex/tmp/p5f-final-review-de78f47d/result.json`。
## 原始审查结果
## 审查发现
### P1 — 最终 dual-block“硬绿”门可在测试未完整执行时伪绿
- **位置**
- `.github/workflows/test.yml:1387-1400`
- `MobileGL/MG_IntegrationTest/Harness/split_log_paths.py:138-160`
- `MobileGL/MG_IntegrationTest/CMakeLists.txt:2580-2601`
- `MobileGL/MG_IntegrationTest/Scenarios/F1WireScenario.cpp:99-103`
- **触发条件**
1. 当前 `dualblock-expected-fatals.txt` 为空;
2. `ctest` 因空选择、提前中断或基础设施错误返回非零;或者新加的某个 `DirectGLES/DirectVulkan.Split.P5fRsp.*` 用例因环境标记或 split runtime 不满足而 skip/未出现在 JUnit 中。
- **失败路径**
- workflow 用 `|| rc=$?` 吞掉 `ctest` 的非零状态;
- 随后仅在“`rc == 0` 且预期表非空”时失败。当前预期表为空,因此任何非零 `rc` 都不会直接使步骤失败;
- `expect_fatal()` 只遍历 JUnit 中实际出现的 testcase,不把 `dualblock-lane.json` 的发现集合与 JUnit 集合比较;skip 被直接计数后忽略,缺失用例也完全不可见;
- 最终空观测集合与空预期集合相等,helper 返回成功。
- 因而阶段出口要求的双后端逐帧 `rsp=0` 用例可以没有实际执行,步骤仍打印硬绿。
- **最小修复建议**
1. 当前阶段预期表为空时,无条件要求 `rc == 0`;
2. 在 `expect_fatal()` 中比较 JSON 发现集合与 JUnit 集合,拒绝 missing、notrun、disabled;硬绿模式还应拒绝所有 skip;
3. 对 `integration-p5f-rsp` 增加独立核验:必须恰好执行 DirectGLES、DirectVulkan 两条,`2 PASS / 0 skip / 0 failed`。
### P2 — 三个反向回调没有投递给实际取得所有权的 `ServerSession`
- **位置**
- `MobileGL/MG_Remote/Server/ServerSession.cpp:264-315`
- 对照正确的错误回调:`MobileGL/MG_Remote/Server/ServerSession.cpp:332-340`
- active owner 发布点:`MobileGL/MG_Remote/Server/ServerSession.cpp:567-573`
- **触发条件**
- 首个成功 `Accept()` 的对象不是 `ServerSessionInstance()`,而是另一个合法的 `ServerSession` 实例;
- 之后后端调用 `OnBufferWriteback`、`OnGpuWritten` 或 `OnSurfaceChanged`。
- **失败路径**
- `Accept()` 将实际 owner 发布到 `g_active`,并把全局回调表安装为该 session 的生产者;
- 但三个生产函数仍硬编码调用 `ServerSessionInstance()`,而不是 `ServerSession::Active()`;
- 事件因此写向未接受连接的 singleton,而非拥有 SEG_EVENT 的 session,通常在无效 event producer 上落入 `Fatal{EventRingOverflow}`;即使 singleton 状态发生变化,也会投递到错误 session。
- `ServerOnGlError()` 已正确通过 `Active()` 解析 owner,四个回调的所有权语义目前不一致。`g_sessionOwner` 对任意 `ServerSession*` 做 CAS,也说明所有权并未限定为 singleton。
- **最小修复建议**
- 让三个生产函数与 `ServerOnGlError()` 一样解析 `ServerSession::Active()`;没有 active owner 时给出具名 `RoleViolation`;
- 增加一个“非 singleton session 首先 Accept,四种回调均进入其 event ring”的测试。
## 审查局限
本次严格保持只读,仅使用 `Read/Glob/Grep`;未运行构建、测试或设备门。因此未评价当前 pending validation 的通过与否,也未将其视为代码缺陷。除此之外,在指定的跨角色访问、上下文/XFB/raw sampler 生命周期、控制帧保真及 Magma record/resource 路径中,未发现其他具有充分代码依据的 P0/P1/P2 问题。
## 处置(均已完成)
1. **P1,结果集不完整可伪绿**:`c42577a4` 给空表要求 ctest rc=0;对 JSON 发现全集与
JUnit 做非空、完整、一一对应核验;拒绝 missing/extra/duplicate/notrun/disabled。
对已执行的 green/skip 也扫描 marker,而非仅扫描 failed 条目。GLES 与 Magma 私有日志
所有权同样校验。新增独立 `integration-p5f-rsp` 硬门,必须恰两后端 2 PASS / 0 skip。
仅保留既有六个 skip,严格匹配名称和原因;不采用“所有 skip 都拒绝”,因为四个是专属
计数车道的普通/SmallRing sibling,另两个是已有 Magma clip-feature 限制。其他 skip 均红。
9 个结果核对回归测试全绿;旧 helper 对“缺一个 JUnit 条目”没有拒绝,控制真实失败为
`ValueError not raised`,新 helper 通过。日志 `exit-review-gate-{red-once,green}.log`。
2. **P2,非 singleton callback owner**:`53699b5a` 让四种 producer 统一取 `Active()`,
无 active owner 时均具名 RoleViolation。新增非 singleton 首先 Accept 后四事件落入其
ring 的生产测试,以及 Close 后缓存的四 callback 不可再投递测试。旧版真实 abort 于
`kEventGpuWritten` 的 `EventRingOverflow`,修复后 11 项反向通道测试全绿;原 readback
fixture 与握手也通过。日志 `fv-review-*.log`。
两项均有实际红转绿证据,未把审查建议当作验证结果。修复后的最终 Android 库也重新部署,
六个 clean-boot 臂全部重新运行。没有留待 P6 的本次审查 P0/P1/P2 项。
@@ -0,0 +1,64 @@
# P5f Redmi 设备门
2026-09-20,指定序列号 `2f7cbe2e`,Xiaomi `M332BF` / Android 16 / SM8750。
验证库源头 **`cfca93c7885fd8db1e881f91189ba59090ae9c52`**,包含跨模型审查的两项修复。
每臂先 reboot,等待 boot complete;六个 boot-id 不同。没有 pin 时钟、清 app 数据、安装 APK
或修改 FCL 设置。测试是独立 shell ELF + AImageReader native window,真实硬件 GPU。
P5F §6.7 的 A/B 取本阶段中心机制:同一 split binary、inproc、strict=1、role0/role1。
额外单体 sanity 也使用同一 binary。P5e 的 MC 30秒/FPS性能阈值没有被移植成 P5f 新要求;
这里的性能只记录,不宣称游戏性能改善或完整 P7 工作负载已支持。
## 身份与结果
NDK 27.3、API26、arm64、RelWithDebInfo;仅在部署副本去掉 debug 数据,原始符号保留。
三份 ELF 的设备 hash 与主机逐项一致:
- `libMobileGL.so`: `764a790d024fbe1b83ebdec5d896cc77ecda4f4a2698d63d2b2d16239f40e74c`
- `P5fDevicePixels`: `76c81e540f723782141054ecc6e99b6a92fff1a55f413d63796ff53e630cec0b`
- `libc++_shared.so`: `d523468d62d9b603cb3354294d70d4b2feabf2c3f1e43b0c96c9aabf32813708`
| 臂 | PASS | skip | vbs 合计 | stats windows | suite 秒(仅记录) | boot-id |
|---|---:|---:|---:|---:|---:|---|
| GLES-monolith | 11 | 0 | 0 | 6 | 0.518 | `9497f21b-f91f-4d95-a403-5729eb537d5f` |
| GLES-role0 | 11 | 0 | 72 | 6 | 0.741 | `02acddae-f9f8-4fff-bfed-bf1ac03ea0b2` |
| GLES-role1 | 11 | 0 | 72 | 6 | 0.314 | `17f16009-86dd-49c4-9da5-bc3bf377e827` |
| Magma-monolith | 9 | 2 | 0 | 6 | 0.259 | `db46e8b0-b74e-4c3f-a97f-a38c373fa2a9` |
| Magma-role1 | 9 | 2 | 68 | 6 | 0.369 | `8d0672c7-bfb1-45d9-8436-764a074a1087` |
| Magma-role0 | 9 | 2 | 68 | 6 | 0.543 | `bfd92cb2-7854-4e54-99ad-de911660ab5e` |
**所有六臂 failed=0,36个统计窗口全部 rsp=0**。GLES 的两 inproc 臂 vbs 同为72,Magma
同为68;单体 vbs=0。运行日志也核了实际 backend、inproc strict/role配置、Espryt run-ahead
ARMED 与 Magma 不发布能力而 lockstep 的明确记录,不能只用环境回显当跑对臂的证据。
Magma 每臂两项 skip 是同一组既有功能限制:
`ClipDistanceScenario.ADisabledClipDistanceRemovesNothing` 与
`ClipDistanceScenario.TheEnablesAreIndependentPerDistance`。程序在像素观察后明确报出
“不实现 per-distance enable masking”的原因;单体、role0、role1一致,不是 preflight/GPU
不可用,也没有计为 PASS。其余9项必须真正通过。GLES 的11项全部真正通过。
## 覆盖与局限
公开 GL 用例为 ClipDistance 三项、CopyImageLayered 六项,以及独立 public mipmap 两项:
CPU红底生成 mip 链;先GPU写绿后生成链且不得被旧CPU红影子覆盖。全部 mip/base 都核像素。
Android 原有 CMake 提前 return,F1/Ct/DualBlock 与私有 peek 不进入 Android binary,因此本次
没有冒称那些 host 私有用例在手机执行,也没有添加 shipping export ABI。
运行时间含测试初始化/驱动缓存影响,只有一次 clean-boot 样本,不能据此推导性能回归或提升。
已保留 P7 buffer/native-format、P8 client arrays、P12窗口到达等具名边界;它们不属于本门
选择的可执行子集。
## 复现与证据
可复用工具已入仓 `tools/device_bench/p5f/`,包含构建/运行/验证脚本及独立 public mipmap 源。
入仓 verifier 核对确切的 11 个唯一用例及每条 `status=run`、`result=completed/skipped`,
已只读复核全部六臂。复制证据的 missing / duplicate / disabled 三个反例均在对应断言拒绝;
原证据文件 hash 前后不变,控制结果保存在
`C:/Users/geekerwan/.codex/tmp/p5f-verify-arm-controls-7nrrujzt/`。两个 shell 脚本的
`bash -n` 与 Python 语法检查也通过。
原始六臂证据:`C:/Users/geekerwan/.codex/tmp/p5f-redmi-exit-cfca93c7/`,每臂有 XML、stdout、
库日志、boot-id、设备/主机SHA256、退出码及 crash-buffer;`summary.json` 汇总上表。
最终 bundle:`/home/swung/w7/p5f-android-cfca93c7885f/bundle`。
Android增量构建复用先前 cache,完整库与符号在
`/home/swung/w7/p5f-android-de78f47df595/library`;其最后 reconfigure/build 对应最终源头。
审查修复前的 de78 预跑证据另存,未混入上表、未代替最终库的六臂复跑。
@@ -88,4 +88,3 @@ frontend program;相应两个 shutdown scope 不能当作不可达依据。已
Linux 新树的子模块递归初始化遇到本地缺少 apitrace nested commit,随后复用了现有
`p5f-int` 的依赖与 fixture 文件;未运行 `git lfs pull/checkout`,未修改参考树。
+28
View File
@@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.24)
project(P5fDevicePixels LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
foreach(required MOBILEGL_SOURCE MOBILEGL_LIBRARY GTEST_SOURCE)
if(NOT DEFINED ${required})
message(FATAL_ERROR "Set -D${required}=...")
endif()
endforeach()
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
set(BUILD_GMOCK OFF CACHE BOOL "" FORCE)
add_subdirectory("${GTEST_SOURCE}" googletest EXCLUDE_FROM_ALL)
add_library(DeviceMobileGL SHARED IMPORTED)
set_target_properties(DeviceMobileGL PROPERTIES IMPORTED_LOCATION "${MOBILEGL_LIBRARY}")
set(itest "${MOBILEGL_SOURCE}/MobileGL/MG_IntegrationTest")
add_executable(P5fDevicePixels
"${itest}/Main.cpp"
"${itest}/Harness/HeadlessGL.cpp"
"${itest}/Harness/SplitRuntimePeek.cpp"
"${itest}/Scenarios/ClipDistanceScenario.cpp"
"${itest}/Scenarios/CopyImageLayeredScenario.cpp"
P5fPublicMipmapScenario.cpp)
target_include_directories(P5fDevicePixels PRIVATE
"${MOBILEGL_SOURCE}/include" "${MOBILEGL_SOURCE}/MobileGL" "${itest}")
target_link_libraries(P5fDevicePixels PRIVATE DeviceMobileGL GTest::gtest)
if(ANDROID)
target_link_libraries(P5fDevicePixels PRIVATE android log mediandk)
endif()
@@ -0,0 +1,62 @@
// Device-only P5f preparation. Public GL calls, no MobileGL internal symbols.
#include "Harness/ScenarioFixture.h"
#include <array>
#ifdef GLAPI
#undef GLAPI
#endif
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glcorearb.h>
#undef GL_GLEXT_PROTOTYPES
namespace MGITest {
class P5fPublicMipmapScenario : public ScenarioTest {
protected:
void Check(bool gpuWritten) {
if (!Ready()) return;
GLuint texture = 0, fbo = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
std::array<GLubyte, 4 * 4 * 4> red{};
for (std::size_t i = 0; i < red.size(); i += 4) {
red[i] = 255;
red[i + 3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, red.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
if (gpuWritten) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GLenum{GL_FRAMEBUFFER_COMPLETE});
glDisable(GL_SCISSOR_TEST);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
glGenerateMipmap(GL_TEXTURE_2D);
for (GLint level = 0; level <= 2; ++level) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, level);
ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GLenum{GL_FRAMEBUFFER_COMPLETE}) << level;
std::array<GLubyte, 4> pixel{71, 72, 73, 74};
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel.data());
EXPECT_EQ(pixel[0], gpuWritten ? 0 : 255) << "mip=" << level;
EXPECT_EQ(pixel[1], gpuWritten ? 255 : 0) << "mip=" << level;
EXPECT_EQ(pixel[2], 0) << "mip=" << level;
EXPECT_EQ(pixel[3], 255) << "mip=" << level;
}
EXPECT_EQ(glGetError(), GLenum{GL_NO_ERROR});
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteFramebuffers(1, &fbo);
glDeleteTextures(1, &texture);
Gl().EndFrame();
}
};
TEST_F(P5fPublicMipmapScenario, UploadedRgba8BaseGeneratesRedMipChain) { Check(false); }
TEST_F(P5fPublicMipmapScenario, GpuWrittenBaseGeneratesGreenMipChainWithoutStaleCpuUpload) { Check(true); }
} // namespace MGITest
+26
View File
@@ -0,0 +1,26 @@
# P5f Android public-pixel gate
Build `bash build_android.sh <Linux-source-tree> <full-source-SHA>` with NDK 27.3/API26/arm64.
This produces one disaggregated/PUSH library and a runner using only public GL/EGL APIs.
Original symbols stay in `library/` and `pixels/`; bundle copies have only debug data stripped.
No FCL/APK configuration or private diagnostic export is required.
The coordinator reboots Redmi `2f7cbe2e` before each arm and waits for `sys.boot_completed=1`.
Run `run_pixel_arm.sh <bundle> <new-output-dir> <DirectGLES|DirectVulkan> <monolith|inproc> <0|1>`
from Windows Git Bash; the script itself never reboots. Set `ADB_BIN` if the Windows adb path differs.
Then run `python3 verify_arm.py <output-dir>`.
Arms: GLES monolith, GLES inproc role0/role1; Magma monolith, Magma inproc role1/role0.
All use the same bundle. Check six distinct boot IDs and equal host/device hashes.
Performance is recorded only; this short pixel suite is not an MC/FPS benchmark.
11 selected cases cover clip distance, six layered image copies and two mipmap cases.
The verifier requires the exact case set with no missing, extra, duplicate or unexecuted entries.
It allows only Magma's two pre-existing per-distance-enable limitations, matched by
exact case and skip reason. They are never counted as passes and must be identical across arms.
Every other skip/failure is an error. Every actual stats window must have `rsp=0`; inproc must
publish `vbs>0` and correct runtime/capability logs, monolith must keep `vbs=0`.
Android's normal integration target omits F1/Ct/DualBlock and private peek bridges. This runner
therefore does not claim those host cases ran on Android. See `device-report.md` in the P5f notes
for the completed six-arm run and immutable artifact hashes.
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
# Build only. No adb or device operation. Run after the final integrated SHA exists.
# Usage: bash build_android.sh /home/swung/w7/p5f-int <full-final-sha>
set -euo pipefail
TREE=$(realpath "${1:?source tree}")
HEAD_SHA=${2:?full final SHA}
[[ $HEAD_SHA =~ ^[0-9a-f]{40}$ ]] || exit 64
[[ $(git -C "$TREE" rev-parse HEAD) == "$HEAD_SHA" ]] || { echo 'source head mismatch'; exit 65; }
git -C "$TREE" diff --quiet --ignore-submodules=all HEAD -- MobileGL CMakeLists.txt
PREP=$(cd "$(dirname "$0")" && pwd)
OUT="$HOME/w7/p5f-android-${HEAD_SHA:0:12}"
NDK="$HOME/android-sdk/ndk/27.3.13750724"
GTEST="$TREE/build-split/_deps/googletest-src"
[[ -f "$GTEST/CMakeLists.txt" && -f "$NDK/build/cmake/android.toolchain.cmake" ]] || exit 66
mkdir -p "$OUT"
COMMON=(-G Ninja "-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake"
-DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-26 -DANDROID_STL=c++_shared
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_POLICY_VERSION_MINIMUM=3.5
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON)
cmake -S "$TREE" -B "$OUT/library" "${COMMON[@]}" \
-DMOBILEGL_BUILD_TEST=OFF -DMOBILEGL_BUILD_BENCHMARK=OFF \
-DMOBILEGL_BUILD_INTEGRATION_TEST=OFF -DMOBILEGL_BUILD_DISAGGREGATED=ON \
-DMOBILEGL_BUILD_DISAGGREGATED_INPROC=ON -DMOBILEGL_PIPE_PUSH=ON \
-DMOBILEGL_LOG_ACTIVE_LEVEL=MOBILEGL_LOG_LEVEL_INFO > "$OUT/configure-library.log" 2>&1
grep -q -- '-DMOBILEGL_BUILD_DISAGGREGATED=1' "$OUT/library/compile_commands.json"
grep -q -- '-DMOBILEGL_PIPE_PUSH=1' "$OUT/library/compile_commands.json"
cmake --build "$OUT/library" --target MobileGL -j "${P5F_ANDROID_JOBS:-4}" > "$OUT/build-library.log" 2>&1
cmake -S "$PREP" -B "$OUT/pixels" "${COMMON[@]}" \
"-DMOBILEGL_SOURCE=$TREE" "-DMOBILEGL_LIBRARY=$OUT/library/libMobileGL.so" \
"-DGTEST_SOURCE=$GTEST" > "$OUT/configure-pixels.log" 2>&1
cmake --build "$OUT/pixels" --target P5fDevicePixels -j "${P5F_ANDROID_JOBS:-4}" > "$OUT/build-pixels.log" 2>&1
mkdir -p "$OUT/bundle"
cp "$OUT/library/libMobileGL.so" "$OUT/pixels/P5fDevicePixels" "$OUT/bundle/"
cp "$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so" "$OUT/bundle/"
# Keep unstripped originals in library/pixels; deploy only a debug-stripped copy.
"$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip" --strip-debug \
"$OUT/bundle/libMobileGL.so" "$OUT/bundle/P5fDevicePixels"
printf '%s\n' "$HEAD_SHA" > "$OUT/bundle/source-head.txt"
file "$OUT/bundle/P5fDevicePixels" "$OUT/bundle/libMobileGL.so" > "$OUT/bundle/elf-identity.txt"
(cd "$OUT/bundle" && sha256sum ./*.so ./P5fDevicePixels > sha256.txt)
echo "Prepared $OUT/bundle (not deployed)"
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Windows Git Bash. Root coordinator runs this only AFTER its own clean reboot.
# Does not reboot, install an APK, alter clocks, clear logcat, or launch FCL.
# Usage: bash run_pixel_arm.sh <bundle-dir> <new-output-dir> DirectGLES|DirectVulkan inproc|monolith 0|1
set -euo pipefail
export MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*'
BUNDLE=${1:?bundle}; OUT=${2:?new output}; BACKEND=${3:?backend}; TRANSPORT=${4:?transport}; ROLE=${5:?role}
[[ $BACKEND == DirectGLES || $BACKEND == DirectVulkan ]] || exit 64
[[ $TRANSPORT == inproc || $TRANSPORT == monolith ]] || exit 64
[[ $ROLE == 0 || $ROLE == 1 ]] || exit 64
[[ ! -e $OUT ]] || { echo 'Output exists; do not overwrite an arm'; exit 65; }
HEAD_SHA=$(tr -d '\r\n' < "$BUNDLE/source-head.txt")
[[ $HEAD_SHA =~ ^[0-9a-f]{40}$ ]] || exit 66
(cd "$BUNDLE" && sha256sum -c sha256.txt)
ADB_BIN=${ADB_BIN:-/c/Users/geekerwan/AppData/Local/Android/Sdk/platform-tools/adb.exe}
A=("$ADB_BIN" -s 2f7cbe2e)
[[ $("${A[@]}" get-state | tr -d '\r') == device ]] || exit 67
mkdir -p "$OUT"
cp "$BUNDLE/source-head.txt" "$BUNDLE/sha256.txt" "$OUT/"
"${A[@]}" shell cat /proc/sys/kernel/random/boot_id > "$OUT/boot-id.txt"
REMOTE=/data/local/tmp/p5f-${HEAD_SHA:0:12}
TAG=$BACKEND-$TRANSPORT-r$ROLE-$(date +%s)
"${A[@]}" shell "mkdir -p $REMOTE"
for f in libMobileGL.so libc++_shared.so P5fDevicePixels; do
"${A[@]}" push "$BUNDLE/$f" "$REMOTE/$f" > "$OUT/push-$f.log" 2>&1
done
"${A[@]}" shell "chmod 755 $REMOTE/P5fDevicePixels; cd $REMOTE; sha256sum libMobileGL.so libc++_shared.so P5fDevicePixels" > "$OUT/device-sha256.txt"
FILTER='ClipDistanceScenario.AnEnabledClipDistanceRemovesTheNegativeHalf:ClipDistanceScenario.ADisabledClipDistanceRemovesNothing:ClipDistanceScenario.TheEnablesAreIndependentPerDistance:CopyImageLayeredScenario.*:P5fPublicMipmapScenario.*'
printf '%s\n' "backend=$BACKEND transport=$TRANSPORT role=$ROLE" > "$OUT/arm.txt"
rc=0
"${A[@]}" shell "cd $REMOTE; env LD_LIBRARY_PATH=$REMOTE MOBILEGL_BACKEND_TYPE=$BACKEND MOBILEGL_TRANSPORT=$TRANSPORT MOBILEGL_IPC_ROLE_SPLIT_STATE=$ROLE MOBILEGL_IPC_STRICT_ERRORS=1 MOBILEGL_IPC_RUN_AHEAD=1 MOBILEGL_IPC_STAGE_MB=256 MOBILEGL_ITEST_REQUIRE_GPU=1 MOBILEGL_ITEST_REQUIRE_HARDWARE_GPU=1 MOBILEGL_PIPE_STATS=1 MOBILEGL_PIPE_STATS_PERIOD=1 MOBILEGL_LOG_FILE_PATH=$REMOTE/$TAG.library.log ./P5fDevicePixels --gtest_filter='$FILTER' --gtest_output=xml:$REMOTE/$TAG.xml >$REMOTE/$TAG.stdout.txt 2>&1" || rc=$?
printf '%s\n' "$rc" > "$OUT/process-exit.txt"
for f in library.log xml stdout.txt; do
"${A[@]}" pull "$REMOTE/$TAG.$f" "$OUT/$f" > "$OUT/pull-$f.log" 2>&1 || true
done
"${A[@]}" logcat -d -b crash -v time > "$OUT/crash-buffer.txt"
echo "Arm completed with process rc=$rc. Verify XML, library log, boot id, and hashes in $OUT."
exit "$rc"
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env python3
"""Read-only verdict for the prepared public-pixel arm; never invokes adb."""
import pathlib
import re
import sys
import xml.etree.ElementTree as ET
d = pathlib.Path(sys.argv[1])
def hashes(path):
return {name.removeprefix('./'): digest for digest, name in
(line.split(maxsplit=1) for line in path.read_text().splitlines() if line.strip())}
assert hashes(d / 'sha256.txt') == hashes(d / 'device-sha256.txt'), 'host/device artifact hash mismatch'
arm = dict(re.findall(r'(backend|transport|role)=(\S+)', (d / 'arm.txt').read_text()))
assert (d / 'process-exit.txt').read_text().strip() == '0', 'process failed'
cases = ET.parse(d / 'xml').getroot().findall('.//testcase')
expected_cases = {
'ClipDistanceScenario.AnEnabledClipDistanceRemovesTheNegativeHalf',
'ClipDistanceScenario.ADisabledClipDistanceRemovesNothing',
'ClipDistanceScenario.TheEnablesAreIndependentPerDistance',
'CopyImageLayeredScenario.ArrayToArrayCopiesEverySlice',
'CopyImageLayeredScenario.ArrayToArrayHonoursDifferentLayerOffsets',
'CopyImageLayeredScenario.VolumeToVolumeHonoursNonZeroZ',
'CopyImageLayeredScenario.VolumeToVolumeAtNonZeroMipLevel',
'CopyImageLayeredScenario.ArrayToVolumeCopiesEverySlice',
'CopyImageLayeredScenario.VolumeToArrayCopiesEverySlice',
'P5fPublicMipmapScenario.UploadedRgba8BaseGeneratesRedMipChain',
'P5fPublicMipmapScenario.GpuWrittenBaseGeneratesGreenMipChainWithoutStaleCpuUpload',
}
case_names = [c.get('classname', '') + '.' + c.get('name', '') for c in cases]
assert len(cases) == len(expected_cases), f'expected 11 selected cases, got {len(cases)}'
assert len(case_names) == len(set(case_names)), ('duplicate test cases', case_names)
assert set(case_names) == expected_cases, (
'selected case set mismatch',
{'missing': sorted(expected_cases - set(case_names)),
'extra': sorted(set(case_names) - expected_cases)})
# The two pre-existing Vulkan per-distance-enable limitations are explicit,
# matched by exact case and reason, and never counted as executed passes.
allowed_skips = {
'ClipDistanceScenario.ADisabledClipDistanceRemovesNothing': 'clips by a DISABLED gl_ClipDistance',
'ClipDistanceScenario.TheEnablesAreIndependentPerDistance': 'clips by every declared gl_ClipDistance regardless of the enables',
} if arm['backend'] == 'DirectVulkan' else {}
skipped = []
for c in cases:
name = c.get('classname', '') + '.' + c.get('name', '')
assert c.get('status') == 'run', ('case did not execute', name, c.attrib)
assert c.find('failure') is None and c.find('error') is None, c.attrib
skip = c.find('skipped')
if skip is not None:
assert c.get('result') == 'skipped', ('invalid executed-skip result', name, c.attrib)
text = ' '.join(skip.itertext()) + ' ' + skip.get('message', '')
assert name in allowed_skips and allowed_skips[name] in text, ('unexpected skip', c.attrib, text)
skipped.append(name)
else:
assert c.get('result') == 'completed', ('case did not complete', name, c.attrib)
stdout = (d / 'stdout.txt').read_text(errors='replace')
log = (d / 'library.log').read_text(errors='replace')
assert f'backend={arm["backend"]}' in stdout
assert 'AImageReader window' in stdout, 'not the Android window harness'
assert not re.search(r'Fatal\{|SIGSEGV|SIGABRT|AddressSanitizer', stdout + log)
stats = [line for line in log.splitlines() if 'MGPipe stats:' in line and re.search(r'\bframes=\d+', line)]
assert stats, 'no actual stats windows'
assert all(re.search(r'\brsp=0(?:\s|$)', line) for line in stats), 'nonzero/missing rsp'
assert any(int(re.search(r'\bframes=(\d+)', line)[1]) > 0 for line in stats), 'no present frames'
vbs = [int(re.search(r'\bvbs=(\d+)', line)[1]) for line in stats]
if arm['transport'] == 'inproc':
assert any(v > 0 for v in vbs), 'no applied verb boundaries; transport not proven'
assert re.search(r'Config: IPC .*strict=1 .*role-split-state=' + arm['role'] + r'\b', log)
expected = 'run-ahead ARMED' if arm['backend'] == 'DirectGLES' else 'run-ahead requested, server does not publish'
assert expected in log, 'missing runtime capability evidence'
else:
assert all(v == 0 for v in vbs), 'monolith control has applied verb boundaries'
print(f'PASS {arm}: {len(cases)-len(skipped)} passed, {len(skipped)} named legacy feature skips, {len(stats)} stats windows, rsp=0, vbs={sum(vbs)}')
for name in skipped: print(' preserved limitation:', name)