diff --git a/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md b/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md index 028f23cb..8814559b 100644 --- a/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md +++ b/docs/Disaggregated/CURRENT_STAGE_PROGRESS.md @@ -1,31 +1,26 @@ -# 当前阶段:P8 已收官(2026-09-30);下一阶段 P13 +# 当前阶段:P13 已收官(2026-10-07);下一阶段 P14 -> **更新 2026-09-30**。这一页只有摘要;计划与裁定在 [`notes/p8/PLAN-P8.md`](notes/p8/PLAN-P8.md)、[`notes/p8/INTEGRATOR-DECISIONS-P8.md`](notes/p8/INTEGRATOR-DECISIONS-P8.md)。上一阶段 P11 于 09-29 收官,见 [`notes/p11/README.md`](notes/p11/README.md)。 +> **更新 2026-10-07**。这一页只有摘要;计划与裁定在 [`notes/p13/PLAN-P13.md`](notes/p13/PLAN-P13.md)、[`notes/p13/INTEGRATOR-DECISIONS-P13.md`](notes/p13/INTEGRATOR-DECISIONS-P13.md),逐波记录在 [`notes/p13/README.md`](notes/p13/README.md)。上一阶段 P8 于 09-30 收官,见 [`notes/p8/README.md`](notes/p8/README.md)。 ## 目标 -补齐 server 侧仿真缺口(Espryt 生成 mip、Espryt 暂存影子与 GPU 写、Magma wire indirect、驱动拒读),并把 monolith 用例登记到 split 各臂;为 P13 删掉旧的「后端直接读前端」路径扫清前置。原范围已重定界(划掉保留在 [`notes/p8/README.md`](notes/p8/README.md))。 +退役 pull 路径:单进程(FCL 内嵌库)也走 P8 修好的记录臂,删掉旧的「后端直接读前端」路径与它的全部编译期 / 运行期开关。 ## 完成情况 | 项 | 状态 | |---|---| -| 只读核查与重定界 | ✅ 原 10 项里 6 项已完成、直接关闭(ID-P8-1) | -| P8-0 普查(设备 + 主机) | ✅ 真实内容只 Magma wire indirect 命中;G 不做;create-indirect 门在多帧 trace 上成立(ID-P8-5) | -| A 覆盖对齐 | ✅ 246 例登上 split / spawn / tcp,`split_coverage.py` 进门(ID-P8-7) | -| B Espryt 生成 mip | ✅(ID-P8-8) | -| C Espryt 暂存影子与 GPU 写 | ✅(ID-P8-9) | -| D Magma wire 原生 indirect | ✅ create-indirect 每次整 GPU 等待 321 → 0(ID-P8-10) | -| E 驱动拒读 / CopyImage | ✅(ID-P8-11) | -| F 死闩清理与重分类 | ✅(ID-P8-6) | -| G 大 blob 分片 | 不做(ID-P8-5) | -| 第一波集成头 `39cd8fb7` | ✅ 整套门全绿,G1 不变(ID-P8-12) | -| 第二波 SE / SV(split 余项) | ✅(ID-P8-15、-16) | -| 第二波 MD + MF(Create 在 Adreno 上) | ✅ dev `f973008c` + feat 镜像:create-instancing × Espryt × monolith 0.870 → 0.99998;create-indirect 坏在 fixture(ID-P8-14) | -| 出口 | ✅ 候选头 `49430538` 整套门全绿;设备矩阵无一格变差;P12 跨机门复跑一致(ID-P8-18、-19) | +| W1 CI 地基(skip 普查、零 `MG_Remote` 符号检查、运行期形态证明) | ✅ | +| W2–W3 默认翻转与去宏(`MOBILEGL_PIPE_PUSH` / `LEGACY_MEMOS` 删除,位 0–13 固定开) | ✅ | +| W4–W5 单进程换到记录臂,记录臂移出 `MG_Remote` | ✅ | +| W6 删后端的前端对象臂(Espryt / Magma),`# P13` 债务清零 | ✅ | +| W7 七个 OBJECT 模块 + server-only 链接检查 | ✅ | +| W8 recorder 金标(首跑抓到并修掉两个单进程推送内容缺陷) | ✅ | +| W9 缓存容量重调 | 移到 P13 之后的性能轮(用户 10-07) | +| W10 文档与收官 | ✅;FCL 真机两后端冒烟通过 | ## 下一步 -**P13**:删掉旧的「后端直接读前端」路径,monolith 换到 P8 已修好的记录臂(P8 留下的 9 条 monolith 缺陷随之消失,`DEBTS.md`)。开工前先做只读核查。 +**P14**:状态归属(同进程多 session / 多 context / share group),设计见 [`design/11-state-ownership.md`](design/11-state-ownership.md)。性能轮(基线 `dev` 构建,定频,FCL MC + anland glmark2,两后端)也排在 P13 之后。 -**待用户决策**:[`DEBTS.md`](notes/DEBTS.md) 六项「需裁定」(CI 触发条件、`TCP_USER_TIMEOUT`、HyperOS 下 FCL 保活、Mali 复测、TLS、`IDLE_EXIT_S`)。 +**待用户决策**:[`DEBTS.md`](notes/DEBTS.md) 中「需裁定」各项;FCL 无声死亡留给用户(`notes/p13/fcl-soak/README.md`)。 diff --git a/docs/Disaggregated/ROADMAP.md b/docs/Disaggregated/ROADMAP.md index a3052641..ea5d7755 100644 --- a/docs/Disaggregated/ROADMAP.md +++ b/docs/Disaggregated/ROADMAP.md @@ -1,6 +1,6 @@ # 路线图(索引) -> **2026-09-30**:P0 到 P7、P12、P9、P10、P11、**P8** 已完成——拆分路线走完,单进程路线只剩 P13。P8(重定界):server 侧仿真缺口补齐(Espryt 生成 mip、暂存副本与 GPU 写、驱动拒读;Magma wire 原生 indirect),246 个 monolith 用例登上 split 各臂并由覆盖门守住;红米上 Create 画错在 dev 与 feat 两条 flush 阶梯修好;契约 `MG_Remote/CONTRACT-P8.md`,G1 整阶段符号不变。下一阶段 **P13**(删掉旧的「后端直接读前端」路径;P8 已把 monolith 要换到的记录臂修好,9 条 monolith 缺陷随之消失)。每个阶段的计划、验收结果、实测与报告在 `notes/<阶段>/`(点阶段名进入)。 +> **2026-10-07**:P0 到 P7、P12、P9、P10、P11、P8、**P13** 已完成——拆分路线与单进程路线都走完。P13(退役 pull 路径):单进程也只走记录臂,pull / push 两套构建、`MOBILEGL_PIPE_PUSH` 与 `MOBILEGL_PIPE_LEGACY_MEMOS` 编译期开关、残余值块和后端的前端对象臂全部删除;库拆成按 link ratchet 分区的七个模块,split 构建里 server 一半单独真链接;G1 退役,由零 `MG_Remote` 符号、skip 普查与 recorder 金标接班;性能工作排在其后,基线是 `dev` 构建。下一项是 **P14**(状态归属)。每个阶段的计划、验收结果、实测与报告在 `notes/<阶段>/`(点阶段名进入)。 ## 目标 @@ -8,7 +8,7 @@ client(跑应用的一方)与 server(跑驱动的一方)可以在**不 ## 两条路线 -- **单进程路线**:先把接口建起来,让单进程版本也受益(后端拥有自己的状态、可以挪到渲染线程)。P0 → P0.5 → P1 → P2 → P3a → P4a → P3b/P4b → P7 → **P8** → P13。 +- **单进程路线**:先把接口建起来,让单进程版本也受益(后端拥有自己的状态、可以挪到渲染线程)。P0 → P0.5 → P1 → P2 → P3a → P4a → P3b/P4b → P7 → P8 → **P13**(走完)。 - **拆分路线**:在接口之上逐步拆开前后端。P5 → P5b → P5c → P5d → P5e → P5f → P6 → P6.5 → Ph → P12 → P9 → P10 → **P11**(走完)。 ## 阶段一览 @@ -37,7 +37,7 @@ client(跑应用的一方)与 server(跑驱动的一方)可以在**不 | [**P9**](notes/p9/README.md) | **反向通道:回读、日志、重铸不再同步等待 client** | ✅ 09-29:PACK-PBO 回读 fire-and-forget(两后端)、日志分级转发、重铸无拉取(`OnLog` / `OnTexturePullRequest` 删,回调 9 → 7),F1 / F2;契约 `MG_Remote/CONTRACT-P9.md`;G1 成立;事件量批处理无实测需求不做;余项进 [`DEBTS.md`](notes/DEBTS.md) | | [**P10**](notes/p10/README.md) | **同步对象、查询与帧节奏** | ✅ 09-29:fence 轮询由 server 报告本地作答(`kEventFenceSignaled`、`MOBILEGL_IPC_POLL_ESCALATE`;主机 Magma·tcp −37%,Adreno 830 上两后端 0 次往返);`SetSwapInterval` 转发、class C 清零;query / XFB / AsyncCompile 登记 split 各臂;credit 1/2/3 设备 loopback 在噪声内;契约 `MG_Remote/CONTRACT-P10.md`;G1 成立;余项进 [`DEBTS.md`](notes/DEBTS.md) | | [**P11**](notes/p11/README.md) | **同机大缓冲零拷贝共享** | ✅ 09-29:T0 零拷贝导入(两后端,默认开,自测不过或 Stream 上静默退回 T2);同机外部 client 经 helper + 令牌 broker 走共享内存(B1);连接按 `PairBind` nonce 配对(修订 5);采纳档位在握手时定;契约 `MG_Remote/CONTRACT-P11.md`;余项进 [`DEBTS.md`](notes/DEBTS.md) | -| [P13](notes/p13/README.md) | 删掉旧的"后端直接读前端"路径 | 待排 | +| [**P13**](notes/p13/README.md) | **删掉旧的"后端直接读前端"路径** | ✅ 10-07:单进程只走记录臂;pull / push 构建与 `PIPE_PUSH` / `LEGACY_MEMOS` 编译期开关、残余值块、后端前端对象臂删除;七个 OBJECT 模块与 server-only 真链接;link ratchet 172 → 27 具名债务;recorder 金标;G1 退役;FCL 真机两后端冒烟通过;性能轮(基线 `dev`)与余项进 [`DEBTS.md`](notes/DEBTS.md) | | **P14** | **状态归属:同进程多 session / 多 context / share group**(统一 server 的前提,anland 内置渲染器不做按进程隔离) | 设计 ✅ [`design/11-state-ownership.md`](design/11-state-ownership.md),实现待做 | ## 另见 diff --git a/docs/Disaggregated/notes/p13/HANDOFF-2026-10-06.md b/docs/Disaggregated/notes/p13/HANDOFF-2026-10-06.md index 428389f1..7009b58f 100644 --- a/docs/Disaggregated/notes/p13/HANDOFF-2026-10-06.md +++ b/docs/Disaggregated/notes/p13/HANDOFF-2026-10-06.md @@ -75,3 +75,7 @@ ## 5. P13 之后:性能(用户裁定,2026-10-07) P13 内不做性能工作。收官后的性能工作以 `dev` 分支构建(pull monolith)为「之前」基线,不用 W6 前的 feat 构建:设备上钉时钟,对比 dev 与 feat,场景 FCL MC 与 anland glmark2,两个后端都测。Magma monolith 记录臂约慢 16% 的读数(DEBTS.md 对应行)留作那时的起点,现在不补测。 + +## 6. 收官(2026-10-07) + +P13 全部波完成(W9 移到 P13 之后的性能轮)。出口门、设备延后清单与 CI 见 [`README.md`](README.md) 的「出口门(收官)」与「设备侧延后清单」。收官时新发现并修掉的:无传输库的单进程不发 `set_context_values`、`RenderStateParameters` 填充字节未清零(W8 recorder 首跑抓到);verify+split 构建不建 server-only 链接检查目标(G4 比较器按设计跨两半)。本机构建目录与手机 `/data/local/tmp/p13` 已清理。 diff --git a/docs/Disaggregated/notes/p13/README.md b/docs/Disaggregated/notes/p13/README.md index d5e64b07..f9e34c78 100644 --- a/docs/Disaggregated/notes/p13/README.md +++ b/docs/Disaggregated/notes/p13/README.md @@ -1,4 +1,4 @@ -# P13 — 退役 pull 路径(进行中) +# P13 — 退役 pull 路径(已收官 2026-10-07) > 计划 [`PLAN-P13.md`](PLAN-P13.md),裁定 [`INTEGRATOR-DECISIONS-P13.md`](INTEGRATOR-DECISIONS-P13.md),CI 清理记录 [`docs/ci/ci-cleanup-log.md`](../../../ci/ci-cleanup-log.md)。本页保存该阶段在路线图上的完整范围与出口门(2026-09-24 从 [`ROADMAP.md`](../../ROADMAP.md) 阶段表移入,原文照录);阶段开工后,计划、裁定与报告都放在本目录。 @@ -12,31 +12,51 @@ | W3a | 完成 | `55de98a0` | `MOBILEGL_PIPE_PUSH` 不再是选项(旧缓存 OFF 警告并忽略) | | W3b | 完成 | `9e14c16d`…`a4d10dd9`、`daf2b44c`…`883b8614`、`c0404018`、`a32ca001` | 删 `MOBILEGL_PIPE_LEGACY_MEMOS`、`MOBILEGL_PIPE_PUSH` 宏与 `MGB_CTX`;位图 bits 0-13 固定开,清位具名拒绝(`SubsystemMaskRefusal.*` 对照);删 HandleRecycle Legacy / AbaControl 车道;每条移除记在 ci-cleanup-log | | W3c | 完成 | `e2c90986` `be86ca17` | 删 `ResidualValueBlock`;op 46 退役为拒绝行;verify 的 A2 负对照接管能力比对 | -| W4a–c(Espryt) | 本地完成 | 14a `3e2aff1d` `cef29781`;谓词、W4a、W4b/W4c(本地) | Espryt monolith 全部族走记录臂:缓冲、indirect、client 数组、绑定点、GPU 写标记、fp64、重启索引、multi-draw、纹理(别名式 staged 纹理 store)、读回(含 pack buffer)、帧缓冲、单元 / sampler / image、program(monolith CSO 记录带档案副本)、XFB;进程内 verb 端口;§1.4 别名刷新。本地 unit 2905/2905、integration-gpu 3650/3650、DirectGLES retrace 29/29(另 11 条缺 LFS fixture 或主机 llvmpipe 的 iterationrp) | -| W4(Magma) | 本地完成 | 一次性换臂(本地) | monolith 注册 wire 资源表;进程内持久映射捐赠(`DonateWireBuffer`:wire store 本就 host-visible / coherent / 常驻映射,交给前端,取 T0 的「回读无字节」语义);`GetSyncStatus` 在记录臂上对同一未提交 fence 连续轮询 64 次后提交一次(split 由 apply 线程空闲时提交,monolith 无空闲时刻);ABA 对照车道钉前端臂(其对象是前端臂的身份表,W6 随之删);`DescriptorPoolGrowth` 的 wire 预算按记录臂而非传输判断。本地 integration-gpu 3650/3650、DirectVulkan retrace 29/29(本机须 `MOBILEGL_GPU_HANG_BUDGET_MS=0`,与 CI 相同,否则 llvmpipe 上 >2 s 的提交触发挂死看门狗) | -| W4b 补 monolith 登记 | 本地完成 | | `DirectGLES.Monolith.CpuMip.*`(`MGITEST_ESPRYT_FORCE_CPU_MIPMAP`)与 `DirectGLES.Monolith.StoreRead.*`(`MGITEST_ESPRYT_REFUSE_TEXTURE_READBACK_EXTENT`),各自私有日志断言本臂的日志行。StoreRead 首跑 3/4 红:别名式纹理 store 不跟随 `glCopyImageSubData`,目的 level 被标为驱动写过,驱动又拒读 → `Fatal{ReplyError, "ReadPixels"}`(W4 引入的 monolith 回归,只在驱动拒读该格式时可达)。修复:`FollowCopy` 在别名模式下先把目的 level 取成服务端自有副本再搬窗口(从不写前端内存),`AdoptClientBoxes` 随后在该副本上落客户端的框;单元 `AnAliasingStoreFollowsACopyIntoAServerOwnedDestination`。**真机(Adreno 750,Lenovo Y700,2026-10-06)**:不加旋钮时修复前后都全绿,日志里没有 store 路由——该驱动有 `GL_EXT_texture_norm16` 与 `GL_EXT_render_snorm`,四种格式的读回都走 GPU,P8-E 记的「Adreno 拒读 RGB16 / 16 位 SNORM」是读代码推断、在 750 上不成立(更老的 Adreno 或缺这两个扩展的驱动才可达)。加 `MGITEST_ESPRYT_REFUSE_TEXTURE_READBACK_EXTENT=12x6` 强制拒读:修复前 monolith 的四个 copy 用例 `Fatal{ReplyError, "ReadPixels"}`(inproc 全绿),修复后 monolith 与 inproc 全绿(探针 `storeprobe`,裸 adb-shell ELF + pbuffer) | +| W4a–c(Espryt) | 完成 | 14a `3e2aff1d` `cef29781`;谓词、W4a、W4b/W4c(本地) | Espryt monolith 全部族走记录臂:缓冲、indirect、client 数组、绑定点、GPU 写标记、fp64、重启索引、multi-draw、纹理(别名式 staged 纹理 store)、读回(含 pack buffer)、帧缓冲、单元 / sampler / image、program(monolith CSO 记录带档案副本)、XFB;进程内 verb 端口;§1.4 别名刷新。本地 unit 2905/2905、integration-gpu 3650/3650、DirectGLES retrace 29/29(另 11 条缺 LFS fixture 或主机 llvmpipe 的 iterationrp) | +| W4(Magma) | 完成 | 一次性换臂(本地) | monolith 注册 wire 资源表;进程内持久映射捐赠(`DonateWireBuffer`:wire store 本就 host-visible / coherent / 常驻映射,交给前端,取 T0 的「回读无字节」语义);`GetSyncStatus` 在记录臂上对同一未提交 fence 连续轮询 64 次后提交一次(split 由 apply 线程空闲时提交,monolith 无空闲时刻);ABA 对照车道钉前端臂(其对象是前端臂的身份表,W6 随之删);`DescriptorPoolGrowth` 的 wire 预算按记录臂而非传输判断。本地 integration-gpu 3650/3650、DirectVulkan retrace 29/29(本机须 `MOBILEGL_GPU_HANG_BUDGET_MS=0`,与 CI 相同,否则 llvmpipe 上 >2 s 的提交触发挂死看门狗) | +| W4b 补 monolith 登记 | 完成 | | `DirectGLES.Monolith.CpuMip.*`(`MGITEST_ESPRYT_FORCE_CPU_MIPMAP`)与 `DirectGLES.Monolith.StoreRead.*`(`MGITEST_ESPRYT_REFUSE_TEXTURE_READBACK_EXTENT`),各自私有日志断言本臂的日志行。StoreRead 首跑 3/4 红:别名式纹理 store 不跟随 `glCopyImageSubData`,目的 level 被标为驱动写过,驱动又拒读 → `Fatal{ReplyError, "ReadPixels"}`(W4 引入的 monolith 回归,只在驱动拒读该格式时可达)。修复:`FollowCopy` 在别名模式下先把目的 level 取成服务端自有副本再搬窗口(从不写前端内存),`AdoptClientBoxes` 随后在该副本上落客户端的框;单元 `AnAliasingStoreFollowsACopyIntoAServerOwnedDestination`。**真机(Adreno 750,Lenovo Y700,2026-10-06)**:不加旋钮时修复前后都全绿,日志里没有 store 路由——该驱动有 `GL_EXT_texture_norm16` 与 `GL_EXT_render_snorm`,四种格式的读回都走 GPU,P8-E 记的「Adreno 拒读 RGB16 / 16 位 SNORM」是读代码推断、在 750 上不成立(更老的 Adreno 或缺这两个扩展的驱动才可达)。加 `MGITEST_ESPRYT_REFUSE_TEXTURE_READBACK_EXTENT=12x6` 强制拒读:修复前 monolith 的四个 copy 用例 `Fatal{ReplyError, "ReadPixels"}`(inproc 全绿),修复后 monolith 与 inproc 全绿(探针 `storeprobe`,裸 adb-shell ELF + pbuffer) | | W4d | 部分(本地) | | monolith 记录臂的 8 个值类字段改由 `set_context_values` 记录供给(不再 residual 填充)。转发访问器替身、`kFatal` 前端指针字段删除、`PipeInputs.h` 去 `MG_State` 头并入 W6/W7(它们是删前端臂与模块边界的一部分) | -| GL_ARB_shader_objects(用户插单) | 本地完成 | | 原先 11 个入口是桩(`glCreate*ObjectARB` 恒返回 1)、其余 28 个在 `eglGetProcAddress` 里根本查不到,扩展却对外宣告(KWin 要这串)。现在:句柄就是核心共享的 shader/program 名字空间里的名字(`glCreateShaderObjectARB` = `glCreateShader`),核心与 ARB 调用互用;`DeleteObjectARB` / `GetHandleARB` / `GetObjectParameter{i,f}vARB`(`OBJECT_TYPE` / `OBJECT_SUBTYPE` 与按类型的核心 pname,错误码按扩展规范)/ `GetInfoLogARB` 在 `GL_ShaderObjectsARB.cpp`,其余转发核心。同样宣告的 GL_ARB_vertex_shader 的 46 个入口(29 个桩、17 个缺失)一并转发核心。顺带修了核心缺陷:`glDetachShader` 后 `GL_ATTACHED_SHADERS` / `glGetAttachedShaders` 仍算该 shader、二次 detach 不报错、下次 link 前重新 attach 被拒(GL 4.6 §7.3)。`glGen*` 各名字空间互相独立、保留名在首次绑定前不是对象(sampler 例外)、删除后不再是对象——新场景逐类断言,全部本来就合规。wire 侧 ARB 入口全走核心入口,记录臂按 `{slot, gen}` 一视同仁。场景 `ArbShaderObjectsScenario`(两后端 × monolith / split / spawn / tcp) | -| W5 S0 | 本地完成 | | 设计见 `notes/p13/` 下的 `W5-DESIGN.md`(临时 CMake 变量 `MOBILEGL_BUILD_RECORD_ARM`,S7 一次翻转,S8 unifdef 掉)。开放三点已定:记录失败钩子在 `FatalFunnel.cpp` 静态注册;`RecordArmTable` 承接三个持久映射 / wire 延迟旋钮(`IpcTable` 仍只在 DISAGG);S7 加 mprotect 臂开关(FCL 是 JVM 进程,SIGSEGV 链接是真风险)。清单 `W5-INVENTORY.csv`(`tools/w5_classify.py`):A 385 块 / 10586 行、B 29/434、C 92/10878、D 89/4683、E 77/933、F 292/3184、N(取反 / 复合)30/1545。主机 x86_64 Release 基线:push 库 `.text` 11540563、0 个 `MG_Remote::` 符号;split 库 `.text` 12766899、1651 个 | -| W5 S1 | 本地完成 | `534f14e3` `3b441531`(已推) | 致命词表(`FatalFamilies.def`、`MGFatalFamily`、名字、计数)移到 `MG_Pipe/PipeFatalFamily.h`,`MG_Remote/FatalFamily.h` 只留线上投影并转出旧名。记录臂的失败 / 闩缝:`MGPipeRecordFail` / `MGPipeRecordLatch` / `MGPipeRecordLatched`(`PipeSessionFail.h`,默认:日志 + stderr + abort),链接了 MG_Remote 时由 `FatalFunnel.cpp` 静态注册 `SessionFail` / `SessionLatch` / `SessionLatched`。fatal census 认新调用(规则 2)并认默认分支的 abort 为漏斗;单元 `RecordFailSeamTest` 两棵树都跑 | -| W5 S2 | 本地完成 | | `MOBILEGL_BUILD_RECORD_ARM`(普通 CMake 变量,恒定义 0/1,S7 前等于 DISAGG);`tools/w5_rewrite.py` 把 MG_State(缓冲 / 程序 / 帧缓冲状态)、MG_Impl(GLImpl、Pipe)、MG_Pipe、MG_Util/SelfTest、MG_Backend 下 A / F 类与 `!DISAGG`、`VERIFY && !DISAGG` 守卫改名,共 536 组、按目录 7 个提交;EGL 层、GL 上下文的设备丢失状态、日志角色文件、统计 dump 路径留给 S3 手工。不变量已核:split 与 push 两库 `.text` 字节相同(sha 前缀 `a0d08e0e` / `df9d3b7a`,与 S1 一致)。`wire_declines_audit` 把新守卫当作构建选择开关(含两条自测) | -| W5 S3 | 本地完成 | `e544121e`…`7f194a85` | 手工改守卫:记录臂的声明、存根、T0 拆分、Magma wire 纹理 / 顶点输入构建、对象死亡、caps 来源跟 `RECORD_ARM`;共享图像、设备丢失闩、双块诊断留 DISAGG。应用侧后端经 `MG_Backend::ApplyRoleBackend` 钩子(`ServerLoop.cpp` 静态安装,无传输时为空,与 monolith 原答案相同) | -| W5 S4 | 本地完成 | `73a185f6` `0f5658f5` `fe5324c9` `8e76f9dc` `85125167` | 代码迁出 MG_Remote,命名空间 `MG_Record`:暂存库到 `MG_Backend/Record/`;持久映射跟踪器到 `MG_State/.../BufferState/`(领养层判定留 `MG_Remote/Client/AdoptTierChoice`);`ServerVerbSink` 的记录动词抽成 `RecordVerbSink`(`ServerVerbSink` 继承它,只留会话动词);动词发射器、monolith 动词端口、客户端 GPU 写集合到 `MG_Impl/Pipe/Verb/`(会话经 `MG_Record::VerbSession`,`EmitTables.cpp` 静态装解析器)。include-closure 新探针 `record-core`(`--expect-probes 5`)。link ratchet 171 不变,fatal census 76 不变 | -| W5 S5 | 本地完成 | `b13af729` `b1978890` | 记录臂三旋钮进 `RecordArmTable`;`DataArmIsRecord` / `RecordArmAliasesFrontend`、`MonolithTakesRecordArm`、`MOBILEGL_PIPE_DATA_ARM` 跟 `RECORD_ARM`(不再跟传输) | -| W5 S6 | 本地完成 | `dd7fbbd7` | 集成 peek 在无传输构建里也答 `dataArmIsRecord`;跟踪器探针跟 `RECORD_ARM` | -| W5 S7 | 本地完成(CI 待跑) | `19610290` `23593c9f`…`e9a353c3` | **翻转**:`MOBILEGL_BUILD_RECORD_ARM` 恒 ON,无 MG_Remote 的库(FCL 形态)也跑记录臂。`MOBILEGL_PIPE_PERSISTENT_MPROTECT=0` 关掉跟踪器的 SIGSEGV 处理器(FCL 是 JVM;启动打日志;单元 `TheMprotectSwitchSendsEveryNewMapToTheHashScan`),mprotect 臂只在 Linux / Android 编。`runtime_mode_proof` 加正半:两形态都要 `MG_Record` 符号(push 294、split 300),自测含两条无 `MG_Record` 的红例。翻转后 push 单元暴露的残留误分类(记录动词的 verb 状态盖章、按记录读的顶点 / IBO / 绑定点 / 采样器路径、XFB 捕获回落、视图窗口 mip、镜像可绑定重铸、暂存库跟随、跟踪器成员资格、测试的前端臂钉)全部改跟 `RECORD_ARM`;push 单元 2028/2028 | +| GL_ARB_shader_objects(用户插单) | 完成 | | 原先 11 个入口是桩(`glCreate*ObjectARB` 恒返回 1)、其余 28 个在 `eglGetProcAddress` 里根本查不到,扩展却对外宣告(KWin 要这串)。现在:句柄就是核心共享的 shader/program 名字空间里的名字(`glCreateShaderObjectARB` = `glCreateShader`),核心与 ARB 调用互用;`DeleteObjectARB` / `GetHandleARB` / `GetObjectParameter{i,f}vARB`(`OBJECT_TYPE` / `OBJECT_SUBTYPE` 与按类型的核心 pname,错误码按扩展规范)/ `GetInfoLogARB` 在 `GL_ShaderObjectsARB.cpp`,其余转发核心。同样宣告的 GL_ARB_vertex_shader 的 46 个入口(29 个桩、17 个缺失)一并转发核心。顺带修了核心缺陷:`glDetachShader` 后 `GL_ATTACHED_SHADERS` / `glGetAttachedShaders` 仍算该 shader、二次 detach 不报错、下次 link 前重新 attach 被拒(GL 4.6 §7.3)。`glGen*` 各名字空间互相独立、保留名在首次绑定前不是对象(sampler 例外)、删除后不再是对象——新场景逐类断言,全部本来就合规。wire 侧 ARB 入口全走核心入口,记录臂按 `{slot, gen}` 一视同仁。场景 `ArbShaderObjectsScenario`(两后端 × monolith / split / spawn / tcp) | +| W5 S0 | 完成 | | 设计见 `notes/p13/` 下的 `W5-DESIGN.md`(临时 CMake 变量 `MOBILEGL_BUILD_RECORD_ARM`,S7 一次翻转,S8 unifdef 掉)。开放三点已定:记录失败钩子在 `FatalFunnel.cpp` 静态注册;`RecordArmTable` 承接三个持久映射 / wire 延迟旋钮(`IpcTable` 仍只在 DISAGG);S7 加 mprotect 臂开关(FCL 是 JVM 进程,SIGSEGV 链接是真风险)。清单 `W5-INVENTORY.csv`(`tools/w5_classify.py`):A 385 块 / 10586 行、B 29/434、C 92/10878、D 89/4683、E 77/933、F 292/3184、N(取反 / 复合)30/1545。主机 x86_64 Release 基线:push 库 `.text` 11540563、0 个 `MG_Remote::` 符号;split 库 `.text` 12766899、1651 个 | +| W5 S1 | 完成 | `534f14e3` `3b441531`(已推) | 致命词表(`FatalFamilies.def`、`MGFatalFamily`、名字、计数)移到 `MG_Pipe/PipeFatalFamily.h`,`MG_Remote/FatalFamily.h` 只留线上投影并转出旧名。记录臂的失败 / 闩缝:`MGPipeRecordFail` / `MGPipeRecordLatch` / `MGPipeRecordLatched`(`PipeSessionFail.h`,默认:日志 + stderr + abort),链接了 MG_Remote 时由 `FatalFunnel.cpp` 静态注册 `SessionFail` / `SessionLatch` / `SessionLatched`。fatal census 认新调用(规则 2)并认默认分支的 abort 为漏斗;单元 `RecordFailSeamTest` 两棵树都跑 | +| W5 S2 | 完成 | | `MOBILEGL_BUILD_RECORD_ARM`(普通 CMake 变量,恒定义 0/1,S7 前等于 DISAGG);`tools/w5_rewrite.py` 把 MG_State(缓冲 / 程序 / 帧缓冲状态)、MG_Impl(GLImpl、Pipe)、MG_Pipe、MG_Util/SelfTest、MG_Backend 下 A / F 类与 `!DISAGG`、`VERIFY && !DISAGG` 守卫改名,共 536 组、按目录 7 个提交;EGL 层、GL 上下文的设备丢失状态、日志角色文件、统计 dump 路径留给 S3 手工。不变量已核:split 与 push 两库 `.text` 字节相同(sha 前缀 `a0d08e0e` / `df9d3b7a`,与 S1 一致)。`wire_declines_audit` 把新守卫当作构建选择开关(含两条自测) | +| W5 S3 | 完成 | `e544121e`…`7f194a85` | 手工改守卫:记录臂的声明、存根、T0 拆分、Magma wire 纹理 / 顶点输入构建、对象死亡、caps 来源跟 `RECORD_ARM`;共享图像、设备丢失闩、双块诊断留 DISAGG。应用侧后端经 `MG_Backend::ApplyRoleBackend` 钩子(`ServerLoop.cpp` 静态安装,无传输时为空,与 monolith 原答案相同) | +| W5 S4 | 完成 | `73a185f6` `0f5658f5` `fe5324c9` `8e76f9dc` `85125167` | 代码迁出 MG_Remote,命名空间 `MG_Record`:暂存库到 `MG_Backend/Record/`;持久映射跟踪器到 `MG_State/.../BufferState/`(领养层判定留 `MG_Remote/Client/AdoptTierChoice`);`ServerVerbSink` 的记录动词抽成 `RecordVerbSink`(`ServerVerbSink` 继承它,只留会话动词);动词发射器、monolith 动词端口、客户端 GPU 写集合到 `MG_Impl/Pipe/Verb/`(会话经 `MG_Record::VerbSession`,`EmitTables.cpp` 静态装解析器)。include-closure 新探针 `record-core`(`--expect-probes 5`)。link ratchet 171 不变,fatal census 76 不变 | +| W5 S5 | 完成 | `b13af729` `b1978890` | 记录臂三旋钮进 `RecordArmTable`;`DataArmIsRecord` / `RecordArmAliasesFrontend`、`MonolithTakesRecordArm`、`MOBILEGL_PIPE_DATA_ARM` 跟 `RECORD_ARM`(不再跟传输) | +| W5 S6 | 完成 | `dd7fbbd7` | 集成 peek 在无传输构建里也答 `dataArmIsRecord`;跟踪器探针跟 `RECORD_ARM` | +| W5 S7 | 完成 | `19610290` `23593c9f`…`e9a353c3` | **翻转**:`MOBILEGL_BUILD_RECORD_ARM` 恒 ON,无 MG_Remote 的库(FCL 形态)也跑记录臂。`MOBILEGL_PIPE_PERSISTENT_MPROTECT=0` 关掉跟踪器的 SIGSEGV 处理器(FCL 是 JVM;启动打日志;单元 `TheMprotectSwitchSendsEveryNewMapToTheHashScan`),mprotect 臂只在 Linux / Android 编。`runtime_mode_proof` 加正半:两形态都要 `MG_Record` 符号(push 294、split 300),自测含两条无 `MG_Record` 的红例。翻转后 push 单元暴露的残留误分类(记录动词的 verb 状态盖章、按记录读的顶点 / IBO / 绑定点 / 采样器路径、XFB 捕获回落、视图窗口 mip、镜像可绑定重铸、暂存库跟随、跟踪器成员资格、测试的前端臂钉)全部改跟 `RECORD_ARM`;push 单元 2028/2028 | | W5 S8 | 已推(CI 37515697754:382 绿、2 红均已归类并修) | `7fb18840` `c1e985c8` | `MOBILEGL_BUILD_RECORD_ARM` 被 unifdef 掉,`retired_switches` 禁止它回到 `#if`。verify 车道的阴性对照 B 改省略 `ReadPixels:GetPixelStoreParameters`(monolith 记录臂不再读 GenerateMipmap 的活动单元);monolith 启动时记一行数据臂 | | W6a | 已推(`887547c7`,CI 37534648608 / 37534648624) | `d61a4240` `740dd301` | 记录臂是唯一数据臂:`DataArmIsRecord()` 恒 true(constexpr),`MOBILEGL_PIPE_DATA_ARM` / `InitDataArm` / `ScopedMonolithFrontendArm` 删;`HandleRecycle.AbaControlHandles` 车道退役;立方面读回两条规则移到 `CubeFaceReadbackScenario` | | W6b | 已推(同上) | `742d43ae` `e0113503` `3aed7ae0` `e822c933` | 数据臂谓词从两后端所有分支折掉,记录臂 return 之后的前端臂代码删;XFB 角色状态只留一份;10 个前端臂单元用例删(逐条记入 `docs/ci/ci-cleanup-log.md`),两条 GL 采样规则移到 `TextureUnitSamplingScenario` | -| W6c | 本地完成 | `dc1e95b4` | Magma 前端臂:前端 `MagmaProgramSource` 构造与 `IsWire()` 折掉,前端采样集遍历、占位纹理、VAO draw memo、`MagmaPipeIdentityTables` 与 ABA 旋钮、`TrySetupDrawFastPath` 与快照、前端 fallback 纹理删(约 7100 行) | -| W6d | 本地完成 | `8abae647` `8bc39c79` | Espryt 各族臂谓词(framebuffer / texture / sampler / program / buffer / vertex input 及其别名)折为记录臂,`g_fboTextureSyncList` 等前端遍历删;启动时只查色彩附件上限(`ResolveRecordArmFamilies`);未迁移仿真名单清空(审计保留,守 0) | -| W6e–f | 本地完成 | `dab827d5` `737ef5e9` `922507f8` | 后端表里 verb port 在各模式都覆盖的前端对象入口(`ClearNamedFramebuffer*`、`BlitNamedFramebuffer`、`GetTex(ture)Image`、`MultiDrawElements`)及其实现删;Magma 前端 render pass、pending clear、renderbuffer 半边删。Magma 管线构建只读 draw framebuffer 记录,其后的前端纹理同步删。link ratchet 171 → 49,`# P13` 95 → 9(余下见 HANDOFF §3d,转 W7) | -| W7 | 本地完成 | `9fa61b84` | D12:`SOURCE_FILES` 按 link ratchet 的 PARTITION 拆成 7 个 OBJECT 库(`mg_util` / `mg_pipe` / `mg_backend` / `mg_frontend` / `mg_remote_transport` / `mg_remote_client` / `mg_remote_server`),`MobileGL` 与 `MobileGL_s` 链同一批对象(每个文件只编一次),编译侧使用要求集中在接口目标 `mgl_build_iface`。新目标 `MobileGL_server_linkcheck`(split、Linux):只链 server 与 shared 模块、`--no-undefined`,基线里每条前端引用经 `scripts/ci/server_link_check.py` 生成的 `--defsym` 具名豁免到一个 abort 桩;基线没列的 server→前端引用在链接前按名拒绝(两个阴性对照已验:少一条基线、少一条豁免都红)。当前 65 条豁免:49 条来自 server 对象(即基线),16 条来自 shared 的入口胶水(`Init` / 全局对象)。`link_ratchet.py` 改为同时扫 `mg_*.dir` | -| `# P13` 出口门 | 本地完成 | `fa77b187` `9987e57f` | 死亡通知带 handle(`StateObjectDeathOps.OnDestroyed(kind, lifetimeId, handle)`),Espryt 按 handle 放孪生(`ReleaseTwinsForWireObjectDeath`,与 server 的 object_death 同一释放),槽由 client 在通知后释放;Espryt 前端键槽表入口(`GetOrCreate(StatePtr)` / `Find(object)` / `HandleOf` 及其记忆 / `Note/StateForHandle` / 寿命 id 死亡遍历)、遗留 map 臂与 GC、注册表拒绝、`MGPipeApplierIsUnbarrieredApply` 与两个空作用域删掉;`InvalidateCompileEnv` 走 `MGPipeNotifyCompileEnvChanged()` 钩子,`HasOpenTransformFeedbackSpan` 改读 applier 的 `StreamOutputSpans`;link ratchet 49 → 36,`--assert-monotone` 拒绝任何 `# P13` 注解;10 个 `DirectGLESSlotTable` 用例改驱 handle 入口,9 个用例退役(记入 ci-cleanup-log) | -| §1.3 残留 | 本地完成 | `de6ab167` | 删遗留 `BufferBackendOps` 表(前端分派、两后端 Ops_*、`BufferObject` Get/SetBackendResource)、Magma 从未填充的缓存(`VkTextureManager` 前端键 map 与记忆、`VkRenderPassManager` 的 render pass / renderbuffer / 待清除 / 追踪附件缓存与驱逐观察者)和 `VkClearManager`;约 30 个 BufferTest mock 用例与 1 个 SplitBufferSet 用例改驱 `MGPipeResourceOps` mock,未退役;ratchet 36 → 27 | -| W8 | 本地完成 | | recorder 金标(`MG_Test/Pipe/RecorderGoldenTest.cpp`,金标在 `MG_Test/Pipe/goldens/recorder/`):记录器装在两张 MGPipe 表、路由 escape 与 verb 会话上,两条固定 GL 调用序列逐条录(47 / 40 行:资源、纹理参数、采样器、program、帧缓冲、render state、顶点输入、4 种 draw、两种 clear、blit、mipmap),规范化只清调用方内存地址;`MOBILEGL_RECORDER_GOLDEN_WRITE=1` 重写且必红;阴性对照两条(改一条 verb 记录的字段 → 在那条红;改一个 GL 输入 → 在资源记录处红);有无 `MG_Remote` 两种库对同一金标。首跑抓到两个真问题并修:无传输库的单进程不发 `set_context_values`(`PipeFill.cpp` 的 `#else` 分支仍是 W5 前的常量 false),`RenderStateParameters` 的填充字节未清零(内容寻址 CSO 在状态相同的两个 context 间不复用);测试接缝 `SetMonolithVerbPortRoutingForTesting` | +| W6c | 完成 | `dc1e95b4` | Magma 前端臂:前端 `MagmaProgramSource` 构造与 `IsWire()` 折掉,前端采样集遍历、占位纹理、VAO draw memo、`MagmaPipeIdentityTables` 与 ABA 旋钮、`TrySetupDrawFastPath` 与快照、前端 fallback 纹理删(约 7100 行) | +| W6d | 完成 | `8abae647` `8bc39c79` | Espryt 各族臂谓词(framebuffer / texture / sampler / program / buffer / vertex input 及其别名)折为记录臂,`g_fboTextureSyncList` 等前端遍历删;启动时只查色彩附件上限(`ResolveRecordArmFamilies`);未迁移仿真名单清空(审计保留,守 0) | +| W6e–f | 完成 | `dab827d5` `737ef5e9` `922507f8` | 后端表里 verb port 在各模式都覆盖的前端对象入口(`ClearNamedFramebuffer*`、`BlitNamedFramebuffer`、`GetTex(ture)Image`、`MultiDrawElements`)及其实现删;Magma 前端 render pass、pending clear、renderbuffer 半边删。Magma 管线构建只读 draw framebuffer 记录,其后的前端纹理同步删。link ratchet 171 → 49,`# P13` 95 → 9(余下见 HANDOFF §3d,转 W7) | +| W7 | 完成 | `9fa61b84` | D12:`SOURCE_FILES` 按 link ratchet 的 PARTITION 拆成 7 个 OBJECT 库(`mg_util` / `mg_pipe` / `mg_backend` / `mg_frontend` / `mg_remote_transport` / `mg_remote_client` / `mg_remote_server`),`MobileGL` 与 `MobileGL_s` 链同一批对象(每个文件只编一次),编译侧使用要求集中在接口目标 `mgl_build_iface`。新目标 `MobileGL_server_linkcheck`(split、Linux):只链 server 与 shared 模块、`--no-undefined`,基线里每条前端引用经 `scripts/ci/server_link_check.py` 生成的 `--defsym` 具名豁免到一个 abort 桩;基线没列的 server→前端引用在链接前按名拒绝(两个阴性对照已验:少一条基线、少一条豁免都红)。当前 65 条豁免:49 条来自 server 对象(即基线),16 条来自 shared 的入口胶水(`Init` / 全局对象)。`link_ratchet.py` 改为同时扫 `mg_*.dir` | +| `# P13` 出口门 | 完成 | `fa77b187` `9987e57f` | 死亡通知带 handle(`StateObjectDeathOps.OnDestroyed(kind, lifetimeId, handle)`),Espryt 按 handle 放孪生(`ReleaseTwinsForWireObjectDeath`,与 server 的 object_death 同一释放),槽由 client 在通知后释放;Espryt 前端键槽表入口(`GetOrCreate(StatePtr)` / `Find(object)` / `HandleOf` 及其记忆 / `Note/StateForHandle` / 寿命 id 死亡遍历)、遗留 map 臂与 GC、注册表拒绝、`MGPipeApplierIsUnbarrieredApply` 与两个空作用域删掉;`InvalidateCompileEnv` 走 `MGPipeNotifyCompileEnvChanged()` 钩子,`HasOpenTransformFeedbackSpan` 改读 applier 的 `StreamOutputSpans`;link ratchet 49 → 36,`--assert-monotone` 拒绝任何 `# P13` 注解;10 个 `DirectGLESSlotTable` 用例改驱 handle 入口,9 个用例退役(记入 ci-cleanup-log) | +| §1.3 残留 | 完成 | `de6ab167` | 删遗留 `BufferBackendOps` 表(前端分派、两后端 Ops_*、`BufferObject` Get/SetBackendResource)、Magma 从未填充的缓存(`VkTextureManager` 前端键 map 与记忆、`VkRenderPassManager` 的 render pass / renderbuffer / 待清除 / 追踪附件缓存与驱逐观察者)和 `VkClearManager`;约 30 个 BufferTest mock 用例与 1 个 SplitBufferSet 用例改驱 `MGPipeResourceOps` mock,未退役;ratchet 36 → 27 | +| W8 | 完成 | | recorder 金标(`MG_Test/Pipe/RecorderGoldenTest.cpp`,金标在 `MG_Test/Pipe/goldens/recorder/`):记录器装在两张 MGPipe 表、路由 escape 与 verb 会话上,两条固定 GL 调用序列逐条录(47 / 40 行:资源、纹理参数、采样器、program、帧缓冲、render state、顶点输入、4 种 draw、两种 clear、blit、mipmap),规范化只清调用方内存地址;`MOBILEGL_RECORDER_GOLDEN_WRITE=1` 重写且必红;阴性对照两条(改一条 verb 记录的字段 → 在那条红;改一个 GL 输入 → 在资源记录处红);有无 `MG_Remote` 两种库对同一金标。首跑抓到两个真问题并修:无传输库的单进程不发 `set_context_values`(`PipeFill.cpp` 的 `#else` 分支仍是 W5 前的常量 false),`RenderStateParameters` 的填充字节未清零(内容寻址 CSO 在状态相同的两个 context 间不复用);测试接缝 `SetMonolithVerbPortRoutingForTesting` | | W9 | 移出 P13 | | 缓存容量重调属性能工作,按用户裁定移到 P13 之后的性能轮(DEBTS.md 对应行) | +| 设备冒烟(收官头) | 完成 | `f4e98710` | FCL(Y700,Adreno 750,Minecraft 1.21.5 RD2,时钟未钉)用收官头的 FCL 形态库(无 `MG_Remote`)两后端都进世界、画面正常、日志无 Fatal / 信号:Espryt 222 fps、Magma 164 fps(只作记录,不是性能数);设备随后还原(原库 md5 与原 `config.json`) | + +### 出口门(收官) + +| 门 | 结果 | +|---|---| +| `ResidualValueBlock` 清零 | W3c 整块删除(op 46 退役为拒绝行),比原门(`static_assert(sizeof == 0)`)更进一步 | +| 三道纯度门在非 verify 构建上转绿 | A 包含闭包:5 探针 0 问题;B server 镜像:link ratchet 172 → 27,全部是基线里具名的债务(14 条 `MG_State::GLState`、10 条 `MG_Remote::Client`、2 条 `PipeInputs`、1 条 `MG_Impl`),`# P13` 注解 0 条并由脚本拒绝回潮,W7 的 `MobileGL_server_linkcheck` 在 split 构建里真链接;C `MG_Backend` 里零 `pGLContext` | +| recorder 金标建立 | W8(见上行) | +| monolith 逐线程 CPU 不差于 P0 基线 | 只记录、不设门(ID-P13-2);P13 之后的性能轮以 `dev` 构建为基线(用户 2026-10-07),Magma 约慢 16% 记为债务 | +| CI | 收官头 Test 与 APK 全绿(运行号见收官报告);本机整套门:unit(split 2884、push 2007、verify 2007)、integration-gpu(push 1433、split 3705)、integration-verify 1290 全过 | + +### 设备侧延后清单 + +- 收官头在 Mali(K50)上的冒烟(只做了 Y700 / Adreno 750 两后端)。 +- Magma 记录臂打开的可选设备扩展(renderpass2 深度 resolve、stencil export、robustness2)在不支持它们的设备上的回退(W5-DESIGN §135)。 +- FCL 的 JVM 里 persistent-map 跟踪器的 SIGSEGV 处理器(`MOBILEGL_PIPE_PERSISTENT_MPROTECT`)长时间游玩下的行为(冒烟只跑了约 90 s)。 +- 性能:monolith 逐线程 CPU、Magma 16%、W9 缓存容量——统一放 P13 之后的性能轮,基线 `dev`,定频,FCL MC + anland glmark2,两后端(`DEBTS.md`)。 +- FCL 游戏进程无声死亡(SIGRTMIN+2)属 FCL,记为债务(`fcl-soak/README.md`)。 + ### G1 退役读数(ID-P13-4,2026-10-06) pull 构建(`DISAGGREGATED=OFF`、`PIPE_PUSH=OFF`,只编 `MobileGL` target),同机同编译器(WSL archlinux,clang 22.1.6):