[Docs] (P11 C): the contract's A1/A2 sections, Config.h's GPU-ordered landing, Init.cpp's DirectVulkan resource table, and the stream refusal CONTRACT-P6 / design 06 / 07 claimed now cites its code

This commit is contained in:
2026-09-29 07:23:41 -04:00
parent 2a902cbd79
commit 82467823ef
6 changed files with 73 additions and 13 deletions
+11 -7
View File
@@ -202,9 +202,12 @@ namespace MobileGL::MG_Config {
// persistently+coherently mapped storage at definition time (negative control /
// escape hatch). Frontend-scoped: it engages only where the active backend
// provides AcquirePersistentMap. With adoption on, an app SubData into a busy
// 128MB arena is a plain memcpy into GPU-visible memory; every driver-mediated
// route for the same write stalls the thread or ghost-copies the whole arena on
// this class of Mali driver, and the arena stops costing its size again in RAM.
// 128MB arena lands GPU-ordered through the backend's resident-subdata op
// (BufferObject::LandBytesIntoResidentStore, since 0ee3384b: an in-place write
// tore the frames still reading the old bytes) - still no driver-mediated write
// into the busy mutable store, which on this class of Mali driver stalls the
// thread or ghost-copies the whole arena, and the arena stops costing its size
// again in RAM.
Bool DisableLargeBufferAdoption = false;
// MOBILEGL_ESPRYT_FORCE_DS_READBACK_EMULATION: make DirectGLES skip the native ES
// depth/stencil reads and always go through the shader-sampling emulation. Core GL
@@ -610,10 +613,11 @@ namespace MobileGL::MG_Config {
// poll loop cannot outlive a late report. 0 = every poll crosses, as before P10: the A/B
// arm and the red-once of the no-reply gate (FencePollScenario).
Uint32 PollEscalate = 64;
// MOBILEGL_IPC_ADOPT_TIER: 2 = emulate (client keeps the shadow and pushes), which
// is the only tier P5 implements and the reason persistent-map-push can be non-zero
// at all (R-6). 0 and 1 parse and are Fatal at use with "P11"; they exist now so the
// negative control has a spelling the day P11 writes it.
// MOBILEGL_IPC_ADOPT_TIER: 2 = emulate (T2: client keeps the shadow and pushes), the
// only implemented tier and the reason persistent-map-push can be non-zero at all
// (R-6). 0 (T0) and 1 (T1) parse and are settled at the handshake (P11 A1,
// MG_Remote/Transport/AdoptTier.h): a stream data plane refuses them by name and runs
// T2; over shared segments the client dies by name before any record.
Uint32 AdoptTier = 2;
// MOBILEGL_IPC_VERB_BARRIER: 1 = the client blocks at every verb boundary until
// appliedSeq reaches its emitSeq (R-1). 0 is the negative control: it is EXPECTED to
+4 -3
View File
@@ -81,9 +81,10 @@ namespace MobileGL::MG_Backend {
// DirectGLES consumes all thirteen migrated families (P2's 0..6, P3a's 7..8, P4a's
// 9..12): it registers the resource op table in Initialize()
// (BackendObject_DirectGLES.cpp:849) and reads every other family out of gPipeInputs.
// DirectVulkan registers NO resource ops - MGPipeSetResourceOps has exactly one caller
// in the whole tree and it is Managers.cpp:2594 - so bit 7 is CLEAR for it, which is
// the same fact ObjectSubsystemControlScenario already pins from the client side.
// DirectVulkan registers its wire resource op table off monolith only
// (VkBufferManager::RegisterWireResourceOps, VkBufferManager.cpp): under a transport it
// owns buffer stores and claims bit 7 (the P4a mask, see ConsumedSubsystemsFor below);
// under monolith it registers none and its buffers keep the legacy BufferBackendOps path.
// P5e (MG_Remote/CONTRACT-P5E.md §6.2). THE ONE CONSTANT THE WHOLE PHASE HANGS ON.
//
// kCapRunAheadApply says "this server applies an unbarriered record without reading
+54
View File
@@ -0,0 +1,54 @@
# P11:persistent map 采纳档位诚实化(A 包主机半)
2026-09-29。依据 [`PLAN-P11.md`](../../docs/Disaggregated/notes/p11/PLAN-P11.md) §2 的 A1、A2 与 C 的文档修正。档位名按 `design/07`:T0 = client 分配 `AHardwareBuffer`、server 导入;T1 = server 导出 opaque fd;T2 = 拒绝,client 保留 shadow 并推送。本文只记实现所需的行为与门;A3 / A4(设备)与 B(T0)不在本文。
## 范围
档位在握手时定下(§1);断言 arena 落在哪一档、三臂登记(§2);文档漂移(§3)。
## 1. 档位由知道数据面的一侧在握手时定下(A1)
### 线上格式
- 无变化。LinkTerms、`RefuseCode`、控制协议修订号(3)都不动:每一侧只判自己的旋钮,不需要把档位带过线。
### 规则(`Transport/AdoptTier.cpp` `SettleAdoptTierAtHandshake`)
| 数据面 | 侧 | `MOBILEGL_IPC_ADOPT_TIER=0/1` |
|---|---|---|
| Stream(tcp) | client / server | 一行 W `Refuse{AdoptTierOnStream, "T<n>"}`,本会话 T2;从不 Fatal |
| SharedSegments(inproc、fork / unix spawn) | client | `Fatal{UnimplementedAdoptTier, "T<n>"}`,握手期、任何记录之前 |
| SharedSegments | server | 一行 W(档位由 client 定),T2 |
- 调用点:client `StartOverTransportPair`(Welcome 校验后)与 `StartOverSocket`(link terms 定下 `stream` 后、开数据连接前);server `ServerSession::Accept`(后端检查后、Welcome 前)。
- 使用处 `Client::AdoptTierIsEmulate`(`PipeApply.cpp`、`PipeWireCodec.cpp` 仍问它):旋钮 2 → true;本进程已有握手定档 → true,不再打印;没有握手定过档的调用者 → 仍 `Fatal{UnimplementedAdoptTier}`("no handshake settled")。旋钮 > 2(解析器不收)→ Fatal。
- `ServerSpawn` 从它拉起的子进程环境剔除 `MOBILEGL_IPC_*`(五个 server 自有旋钮除外),所以 fork / unix spawn 的 server 看不到 client 的旋钮;tcp 的 server 读自己的环境。
### 普查
新的死亡走 `SessionFail`:abort 站点仍 79,family 词仍 45(复用 `UnimplementedAdoptTier`);refusal 词 3 → 4,`AdoptTierOnStream` 进 `fatal_census.py` 的 `LOCAL_REFUSAL_WORDS`(本地拒绝,不成为 Refuse 帧)。
### 门
- 单元:`AdoptTierStream.*`(真 tcp 会话:client 0/1 → 会话起、一行拒绝、`map_persistent` 得 DECLINED、之后仍 apply;进程内显示 server 0 → 每会话一行、不死);`RemoteClientControls.AdoptTier{Zero,One}OverSharedSegmentsDiesAtTheHandshakeBeforeAnyMapPersistent`(inproc 真握手,子进程在 `Start` 返回前死、具名);`SplitBufferSet.OnlyAdoptTierTwoIsImplemented`(函数级矩阵);`PipeWireCodecTest.AdoptTier{Zero,One}AfterAStreamHandshakeIsADeclineOnTheWirePath` 与 `AnUnsettledAdoptTierStillDiesByNameOnTheWirePath`。
- 集成:`{DirectGLES,DirectVulkan}.Tcp.AdoptTier0.LargeArenaAdoptionScenario.*`(`MOBILEGL_IPC_ADOPT_TIER=0`;`integration-tcp` / `integration-magma-tcp`),`AStreamSessionRefusesTheAdoptTierOnceByName` 读 client 日志恰一行,其余用例绿。tcp 专属:共享段上同一旋钮在握手期死(`spawn_lane_parity.py` 的 `MAGMA_TCP_ONLY`)。
- red-once:删 Stream 分支 → 两后端 tcp 条目 client 握手期 `Fatal{UnimplementedAdoptTier}`、无拒绝行,单元 `AdoptTierStream` 两例、codec 两例、`SplitBufferSet` 一例红;把检查挪回使用处 → inproc 会话起来、`map_persistent` 发出后才在 apply 线程死(子进程写出 `S`),spawn 臂则静默跑 T2(server 环境被剔除)。
## 2. arena 落在哪一档(A2)
- `LargeArenaAdoptionScenario.TheArenaLandsInTheTierItsLaneDeclares`:`PersistentMapPeek` 读 arena 的 `IsBackendPersistentMapped`,与车道的 `MGITEST_PERSISTENT_MAP_ARM` 比;问两次(NULL 定义后;一帧绘制 + SSBO 绑定 + dispatch 后)。未声明的车道跳过。
- 声明:monolith = adopted(`DirectGLES.ResourceSubsystemOn/Off.`、新 `DirectVulkan.ArenaArm.`,都钉 monolith);split = emulated(Espryt 三臂经 `SplitLogPaths` 按条目声明;Magma `Arena.` 块与 Buffers 车道)。
- 登记:`mgl_itest_register_split_arms("LargeArenaAdoptionScenario.*")`(Espryt 进门、Magma 进信息层);Magma 进门:`DirectVulkan.<arm>.Arena.`(band 口味,六例)与 Buffers 车道(加六例,`test.yml` 的 require-green 名单同步)。
- red-once:monolith 车道加 `MOBILEGL_DISABLE_LARGE_BUFFER_ADOPTION=1` → 三条红;split 车道改声明 adopted → 两后端 8 条红。删 `PipeApply.cpp` 的 R-6 拒绝**不会**让 Espryt inproc 采纳(实测仍 emulated):split 下 client 的采纳门经线路走,codec 不调 applier 就答 DECLINED;applier 只在 server 角色自己发射时被问到(只有 Magma 的 `EnsureGpuResidentStorage`),而 Magma 的线路表 `MapPersistent` 恒返回空。
## 3. 文档漂移(C)
- `Config.h`:大 buffer 采纳下的 SubData 自 `0ee3384b` 起经 resident-subdata GPU 有序落地,不是"plain memcpy"。
- `MG_Backend/Init.cpp`:DirectVulkan 在非 monolith 下注册线路资源表(`VkBufferManager::RegisterWireResourceOps`)并声明 bit 7。
- 档位命名按 `design/07`:`PersistentMapTracker.h` 注释已改。`protocol.fbs` 的 `Adopt = 6 // server-owned adopted store` 注释**没改**:`protocol_revision_pin.py` 对整文件取 sha256,改注释要 bump 修订号。
- `CONTRACT-P6.md`、`design/06`、`design/07` 的"stream 上具名拒绝"现为真,已指向本节代码。
## 不变量
- G1:新代码全在 `MOBILEGL_BUILD_DISAGGREGATED` 下(`MG_Remote`)。
- 线上格式与控制协议修订号不变(3)。
+2 -1
View File
@@ -673,7 +673,8 @@ readback and the reply-slot pool (P9); `DynamicBackendParameters`' fixed-width r
**The two-axis transport stack — control × data, TCP-capable, cross-build — is P6.5** and is the
IPC track's next stage (§10.3). P9 builds its reply semantics on P6.5's message replies rather than
on a slot pool, and P11's T0/T1 are refused by name on a stream data plane.
on a slot pool, and P11's T0/T1 are refused by name on a stream data plane (landed by P11 A1 at
the handshake: `Transport/AdoptTier.cpp`, `SettleAdoptTierAtHandshake`; CONTRACT-P11 §1).
**Untrusted-guest hardening is `Ph`**, and it must land before any shipping server app accepts a
connection from a guest it did not produce — including the `Fatal`-policy flip (§5.2), the
handle-slot budget, and the caps in §12.
+1 -1
View File
@@ -12,7 +12,7 @@
| `SEG_STAGE` | client | 32 MiB | bulk 字节:buffer / 纹理 subdata、UBO、client 数组、persistent-map 脏块 |
| `SEG_REPLY` | server | 16 MiB,8 × 2 MiB slot | readback 像素、acceptance 答案(ID-47) |
| `SEG_EVENT` | server | 256 KiB SPSC ring | 回调事件 |
| `SEG_SHADOW` / `SEG_ADOPT` | client / server | — | 零拷贝 shadow(Phase 2)/ ≥16 MiB 采纳(P11);stream 数据面上具名拒绝 |
| `SEG_SHADOW` / `SEG_ADOPT` | client / server | — | 零拷贝 shadow(Phase 2)/ ≥16 MiB 采纳(P11);stream 数据面上具名拒绝(`MG_Remote/Transport/AdoptTier.cpp`,握手期,P11 A1) |
段在同机上由 `ShmSegment` 创建(Android `ASharedMemory`、Linux `memfd`、Windows `CreateFileMappingW`),描述符经 `SCM_RIGHTS` 传递;stream 数据面上两端各持一份同尺寸的私有段(§11.9)。
@@ -10,7 +10,7 @@
|---|---|---|
| T0 | client 分配 `AHardwareBuffer` BLOB,server 导入(Vulkan / GLES) | 唯一在两台设备、两个后端上都完整读写的档(P11 主攻) |
| T1 | server 导出 opaque fd | 仅 Adreno 的 Vulkan 路径 |
| T2 | 拒绝,client 侧推送 | 永久正确回退;**今天 split 用的档**(`MOBILEGL_IPC_ADOPT_TIER=2`),stream 数据面上强制 |
| T2 | 拒绝,client 侧推送 | 永久正确回退;**今天 split 用的档**(`MOBILEGL_IPC_ADOPT_TIER=2`),stream 数据面上强制(P11 A1:两端握手时 `Transport::SettleAdoptTierAtHandshake` 对 0/1 打一行 `Refuse{AdoptTierOnStream}` 并走 T2;共享段上 client 握手期 `Fatal{UnimplementedAdoptTier}`,[`CONTRACT-P11.md`](../../../MobileGL/MG_Remote/CONTRACT-P11.md) §1) |
T2 下 client 侧推送三件套:不做 map/unmap 命令对(payload 带 `hasLiveHostWrites`);在每个 validate 点按块(`MOBILEGL_IPC_PERSISTENT_BLOCK_KB`,默认 64)推送可达的已映射 buffer,脏页追踪 + 哈希抑制只发变化的块(P5d);门 `PersistentCoherentMapScenario`。`mpr` 数的是每一次 `MapPersistent` 发射(铸成或拒绝都算),所以在 monolith 下也可断言。