Files
MobileGL/docs/Disaggregated/notes/p5f/fc-report.md
T

162 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# P5f / fc — EGL/surface 控制面帧化:落地报告
> 落地于 `p5f/fc`。设计输入:`f0-egl.md`(逐 forwarder 点名表、schema 缺口清单、帧设计草案);
> 契约草稿 [`fc-contract-draft.md`](fc-contract-draft.md)(CONTRACT-P5F.md 本体留给集成收口)。
> 范围:P5F-WIRE-COMPLETENESS.md §2.3(P5c 审计 G4 行,原记 P6,P5f 收回)。
---
## 1 落地内容
| 文件 | 内容 |
|---|---|
| `MobileGL/MG_Remote/Protocol/protocol.fbs` | **append-only**:`SurfaceOpKind` 补 `SetSwapInterval=8` / `ReleaseResources=9` / `SetWindowHandle=10`(与 P6-SPAWN-PLAN 的预测逐字一致);`WindowKind` 补 `MetalLayer=6`(f0-egl schema 缺口 3:两枚举不互洽的另一半);`SurfaceOp` 补 `readSurface`、`context` 两字段(MakeCurrent 的语义单元是四元组) |
| `.../Protocol/generated/protocol_generated.h` | 用 pinned flatc(`~/w7/p5-s1-flatc-build/flatc`,25.12.19)重新生成;diff 仅 +58/−6 行,全部落在追加的枚举值与字段上 |
| `.../Server/SurfaceControlFrame.{h,cpp}` | 纯值帧:`SurfaceControlOp`(10 个 wire op + 4 个 inproc-only kind)+ `SurfaceControlFrame`(constexpr 穷举结构化绑定 + 每成员 integer/enum 断言禁止指针;trivially-copyable / standard-layout 单独约束复制形态(§8 修正初版断言)) |
| `.../Protocol/SurfaceOpCodec.{h,cpp}` | 帧 ↔ `Wire::SurfaceOp`/`SurfaceReply` 编解码;`WindowBackend` ↔ `WindowKind` 显式映射表(Surfaceless/Pbuffer 具名无后端);wire 入口 `ServerApplyWireSurfaceOp` 的两个具名 Fatal(见 §3);枚举对齐用 static_assert 钉死而非强转 |
| `.../Server/ServerLoop.{h,cpp}` | **单槽邮箱的载荷从"函数指针 + 栈上 void\*"换成按值携带的一个帧**。`RunOnApplyThread(ControlWork, void*)` → `RunSurfaceControlFrame(SurfaceControlFrame&)`;十二个 forwarder 的 Args::Run 本体逐字搬进成员分发 `ApplySurfaceControlFrame`(C7/ID-54 分类、N-3 遗忘、R-12 重发布全部原位保留);阻塞握手、影子位、publish-then-ring、C2 出口块全部不动。测试缝:`RunProbeOnApplyThreadForTesting`(hook 是成员变量,**不进槽位**) |
| `MG_Test/Wire/SurfaceControlFrameTest.cpp` | 新套件 9 用例(见 §3) |
| `MG_Test/Wire/ServerLoopTest.cpp` | 既有用例 5 处迁移到 probe 缝;新增 2 用例(见 §3) |
| `MG_Test/Wire/RemoteClientTest.cpp` + `RemoteClientControls.inc` | 18 + 11 处 `RunOnApplyThread` 调用点机械迁移到 probe 缝(lambda 签名逐字兼容) |
| 根 `CMakeLists.txt` / `MG_Test/Wire/CMakeLists.txt` | 两个新源文件进 disagg 闭包;新套件按既有"加一个 NAME"约定注册 |
| 文档 | ROADMAP.md G4 行(f0-egl F9 的行号修正 + 去向改为"已由 P5f fc 帧化");P5F 计划进度行与 §2.3 标注;P6-CONTRACT-DRAFT §1/§4 与 P6-SPAWN-PLAN 第 4 条改为"fc 已落,P6 只剩传输";CONTRACT-P5E 两处 ServerLoop.cpp 行号随动 |
**grep 证明**(验收项):`grep -rn "ControlWork\|m_controlWork\|m_controlUser\|RunOnApplyThread"
MobileGL/ --include="*.h" --include="*.cpp" --include="*.inc"` → **0 命中**;邮箱槽位类型是
`SurfaceControlFrame m_controlFrame;`(按值,`ServerLoop.h:412`),其无指针约束由
`SurfaceControlFrame.h` 的穷举成员检查钉死;仅 trivially-copyable 并不能拒绝指针(§8)。披露:测试缝的 `m_controlProbeHook` /
`m_controlProbeUser` 是 ServerLoop 的**成员**而非槽位内容(同 `m_beforeRetireHook` 的既有先例),
只在 `ProbeForTesting` kind 的分发臂被读。
### 与 f0-egl 的逐条核对
- **9 个 forwarder / 10 种 op 帧化** ✔(含 `ReleaseCurrent` 复用:`ServerMakeEGLCurrent` 在打包侧按
三 NO\_\* 形状拆出 `ReleaseCurrent` kind,分发到达同一个 `ApplyMakeCurrent` ClientRelease 臂)。
- **死代码不帧化** ✔(按 F8 的"标注 inproc-only"臂):`ServerSwapEGLBuffers` / `ServerInitWindowSurface`
与 `ServerInitCapabilities` 拿的是 **inproc-only kind,codec 拒绝编码它们**
(`InprocOnlyOpOnTheWire`)。它们仍走帧通道是因为函数指针邮箱已整体拆除,而 G14 禁止删它们的
钉住用例。这是与 f0-egl 字面建议的唯一偏差,理由是它自己的 F8 给的第二条路。
- **`ANativeWindow*` 具名拒绝** ✔:wire 解码入口 `Fatal{UnmigratedSurface, "AndroidNativeWindow@P12"}`
(P6-CONTRACT-DRAFT 预写的名字);inproc 路径不受影响(Android 同进程照常)。
- **`SurfaceReply.defaultFb` 不启用** ✔(f0-egl §4.4 路线冲突的二选一):默认 FBO 形状已由
SEG_EVENT `kEventSurfaceChanged` 承载,回复帧不回写它。契约草稿 §4。
- **发送纪律**(f0-egl §3):`WaitForApplyBeforeEglForwarder` 原样保留;契约草稿 §2.2 写明它在
spawn 下仍是硬要求。
## 2 双块车道:fc 名下的红
**零。** `dualblock-expected-fatals.txt` 的 6 对首阻塞全部是 `PipeInputs` 字段的 BARRIER_PULLED
读(GetFramebufferBindingSlot@ReadPixels 等),与 EGL 控制面无交集——双块机关探的是
`gPipeInputs` 的读侧,邮箱/帧通道不经过它。fc 的对应义务是**普查不变**:旋钮开的车道在 fc 前后
产生同一对集(逐门数字见 §5),棘轮文件未动。fc 自己的红一次对照见 §4。
## 3 新增测试(G14:只增不删)
`SurfaceControlFrameTest`(9):帧是纯值聚合(trivially-copyable);十个帧化 op 恰好有 wire
kind 且数值钉死(8/9/10 与 MetalLayer=6 是 wire ABI);WindowBackend↔WindowKind 双向显式表
(含"两枚举整数值错位"的防强转断言);十 op 逐个过真 `CtrlEnvelope{SurfaceOp}` 字节往返
(readSurface/context 在内);SurfaceReply 往返(seq 回声 + 版本号);inproc-only 与畸形帧的
编码拒绝;无后端 windowKind 的解码拒绝;**两个 fork 死亡用例**钉住 wire 入口的具名 Fatal。
`ServerLoopTest` +2:`AVoidForwarderCrossesAsOneDispatchedFrame`(无 backend 时
`ServerSetEGLSwapInterval` 仍恰好分发一帧——帧通道自己的 R-16 扳机);
`ServerLoopEglTest.TheInitializeDisplayReplyArrivesThroughTheFrame`(major/minor 以**回复字段**
而非栈指针回到调用方,mesa 真实版本号佐证)。
既有钉住用例全部保留并经帧路径驱动:C7 的 native bind 计数(`readSurface`/`context` 字段若丢,
0x1 句柄会变 0 → ClientRelease 误分类 → NativeBindCount 不动 → 红)、N-3 的 destroy-recreate、
ID-67 的重发布计数、M-7/C2 的两个 !m_running 臂、影子位双清用例。
## 4 R-16 阴性对照(真跑过一次)
在 WSL 门树(未提交)把 `ServerSetEGLSwapInterval` 的投递行改成 `(void)frame;`(forwarder 不再
过帧通道),重链 ServerLoopTest:
- **红**:`ServerLoopTest.AVoidForwarderCrossesAsOneDispatchedFrame` Failed,失败文本正是该用例
自己的断言——`loop.ControlFramesDispatched()` Which is: **0**,expected 1
("the forwarder reached the backend (or did nothing) without crossing the frame channel")。
- 还原后同一条目转绿(`100% tests passed, 0 tests failed out of 1`)。
## 5 逐门数字(WSL 门树 `~/w7/p5f-fc`,split flavour,逐条实跑)
| 门 | 结果 |
|---|---|
| build(split flavour) | rc=0(全量 915+ TU;增量修订后最终全绿) |
| unit(旋钮关) | **2273/2273**(f1 基线 2262 + 本包新增 11:SurfaceControlFrameTest 9 + ServerLoopTest 2;G14 只增不删,无标签前缀误伤——未新增任何标签,`SurfaceControlFrameTest` 名集合与既有名无前缀关系) |
| integration-split(旋钮关) | **179/179**,零回归 |
| strict(旋钮关) | 179/179 绿、`Fatal{` 为 0、观测 Admitted 恰为既有 8 对(7 admitted + 1 escalated)。双向棘轮仍报 f1 §8.1 记录的**基线既有** 2 行 stale(`GetBoundVertexArray@DrawArrays`、`GetBufferBindingSlot@DrawArrays`)——与 fc 无关,f1 已归因基线树逐字复现,修复属 strict 车道养护 |
| 双块 census(旋钮开) | 181 条目:**155 红 / 22 绿 / 4 skip,与 f1 初版逐对逐数相同**(132/11/6/2/2/2 六对),`expect-fatal: ratchet OK - 6 fatal pair(s), zero admitted, every red entry named`。**棘轮文件零改动**——fc 名下无红(§2) |
| R-16 阴性对照 | 见 §4(改回即红、还原即绿,各真跑一次) |
| flavours | pull rc=0(915 TU,`MOBILEGL_PIPE_PUSH=1` absent ✓)、push rc=0(929 TU,=1 ✓),compile_commands.json 断言过 |
| **G1**(pull 对基线 `~/w7/p5f-base` @ e75e00cb) | `.text` 10806051 → 10806051(+0);defined symbols 27815 → 27815,**0 added / 0 removed / 0 resized / 0 renamed**——零认定 |
| gens | gen_pipe --check/--self-test、field-ownership(fc 未动 FieldOwnership.def,仍跑)--check/--self-test、dirty-surface --check/--self-test、include 闭包 4 probes 全绿;**protocol 重生成对提交头零 diff**(pinned flatc 25.12.19);doc 引用 --strict 恰为基线既有 2 处 ambiguous(CONTRACT-P5.md:349/:524,f1 §8.2 同此),fc 新增 0 处 |
| integration-gpu | 按任务分工由集成者跑,本包未跑 |
注:f1 §8.4 的教训已遵守——census 与其他车道串行跑,无私有日志覆写。
## 6 附带发现(未修)
1. `p5f_new.sh` 按 SHA fetch 在源仓未开 `uploadpack.allowAnySHA1InWant` 时失败
("couldn't find remote ref");fc 改用按分支名 fetch(`git fetch <gitdir> p5f/fc`)。
建议脚本照改或源仓开 `allowTipSHA1InWant`。
2. `git submodule update --init --recursive` 在新建 worktree 上反复超时(嵌套子模块走网络);
fc 从同父提交的 `~/w7/p5f-f1` 树整体拷贝 submodule 工作区并改写 gitdir 指针解决。
脚本那行 `cp -a .../glslang/External` 掩盖了这一点(它只补了 glslang 一家)。
3. `p5f_gate.sh` 的 build 步以 `[ $rc -ne 0 ] && grep ...` 收尾,成功时脚本退出码是 1
(日志行 `build rc=0` 才是真相)。既有噪音,未动。
## 7 预期合并冲突点
- `MobileGL/MG_Test/Wire/CMakeLists.txt` 的套件清单(文件自述为"本阶段反复冲突点",按
"加一个 NAME" 约定解)。
- `ServerLoop.{h,cpp}` 与 `RemoteClient{Test,Controls}`:若有并发包碰 apply 线程或角色守卫
测试(fm 的 Clear 臂不改这里;fv 若动 `RunOnApplyThread` 调用点则须平移到 probe 缝)。
- `protocol.fbs` 与 `protocol_generated.h`:若并发包也动 schema,枚举/字段追加序须人工保
append-only 后重生成。
- `docs/Disaggregated/ROADMAP.md` G4 行、`P5F-WIRE-COMPLETENESS.md` 进度行、`P6-CONTRACT-DRAFT.md`
§4:文档同点编辑。
## 8 集成前局部复审修复(2026-09-19)
本节追加独立修复,§5 的全门数字保留为初版历史;本次只重跑受影响测试,集成全门由集成者负责。
这次局部复审不代替 P5f 不同模型族终审。
| 缺陷 | 修复与回归用例 |
|---|---|
| wire `seq` 在真实 dispatch 入口被重新 mint,codec-only 往返漏检 | 仅 `seq==0` 的本地帧 mint;wire 序号保留。`WireSequenceSurvivesRealDispatchAndFailureReply` 驱动 wire → apply → reply 编码,要求无 backend 的失败回复仍回声 4242;成功臂亦断言原序号。 |
| 4 个 void 成功臂未填 `ok`,编码成 `false` | `SetSwapInterval` / `ReleaseSurface` / `ReleaseResources` / `SetWindowHandle` 完成后写 `ok=true`。`SuccessfulVoidWireOperationsReplyWithSuccessAndOriginalSequence` 用真实 EGL backend 驱动四种 op 并检查实际编码回复。 |
| MetalLayer 与 Android 一样携带客户端对象地址,却未拒绝 | `DecodeWireSurfaceOp` 对两种 window op 都返回 `MetalLayerArrived`,入口具名 Fatal `MetalLayer@P12`;新增纯解码检查与死亡用例。 |
| trivially-copyable + standard-layout 不能排除指针;初版的机械证明错误 | constexpr 结构化绑定穷举 14 个字段,每项只准 integral/enum。添加任何成员而不更新绑定会编译失败;将既有字段改为指针会触发 static_assert。保留旧两个 trait,并加入 object/function pointer 的 constexpr 反例和新用例。 |
| probe hook/user 在 `m_callerMutex` 外写,可被并发或重入 probe 覆盖 | 发布移入 caller 临界区,锁覆盖整个握手;apply 线程重入用调用栈上的 hook/user 参数,不写共享 pair。8 个并发投递者各 128 次,每次再嵌套一个 probe,逐投递者计数并校验总分发数。 |
真实 dispatch 测试还暴露 `SurfaceOpCodec.h` 的 include 顺序问题:`Wire::` 会被既有
`MG_Remote::Wire` 命名空间遮蔽;已将公开声明限定为 `::MobileGL::Wire::`。
**G14**:原测试全部保留,新增 5 条(SurfaceControlFrameTest +2、ServerLoopTest +2、
ServerLoopEglTest +1)。两目标 `cmake --build build-split --target SurfaceControlFrameTest ServerLoopTest -j8`
通过;`MOBILEGL_ITEST_REQUIRE_GPU=1 ctest --test-dir build-split -R
'^(SurfaceControlFrameTest|ServerLoopTest|ServerLoopEglTest)[.]' --output-on-failure -j8`
**42/42 通过,零 skip**。probe 的另外两组调用者也已覆盖:重建 `RemoteClientTest`,
`RemoteClientControls` **26/26** 与该可执行文件的其余 8 套件 **116/116** 全绿,
合计本次相关 unit **184/184**。
**真实 red-once,全部在 WSL 验证副本修改并还原,没有提交故障代码:**
| 单独回退 | 红证据 |
|---|---|
| seq 恢复无条件 mint | `WireSequenceSurvivesRealDispatchAndFailureReply` 失败:回复 1,预期 4242;ctest rc=8。 |
| 删除四处 `frame.ok=true` | 四种操作均报 `successful void operation encoded failure`;ctest rc=8。 |
| 删除 MetalLayer 解码拒绝 | 解码错误码不符,死亡测试 `failed to die`;ctest rc=8。 |
| probe 恢复锁外共享 pair 发布,并让重入读共享 pair | 并发+nested 用例逐投递者计数不符,报 `another poster or nested probe replaced this hook/user pair`;ctest rc=8。 |
| 额外新增第 15 个指针成员但不更新检查 | 用真实 SurfaceControlFrame.cpp TU 的 compile_commands 编译参数执行 `-fsyntax-only`,编译失败:`binds to 15 elements, but only 14 names were provided`,rc=1。 |
| 将既有 nativeToken 改为 void* | 同样的真实 TU 编译失败,正是 `every surface control frame member must be an integer or enum` 断言,rc=1。 |
还原后两目标重建通过,相关测试再次 **42/42 绿**。日志在 WSL
`/tmp/p5f-fc-fix-{red-seq,red-ok,red-metal,red-probe,red-added-member,red-pointer-type,restored-green}.log`。
第一次编译负例的检查脚本预期了另一种编译器措辞,实际已按正确原因编译失败;修正日志匹配词后
单独重跑两个编译负例并恢复验证,没有重跑无关门。
WSL 旧门树 HEAD `7257a372` 与 Windows `d5ed139c` 为兄弟提交,仅报告不同,不能 ff-only。
本次仅覆盖已确认无本地修改的 7 个相关源/测试文件验证,未 reset WSL 树,未改动其既有子模块状态。