Files
MobileGL/docs/Disaggregated/design/05-backend-and-server.md
T

6.7 KiB
Raw Blame History

后端改造与 server 侧(原 ARCHITECTURE §9–§10)

设计细节。设计要点与全部章节的索引见 ../ARCHITECTURE.md。章节编号沿用原 ARCHITECTURE.md,代码注释里的 ARCHITECTURE.md §N 按编号在这里找到。

9. 后端状态机改造

9.1 原样不动的东西

Espryt 的 persistent ring、buffer pool、fallback-repack、scratch FBO、驱动绑定影子、Adreno / Mali workaround、SPIRV-Cross 会话、restart 重写与 multi-draw 分档;Magma 的 VulkanRenderer memo、PipelineFactory、ProgramFactory、UniformManager、五个 Vk*Manager、SwapchainObject、D18 的节点式容器纪律。"输入变了、算法不许动"的那一类由 G5 字节一致门把关(scripts/p3a_untouched_regions.sh 十一函数、scripts/p4a_untouched_regions.sh 17 区),re-pin 必须两份同改。

9.2 strangler 脚手架:PipeInputs + 逐 verb 填充 + poison 世代(P1)

// MG_Backend/MGPipe/PipeInputs.h —— 按 memo 键组织,访问器类型与后端原来读到的完全一致
#if MOBILEGL_PIPE_PUSH

#### 9.2.1 server 侧的 verb 戳与读检查

client 的残余填充在自己的 verb 边界给全部字段盖戳,server 读 `PipeInputs` 前必须换成自己的戳:与 client 共用一块时,不清零则每次读都“新鲜”、`rsp` 恒为 0,门形同虚设;两块分开时,没有戳则第一次读就中止。

- 盖戳点:`PipeApplier::StampVerbBoundary` 只在 `MGPipeVerbForWireOp`(`FieldOwnership.def` 的 `MGP_VERB_OP_LIST`)映到 verb 的 op 上调用 `MGPipeServerStampVerbBoundary`:递增 `CurrentVerbSerial`、记下 verb,给该 verb 类可读掩码(`FillPoints.def`)内的 `RECORD_SUPPLIED` / `APPLIER_DERIVED` 字段盖新戳,其余字段戳清零(“从未填充”先于 sticky 判定,所以清零也取消 sticky 豁免)。
- 非边界记录(如两次 draw 之间的 `set_dynamic_state`)不盖戳,沿用前一边界的序号、掩码与 verb 名,但盖戳标志已在上一条记录后清除,读检查按盖戳之外处理;20 个 draw 入口都盖成 `DrawArrays`,掩码正确,Fatal 里的名字是泛称。
- 读检查只在 server 盖戳的 verb 内按归属类(§3.1 的 G8)分流:`RECORD_SUPPLIED` / `APPLIER_DERIVED` 读到旧值是 `Fatal{RoleViolation}`,`FATAL` 直接中止,`BARRIER_PULLED`(仅供生成器对照,没有生产行)在该 verb 类内计入 `rsp`,由 `CountBarrierPull` 决定何时改为中止(记录未 barrier、两角色用不同块、strict 下未准入)。盖戳之外一律是普通 poison `Fatal{UnmigratedPipeInput}`。
- 盖戳标志由 `PipeApplier::LeaveApplier` 在每条记录之后清除;server 进程里没有 client 半边替它清,漏清会让之后的读都按上一个 verb 的掩码判定。
#  define MGB_CTX (&::MobileGL::MG_Pipe::gPipeInputs)
#else
#  define MGB_CTX (::MG_State::pGLContext)
#endif

三步:A 别名(P1,机械替换 + 逐 verb 类填充点,nm 不变)→ B 推送(P2,tracker 填 gPipeInputs,verify 构建逐 draw 比对快照版)→ C 句柄化(P3a–P4a、P7,SharedPtr<前端对象> → 句柄 + 描述符,写回变回调)。poison 是逐 verb 世代:读一个当前 verb 未填的字段是 Fatal{UnmigratedPipeInput, "<Getter>@<Verb>"}。

P13 收尾:pull 分支与宏一起删掉(W3b,MGB_CTX 不再存在,后端只经 gPipeInputs 与 applier 记录取状态);单进程也走记录臂(W4–W5),后端的前端对象臂与前端键 twin 入口删除(W6)——Espryt 的 twin 表只收 client 铸好的句柄,对象死亡通知带句柄、按句柄释放(与 server 的 object_death 同一释放)。

9.3 Track V / Track H

Track V(值类型:render state、pixel store、capability 位、标量)是机械迁移;Track H(167 个 SharedPtr<MG_State…> 读点)是真活。74% 的读点是翻译输入,所以"bump 一个版本让 server 自己拉"行不通,值本身必须过去。

9.4 残余值块

迁移期临时调用 SetResidualValueState(ResidualValueBlock):尺寸只降不升(1248 → 8,只剩 CapabilityBits),P13 W3c 删除——op 46 退役为拒绝行,capability 交叉核对交给 verify 比较器;set_context_values 携带剩下的值类字段(单进程也发,W4d / W8)。

9.5 身份 memo 的重键

{slot, gen} + 显式 destroy 让 21 条身份 memo 中 11 条直接删除、2 条的去抖搬到 client(§5.4)、7 条重键成更便宜的比较、1 条(D18)不动。统一事实:进 memo 键的版本计数器要么会回绕,要么根本不被它害怕的 mutation bump,身份比较是堵洞的补丁。

9.6 A/B 与口径收窄

MOBILEGL_PIPE_PUSH 子系统位图在阶段 B 是真 A/B;阶段 C 之后位清零时后端仍跑重键后的代码,所以编译期 MOBILEGL_PIPE_LEGACY_MEMOS 曾保留 pre-handle 臂。P13 结束了这段:LEGACY_MEMOS 与 pre-handle 臂删除,位 0–13 固定开、清位即启动期具名拒绝(原 Off 车道改为这条拒绝的阴性对照),只剩位 63 可设。位依赖两侧都拒(客户端族门里根本不发射,否则会"客户端已清 dirty、服务端却走旧臂"而丢上传);没有消费者的后端一条不发。

10. server 侧

10.1 对象表与 applier

MG_Remote/Server/PipeApplier:解码 → 更新对象表与 PipeInputs → 调后端。单进程(P13 起)是同一记录臂少了编解码与环:状态记录经 PipeRoute 的单进程表直进 applier,verb 记录由 MG_Impl/Pipe/Verb 的发射器交给本进程的 MG_Backend/Record/RecordVerbSink。server 不持有 buffer 的完整副本(只有 staged shadow)、不持有前端对象图;任何传输下都不得有 SharedPtr 或裸前端指针跨过 applier 边界(P5c 角色守卫、P5e 规则 F)。InProcessTransport 与 spawn 走完全相同的编解码路径。

10.2 monolith 侧的净收益

即使 IPC 永不上线:复用地址 ABA 一整类不可表达;FBO → program 排序 hazard 消失;SwapchainObject 写 MG_Impl 的分层倒置消失;inproc = 渲染线程。monolith 净代码量是增加的,论据只看逐线程 CPU。

10.3 索引宿主镜像(Server/IndexHostMirror,P8,待重裁)

设计:kCapNeedsHostIndexBytes 下,server 从本来就要收的 ResourceCreate/Respecify/SubData 流增量维护 element-array buffer 的宿主镜像,零额外流量;预算 MOBILEGL_PIPE_INDEX_MIRROR_MB(默认 64),超预算退化为逐 draw 经 MGHostSpan 传送。P6 的 a6 审计实测宿主索引 span 无 producer、client 索引已是 owned buffer,所以 P8 要按真实消费者重新裁定,不照抄本节(docs/archive/notes/p8/README.md)。