From 1e7de1edd664de99dc0b118c9c59561336a1a32e Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 20 Sep 2026 01:35:14 -0400 Subject: [PATCH] [docs, tools] (Disaggregated): P5f close - record final host device and review evidence --- MobileGL/MG_Remote/CONTRACT-P5.md | 4 +- docs/Disaggregated/CURRENT_STAGE_PROGRESS.md | 82 ++++++++--- docs/Disaggregated/P5F-WIRE-COMPLETENESS.md | 43 +++--- docs/Disaggregated/P6-CONTRACT-DRAFT.md | 66 ++++++--- docs/Disaggregated/P6-SPAWN-PLAN.md | 32 ++--- docs/Disaggregated/ROADMAP.md | 27 ++-- docs/Disaggregated/notes/p5f/HANDOFF-P5F.md | 131 +++++++----------- docs/Disaggregated/notes/p5f/close-report.md | 109 +++++++++++++++ docs/Disaggregated/notes/p5f/close-review.md | 78 +++++++++++ docs/Disaggregated/notes/p5f/device-report.md | 64 +++++++++ docs/Disaggregated/notes/p5f/fr-report.md | 1 - tools/device_bench/p5f/CMakeLists.txt | 28 ++++ .../p5f/P5fPublicMipmapScenario.cpp | 62 +++++++++ tools/device_bench/p5f/README.md | 26 ++++ tools/device_bench/p5f/build_android.sh | 41 ++++++ tools/device_bench/p5f/run_pixel_arm.sh | 38 +++++ tools/device_bench/p5f/verify_arm.py | 73 ++++++++++ 17 files changed, 729 insertions(+), 176 deletions(-) create mode 100644 docs/Disaggregated/notes/p5f/close-report.md create mode 100644 docs/Disaggregated/notes/p5f/close-review.md create mode 100644 docs/Disaggregated/notes/p5f/device-report.md create mode 100644 tools/device_bench/p5f/CMakeLists.txt create mode 100644 tools/device_bench/p5f/P5fPublicMipmapScenario.cpp create mode 100644 tools/device_bench/p5f/README.md create mode 100644 tools/device_bench/p5f/build_android.sh create mode 100644 tools/device_bench/p5f/run_pixel_arm.sh create mode 100644 tools/device_bench/p5f/verify_arm.py diff --git a/MobileGL/MG_Remote/CONTRACT-P5.md b/MobileGL/MG_Remote/CONTRACT-P5.md index 4789818b..277a6c07 100644 --- a/MobileGL/MG_Remote/CONTRACT-P5.md +++ b/MobileGL/MG_Remote/CONTRACT-P5.md @@ -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. diff --git a/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md b/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md index 4cbd5dca..59085b92 100644 --- a/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md +++ b/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md @@ -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/` | diff --git a/docs/Disaggregated/P5F-WIRE-COMPLETENESS.md b/docs/Disaggregated/P5F-WIRE-COMPLETENESS.md index c13662fb..d4f2ea3e 100644 --- a/docs/Disaggregated/P5F-WIRE-COMPLETENESS.md +++ b/docs/Disaggregated/P5F-WIRE-COMPLETENESS.md @@ -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 回答。 diff --git a/docs/Disaggregated/P6-CONTRACT-DRAFT.md b/docs/Disaggregated/P6-CONTRACT-DRAFT.md index e08d800d..54bf03b5 100644 --- a/docs/Disaggregated/P6-CONTRACT-DRAFT.md +++ b/docs/Disaggregated/P6-CONTRACT-DRAFT.md @@ -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. diff --git a/docs/Disaggregated/P6-SPAWN-PLAN.md b/docs/Disaggregated/P6-SPAWN-PLAN.md index 504bb98f..8dbddfda 100644 --- a/docs/Disaggregated/P6-SPAWN-PLAN.md +++ b/docs/Disaggregated/P6-SPAWN-PLAN.md @@ -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 开工顺序 diff --git a/docs/Disaggregated/ROADMAP.md b/docs/Disaggregated/ROADMAP.md index 2d8e8e88..3a80a3be 100644 --- a/docs/Disaggregated/ROADMAP.md +++ b/docs/Disaggregated/ROADMAP.md @@ -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 不会传播 | diff --git a/docs/Disaggregated/notes/p5f/HANDOFF-P5F.md b/docs/Disaggregated/notes/p5f/HANDOFF-P5F.md index 118b1df4..2bc946d1 100644 --- a/docs/Disaggregated/notes/p5f/HANDOFF-P5F.md +++ b/docs/Disaggregated/notes/p5f/HANDOFF-P5F.md @@ -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 `;最终日志 `~/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 `。脚本末尾 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 噪音不在本次范围。 diff --git a/docs/Disaggregated/notes/p5f/close-report.md b/docs/Disaggregated/notes/p5f/close-report.md new file mode 100644 index 00000000..4553dc63 --- /dev/null +++ b/docs/Disaggregated/notes/p5f/close-report.md @@ -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 已实现。 diff --git a/docs/Disaggregated/notes/p5f/close-review.md b/docs/Disaggregated/notes/p5f/close-review.md new file mode 100644 index 00000000..f5d47495 --- /dev/null +++ b/docs/Disaggregated/notes/p5f/close-review.md @@ -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 项。 diff --git a/docs/Disaggregated/notes/p5f/device-report.md b/docs/Disaggregated/notes/p5f/device-report.md new file mode 100644 index 00000000..665f21d8 --- /dev/null +++ b/docs/Disaggregated/notes/p5f/device-report.md @@ -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 预跑证据另存,未混入上表、未代替最终库的六臂复跑。 diff --git a/docs/Disaggregated/notes/p5f/fr-report.md b/docs/Disaggregated/notes/p5f/fr-report.md index bf3c4f28..fa270bc9 100644 --- a/docs/Disaggregated/notes/p5f/fr-report.md +++ b/docs/Disaggregated/notes/p5f/fr-report.md @@ -88,4 +88,3 @@ frontend program;相应两个 shutdown scope 不能当作不可达依据。已 Linux 新树的子模块递归初始化遇到本地缺少 apitrace nested commit,随后复用了现有 `p5f-int` 的依赖与 fixture 文件;未运行 `git lfs pull/checkout`,未修改参考树。 - diff --git a/tools/device_bench/p5f/CMakeLists.txt b/tools/device_bench/p5f/CMakeLists.txt new file mode 100644 index 00000000..e3629346 --- /dev/null +++ b/tools/device_bench/p5f/CMakeLists.txt @@ -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() diff --git a/tools/device_bench/p5f/P5fPublicMipmapScenario.cpp b/tools/device_bench/p5f/P5fPublicMipmapScenario.cpp new file mode 100644 index 00000000..efc16a57 --- /dev/null +++ b/tools/device_bench/p5f/P5fPublicMipmapScenario.cpp @@ -0,0 +1,62 @@ +// Device-only P5f preparation. Public GL calls, no MobileGL internal symbols. +#include "Harness/ScenarioFixture.h" +#include +#ifdef GLAPI +#undef GLAPI +#endif +#define GL_GLEXT_PROTOTYPES +#include +#include +#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 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 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 diff --git a/tools/device_bench/p5f/README.md b/tools/device_bench/p5f/README.md new file mode 100644 index 00000000..a015b829 --- /dev/null +++ b/tools/device_bench/p5f/README.md @@ -0,0 +1,26 @@ +# P5f Android public-pixel gate + +Build `bash build_android.sh ` 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 <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 `. + +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. diff --git a/tools/device_bench/p5f/build_android.sh b/tools/device_bench/p5f/build_android.sh new file mode 100644 index 00000000..d71f4b88 --- /dev/null +++ b/tools/device_bench/p5f/build_android.sh @@ -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 +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)" diff --git a/tools/device_bench/p5f/run_pixel_arm.sh b/tools/device_bench/p5f/run_pixel_arm.sh new file mode 100644 index 00000000..eed3d2c9 --- /dev/null +++ b/tools/device_bench/p5f/run_pixel_arm.sh @@ -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 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" diff --git a/tools/device_bench/p5f/verify_arm.py b/tools/device_bench/p5f/verify_arm.py new file mode 100644 index 00000000..459ed2a8 --- /dev/null +++ b/tools/device_bench/p5f/verify_arm.py @@ -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)