[Chore] (docs): Remove orphaned CS_Refactor notes accidentally committed in 4e48702f2

This commit is contained in:
2026-09-28 21:16:35 -04:00
parent 884f6aac96
commit 3bdd565dc6
3 changed files with 0 additions and 413 deletions
@@ -1,63 +0,0 @@
# FCL Integration Checklist (MobileGL C/S, FCL 0 改动)
> 状态:代码完成态(phase 2,禁用 shell,未编译/未真机)。
> 目标读者:MobileGL 核心开发者 + 验证者。本文件把 FCL 启动全链路与 MobileGL
> 组件逐点划上钩,并记录已知不支持面(以 `generated_trampoline_coverage.txt` 为准)。
## 1. 启动链路逐点映射
| # | FCL 行为(来源) | MobileGL 组件 | 状态 |
|---|---|---|---|
| 1 | 安装渲染器插件 APK(`top.mobilegl.plugin`) | `android-plugin/app`(`:MobileGL` 产 `jniLibs`) | ✅ 配置完成 |
| 2 | 校验 `renderer` / `pojavEnv`(`PluginNativeLoadGuard.verifyRendererLibraries`) | manifest: `MobileGL C/S:libMobileGL_Client.so:/libMobileGL_Client.so` + `DLOPEN=…` | ✅ |
| 3 | `LD_LIBRARY_PATH` 指向插件 native 目录 | 无需客户端特殊处理 | ✅ |
| 4 | `DLOPEN` 依序加载 FullServer/UtilRuntime/BackendObject | `mobilegl_fullserver_create` 再用同路径 `dlopen`(幂等) | ✅ |
| 5 | dlopen `glLib` = `libMobileGL_Client.so` | `ClientTrampoline` 首次调用 → `InitializeFromEnvironment()` | ✅ |
| 6 | `-Dorg.lwjgl.opengl.libname=…` | LWJGL 加载 Client `.so`,经导出 `egl*`/`gl*` | ✅(受支持子集) |
| 7 | 游戏线程调 `eglGetDisplay/Initialize/CreateContext/MakeCurrent` | M1 EGL trampoline(DisplayCreate/GroupCreate/SessionCreate + `SetCurrentSession`) | ✅ |
| 8 | 游戏调 GL 命令 | `generated_wire_trampoline.cpp`(`Wire::SendGl*` → FullServer → DirectGLES) | ✅(受支持子集) |
| 9 | 对象创建(`glGenTextures` 等) | `ret_bytes` 通道(服务端分配 + 客户端拷贝) | ✅ |
| 10 | 数据上传(`glBufferData` 等带 size 字段) | `AllocateShm` + `memcpy` + `ret_i64` | ✅ |
| 11 | `glGetString` | `SendGetString` 专用通道 | ✅ |
| 12 | 进程退出 | `Client::Shutdown` → `mobilegl_fullserver_destroy`(join server thread) | ✅ |
## 2. 环境变量(`MOBILEGL_CS_*`)
见 README「Runtime environment variables」表。插件 manifest 已固化:
`MOBILEGL_CS_MODE=inprocess`、`MOBILEGL_CS_BACKEND=DirectGLES`。
## 3. 已知不支持面(eglGetProcAddress 返回 nullptr / 生成器跳过)
| 类别 | 例子 | 计划 |
|---|---|---|
| 无尺寸 out 参数 | `glGetIntegerv` / `glGetFloatv`(已支持:共享 `MobileGLQueryCount` 表 + `out_capacity`) | ✅ 已实现 |
| 多级指针 | `glShaderSource`(已支持:shm NUL 拼接 + FullServer opcode 拦截重建指针数组);`glGetActiveAttrib/Uniform` 等仍待 | 部分支持 ✅/待补 |
| 输入向量 | `glUniform*`(已支持:客户端物化 + 内联向量) | ✅ 已实现 |
| 指针返回(非 GetString) | `glMapBufferRange`(typed 通道已覆盖) | 保持 typed 路径 |
| EGL 全量 | `eglCreateSync` / `eglCreateImage` 等 | 后续补齐 |
**安全红线**:任何返回写入都必须遵守“服务端知道写入量 ≤ 客户端缓冲区容量”。
当前仅对带 `n/count/num` 的 out 向量允许自动分配;无尺寸查询保持 unsupported。
## 4. 验证步骤(需要 shell/构建工具,phase 2 禁用,留待后续阶段)
```sh
# 1) 代码生成 + 编译(Linux)
cmake -S . -B build_agent -DMOBILEGL_BUILD_TEST=ON -DMOBILEGL_BUILD_CS_REFACTOR=ON -DMOBILEGL_FLATC=/tmp/flatc_bin/flatc
cmake --build build_agent --target MobileGL_Client MobileGL_FullServer MobileGL_UtilRuntime BackendObject_DirectGLES -j
# 2) 生成覆盖报告
cat MobileGL/MG_Client/generated_trampoline_coverage.txt
# 3) 单元/传输回归
ctest --test-dir build_agent -L unit -j
# 4) 插件 APK(Android,需要 SDK/NDK 27.3)
cd android-plugin && ./gradlew :app:assemblePluginRelease
```
## 5. 验收标准(M1/M2/M3)
- **M1**:裸进程 `libMobileGL_Client.so` + in-process hosting → `eglGetDisplay/Initialize/MakeCurrent/glClear/glReadPixels` 全通。
- **M2**:FCL 选择「MobileGL C/S」渲染器,进入 Minecraft 主菜单(对象创建 + 数据上传 + GetString 必通)。
- **M3**:游戏可玩(渲染正确、crash-free、退出无挂起线程)。
-130
View File
@@ -1,130 +0,0 @@
# MobileGL C/S: Handle / Session / Generation 统一语义
> 状态:Phase 0 契约文档(与 `C_S_REFACTOR_PLAN.md` §5 一一对应)
> 范围:FullServer、Client、BackendObject、UtilRuntime 共用的对象标识语义
> 读者:所有实现 BFA / 外部协议的模块
---
## 1. ID 层级
```text
DisplayId
└─ SharedGroupId
└─ SessionId
└─ ObjectHandle(共享对象在 SharedGroup 级;上下文私有对象在 Session 级)
```
所有 ID 均为 `uint64_t`,由 FullServer 在进程生命周期内分配,**不复用**。`0` 保留为无效 ID。
| ID | 分配者 | 生命周期 | 语义 |
|---|---|---|---|
| `MobileGLDisplayId` | FullServer (EGL) | `eglGetDisplay` → `eglTerminate` | 一个 EGLDisplay 的句柄;持有 backend device |
| `MobileGLSharedGroupId` | FullServer | 首个无 share 的 context 创建 → group 内全部 context 销毁 | 共享对象表、ShareGroup 级 backend native 资源 |
| `MobileGLSessionId` | FullServer | `eglCreateContext` → `eglDestroyContext` | 一个 GL context;持有 current bindings / error queue |
| `MobileGLBackendHandle` | FullServer | 对象创建 → 对象销毁 | 不透明对象句柄,与 GL name 解耦 |
## 2. 归属规则
| 状态 | 归属 |
|---|---|
| EGL display / config / surface | DisplayId |
| GL 共享对象表(buffer/texture/sampler/VAO/program/shader/pipeline/FBO/RBO/TF) | SharedGroupId |
| 上下文私有对象(default FBO/VAO/texture 0、query、sync 等) | SessionId |
| current bindings / render state / viewport / error queue | SessionId |
| backend native 共享资源(VkBuffer/VkImage/pipeline/sampler) | SharedGroupId |
| command pool / descriptor pool / frame tracking / deferred release | SessionId |
| 硬件设备 / loader | DisplayId |
## 3. ObjectHandle 模型
```text
ObjectHandle = uint64_t
- FullServer 分配,进程生命周期内不复用
- 共享对象:同一 handle 在 SharedGroup 内所有 Session 可见
- 上下文私有对象:仅所属 Session 有效
- 与 GL name 解耦
- 映射:
共享对象 (SharedGroupId, ObjectKind, GLname) → handle
上下文私有 (SessionId, ObjectKind, name/slot) → handle
```
设计理由:
- 天然支持 name 0 默认对象、proxy texture、texture view、reserved-but-not-materialized 对象;
- 避免 `SharedPtr<T>` / 裸指针跨插件边界;
- 未来 share group 语义扩展不需要改接口。
## 4. 映射表(FullServer 拥有)
FullServer 维护以下 Registry(线程安全):
```text
DisplayRegistry : DisplayId -> DisplayInfo
SharedGroupRegistry : SharedGroupId -> SharedGroupInfo
SessionRegistry : SessionId -> SessionInfo
SharedObjectRegistry : { SharedGroupId, ObjectKind, GLname } -> BackendHandle
PrivateObjectRegistry : { SessionId, ObjectKind, name/slot } -> BackendHandle
```
Backend 不再持有 frontend `SharedPtr<T>`:只接收 `BackendHandle` 并通过
`BackendHost` 查询信息。Frontend 对象销毁时调用
`BackendVTable::OnObjectDestroyed` 显式通知。
## 5. Generation 机制
| frontend 现状 | BFA 字段 |
|---|---|
| `GetShapeVersion / GetContentVersion / GetTextureParamsVersion` | `TextureInfo.generation / contentGeneration / paramsGeneration` |
| `GetTextureBindGeneration / GetSamplingResolutionGeneration` | `TextureInfo.bindGeneration / samplingGeneration` |
| `GetRenderStateParametersVersion / GetPipelineStateVersion` | `RenderState.version / pipelineVersion` |
| `GetLinkVersion / GetBackendStateVersion / GetUniformWriteSetVersion / GetUBOContentVersion / GetBlockBindingVersion` | `ProgramInfo.*Generation` |
| `GetConfigVersion / GetAttributeVersion` | `VertexArrayInfo.generation / attribs[].generation` |
| `GetObjectVersion / GetAllFramebufferAttachmentVersions` | `FramebufferInfo.generation` |
| `SamplerObject::GetVersion` | `SamplerInfo.generation` |
| `GetTransformFeedbackGeneration` | `TransformFeedbackInfo.generation` |
| `GetTextureContextId` | SessionId 来源 |
Backend 缓存 key:
```text
{ SharedGroupId, ObjectHandle, objectGeneration }
```
约定:
- Generation 只在 FullServer 修改(单调递增,不回绕);
- Backend 只比较、不推导;
- `generation` 变了就整级/整对象重传,v1 不做 dirty-rect 增量。
## 6. 跨层数据通路(只读快照,调用期有效)
| 数据 | Host 接口 | 生命周期 |
|---|---|---|
| Buffer shadow | `GetBufferShadow` | 调用期有效,Backend 必须 copy |
| Buffer range | `ReadBufferRange` | 同步拷贝 |
| Texture mip | `GetTextureMipInfo` + `GetTextureMipData` | 同步拷贝 |
| Program 模块 | `GetProgramModules` | 返回的 SPIR-V 指针调用期有效 |
| Persistent map | `BufferAcquirePersistentMap` | Backend 管理的 GPU 映射 |
## 7. 线程模型
- 同一 `(sessionId, clientThreadId)` 流严格 FIFO;
- 同一 session 的 backend 调用串行;
- 不同 session/thread 可并发,Host 查询线程安全;
- v1 禁止 backend 自建线程回调 Host。
## 8. C ABI 类型映射
| 语义 | C 类型 |
|---|---|
| DisplayId | `uint64_t` |
| SharedGroupId | `uint64_t` |
| SessionId | `uint64_t` |
| BackendHandle | `uint64_t` |
| Generation | `uint64_t` |
| Bool | `bool`(`stdbool.h`) |
| Size | `uint64_t` |
| 错误码 | `int32_t` + Host `RecordError` |
所有 BFA / RuntimeApi 契约头不包含任何 C++ 类型。
-220
View File
@@ -1,220 +0,0 @@
# C/S Refactor Implementation Status
> 更新:Phase 0-2 完成;Phase 3 DirectGLES 真实 BFA 插件已接入(EGL/GLES 自包含,24+ 类命令真实 entry point);**本 session 按用户决策跳过 DirectVulkan 迁移**;Phase 4 完成 Token↔session 失效模型 + 全量 1396 API codegen 运行时分发(1171 supported / 225 unsupported 分类;客户端 1170 个 `SendGl*` wrapper);Phase 6 完成 Win32/Android Surface 条件代码 + batch/大 payload 零拷贝基准;**Linux 全量单元回归 1448/1448 通过(3 skipped)**。
> 分支:`Feat/cs-refactor`(从 `dev@81b17c0` 创建)
> 最新 HEAD:`6d3e5132 [Feat] (MG_Protocol, MG_Client, MG_FullServer): Add EGL MakeCurrent/SwapInterval/ResizeSurface commands.`(EGL 命令提交后)
> 首次提交:`9be8bcff [Feat] (All): Add C/S refactor Phase 0-5 scaffolding and state/handle registry.`
> 源码目录约定:新 C/S 模块统一使用项目原有的 `MG_*` 前缀(`MG_Protocol` / `MG_Client` / `MG_FullServer` / `MG_Transport` / `MG_UtilRuntime`),保持 `MobileGL/` 下模块分层一致。
## 本阶段验证记录(已通过)
- 配置:`cmake -S . -B build_agent -DMOBILEGL_BUILD_TEST=ON -DMOBILEGL_BUILD_CS_REFACTOR=ON` ✅
- monolith(`MobileGL` / `MobileGL_s`)编译通过 ✅
- C/S 目标编译通过:`libMobileGL_FullServer.so`(链接 `libMobileGL_MG_FullServerCore.a`)、`libMobileGL_Client.so`、`libMobileGL_UtilRuntime.so`、`BackendObject_DirectGLES.so`、`BackendObject_DirectVulkan.so`、`libMobileGL_Transport.a` ✅
- 单元测试:`ContextRegistryTest` 5/5、`HandleRegistryTest` 5/5 通过 ✅
- **目录重构后全量验证**:C/S 目标与全部相关测试重编译通过;`SanityTest` 82/82、`InProcessTransportTest` 1/1、`BigServerE2ETest` 1/1 通过;`libMobileGL_FullServer.so` 构建成功
- **全量 ctest(unit)**:1442/1442 通过(3 skipped)✅(含 ClientQueryResults 等新测试)
- **本 session 全量回归(Commit 713a9536 之后)**:`cmake -S . -B build_agent -DMOBILEGL_BUILD_TEST=ON -DMOBILEGL_BUILD_CS_REFACTOR=ON` + `ninja -C build_agent -j10` ✅;`ctest --test-dir build_agent -L unit -j10` **1448/1448 通过(3 skipped)** ✅(含 ClientTokenSessionTest 2/2、ClientWirePayloadTest 1/1、ProtocolDispatchCoverageTest 3/3)
- **本 session 基准实测(批量零拷贝后)**:`ShmPayloadBenchmark` single(1B,20 iter) per-command avg 40.7µs / min 34.9µs / max 62.1µs;batch 多命令帧(64条/帧) avg **5.3µs/条**、帧 avg 340.1µs;large-batch(4MiB×64) avg **5.0µs/条**、帧 avg 317.8µs(serverOk=1;相对逐条提交 17.4µs/条 → 5.3µs/条)
- 第二次构建(共享 Buffer 表迁移后):`BufferState` 委托 group 级 `SharedBufferObjectTable`,跨 session 可见性测试通过 ✅
## FCL 接入(FCL 0 改动,代码完成态,未编译验证)
目标:MobileGL C/S 作为一个标准 FCL 渲染器插件 APK 使用;FCL 代码零改动。Client 库通过 `dladdr` 自动定位与启动同目录 `libMobileGL_FullServer.so`。
- [x] `MOBILEGL_CS_*` 环境变量运行时选择:
- `MOBILEGL_CS_MODE` = `inprocess`(默认,自动宿主)/ `connect`(连接既有 server)
- `MOBILEGL_CS_ENDPOINT` / `MOBILEGL_CS_BACKEND` / `MOBILEGL_CS_SERVER_UTIL` / `MOBILEGL_CS_SERVER_BACKEND` / `MOBILEGL_CS_DEBUG`
- 实现:`MobileGL/MG_Client/ClientEnv.h/.cpp`
- [x] Client 自动宿主:`MobileGL::Client::InitializeFromEnvironment()` —— `inprocess` 下 `dlopen` 同目录 FullServer 并调用 `mobilegl_fullserver_create_inprocess`;`connect` 下走 `Initialize(endpoint)`;`Shutdown()` 先销毁宿主再释放 in-process 传输
- [x] FullServer 同进程宿主 C ABI:`mobilegl_fullserver_create_inprocess(utilPath, backendPath, &clientTransport, &clientOps)` —— `CreateInProcessTransportPair` + `ServerCore` + server thread;`destroy` 通过 `ServerShutdown` 哨兵唤醒阻塞的 `WaitResponses` 后 join
- [x] `MG_Protocol/control.h`:`ServerShutdown = 1'000'050`(唤醒哨兵,宿主线程拥有退出权)
- [x] M1 引导级 Client trampoline:`MobileGL/MG_Client/ClientTrampoline.cpp` 导出 EGL 核心子集(display/config/context/pbuffer/makecurrent/swapbuffers/getprocaddress)+ `glClearColor/glClear/glViewport/glDrawArrays/glReadPixels/glGetString/glGetError/glFlush/glFinish` 子集;`eglGetProcAddress` 对未覆盖符号返回 NULL
- [x] EGL wire codegen 管线扩展(脚本层,构建期重新生成):
- `scripts/generate_protocol_fbs.py`:解析 `EGLImpl/Exporting/Definitions.cpp`,产出 `Egl*` payload 表(与 `Gl*` 合并)
- `scripts/generate_wire_full_fbs.py`:`Egl*` → `Gen*` 表
- `scripts/generate_wire_dispatch.py`:EGL 条目产出 `::egl<Name>(...)` 分发 + EGL 类型 cast(handle/标量/数组)
- `scripts/generate_wire_client.py`:生成 `SendEgl*` wrapper
- `MobileGL/MG_Protocol/CMakeLists.txt`:EGL Definitions 加入三个 codegen 的 DEPENDS
- [x] 标量回传通道(response.ret_i64):
- `MobileGL/MG_Protocol/wire.fbs` `Response` 增加 `ret_i64: long`(`wire_full.fbs` 模板同步)
- `generate_wire_dispatch.py`:非 void 支持条目捕获返回值(整型 `StoreI64` / 句柄指针 `StoreU64`),暴露 `WireDispatchReturnValid/ReturnI64`
- `FullServerEntry`:`WireDispatchWithSession` 捕获后经 `WireRetProvider` 回调转发
- `ServerCore`:可选 `SetWireRet`(测试可不链接生成分发实现),回填 `Response.ret_i64`
- `Client::GetLastResponseRetI64()` 解析回传;`ServerCore`/`Client.cpp` 无 `generated_wire_dispatch.cpp` 链接依赖
- [x] InProcessTransport 内嵌共享内存:`InProcessLink` 持有 `slot`(同一进程共享指针),`OpenSharedMemory/ReceiveShmHandle/SubmitCommands` 帧携带 `MobileGLShmHandle`(含 `mappedAddress`),使 `ReadPixels/BufferReadback/Texture/Buffer shm 上传`在 in-process 模式下可用(FCL 同进程路径不再依赖 `memfd/SCM_RIGHTS`)
- [x] 生成式全量 trampoline(受支持子集):
- `scripts/generate_client_trampoline.py`:从 `generated_dispatch.h` + `wire_full.fbs` + GL Definitions 生成 `generated_wire_trampoline.h/.cpp`(`MOBILEGL_GL_API` 导出)
- 规则:标量/string 参数直接透传;`ShmRegion` 参数且带 size 字段的条目(`glBufferData` 等)自动 `Client::AllocateShm` + memcpy + 释放;标量返回走 `GetLastResponseRetI64()`;`glGetString` 走 `SendGetString`;out-vector/多级指针/无表条目跳过(`eglGetProcAddress` 返回 NULL)
- `Client::SetCurrentSession/GetCurrentSessionId` + `AllocateShm/ReleaseShm` 基础设施
- `ClientTrampoline.cpp` 保留 EGL + 4 个无表 GL 条目(`glReadPixels/glFlush/glFinish/glGetError`),其余 GL 由生成器接管;`MG_TrampolineGen` 目标 + `MobileGL_Client` 依赖 + `.gitignore` 忽略生成物
- [x] out-vector 回传通道(`Response.ret_bytes`):
- `wire.fbs`/`wire_full.fbs` `Response` 追加 `ret_bytes: [ubyte]`
- `generate_wire_dispatch.py`:非 const 向量参数(`glGen*` 家族,带 `n/count/num` 计数)分配服务端缓冲区 → 调用 → `WireDispatchStoreBytes`;新增 `WireDispatchBytes/BytesSize`
- `WireRetFn` 扩展为 `(valid, i64, bytes, bytesSize)`;`FullServerEntry` 转发字节;`ServerCore` 以 `CreateVector` 回填
- `Client::GetLastResponseBytes()`;`generate_wire_client.py` 对 out-vector 不再发值;`generate_client_trampoline.py` 对 `glGenTextures/glGenBuffers/...` 拷贝 `ret_bytes` 到调用者缓冲区
- [x] 插件 APK 打包方案(`android-plugin/`,FCL 0 改动):
- `android-plugin/app/build.gradle.kts`:V2 DSL `rendererGLPath/EGLPath` = `libMobileGL_Client.so`;`dlopenLibPaths` = FullServer/UtilRuntime/BackendObject_DirectGLES;env 增加 `MOBILEGL_CS_MODE=inprocess`、`MOBILEGL_CS_BACKEND=DirectGLES`
- legacy manifest(旧 FCL `RendererPlugin.kt` 读取):`renderer` = `MobileGL C/S:libMobileGL_Client.so:/libMobileGL_Client.so`;`pojavEnv/boatEnv` 增加 `DLOPEN=libMobileGL_FullServer.so,libMobileGL_UtilRuntime.so,BackendObject_DirectGLES.so` + `MOBILEGL_CS_*`
- 根 `build.gradle`(`:MobileGL` 模块):CMake 增加 `-DMOBILEGL_BUILD_CS_REFACTOR=ON`(default/for-debug/trace 三处)
- [x] 无尺寸 out 参数(getter 族)通道:
- `MobileGL/MG_Protocol/query_sizes.h`:共享 pname→count 表(VIEWPORT/SCISSOR/COLOR_WRITEMASK/DEPTH_RANGE 等,未知回退 1)
- wire `Command.out_capacity`;`SendWirePayload(+outCapacity)`;`WireDispatchFn(+outCapacity)`
- 生成分发对无 count 的 out 向量使用 `outCapacity` 分配;trampoline 用同一张表传容量并拷贝 ret_bytes
- `glGetIntegerv/glGetFloatv/glGetDoublev/glGetBooleanv/glGetInteger64v` 进入支持集
- [x] EGL window/平台 surface 路径:
- wire `EglCreateWindowSurface{native_window}` + `SendEglCreateWindowSurface` + ServerCore `CreateWindowSurface`(backendType Android=3 / 其他=1)
- M1 trampoline 导出 `eglGetPlatformDisplay(+EXT)`、`eglCreateWindowSurface`、`eglCreatePlatformWindowSurface` 并登记 getproc
- [x] 输入向量(`glUniform{1,2,3,4}{f,i,ui}*v` / `glUniformMatrix*` / `glDelete*`):trampoline 生成器把 `const T*` 物化为 `std::vector<T>`(元素数:uniform 由函数名推断——`Matrix{N}fv=N²`、`Matrix{N}x{M}fv=N*M`、其余为 N;delete 为 1)交给 wrapper 内联路径;服务端既有 `[vector]` 解码透传指针
- [x] `glShaderSource` 专用路径(M2 关键:无着色器无法编译程序):
- Client `glShaderSource` 手写:NUL 拼接 count 个源码 → `AllocateShm` → `SendWirePayload`(`GenShaderSource` + ShmRegion)
- FullServer `WireDispatchWithSession` opcode 拦截:从 shm 重建 `const GLchar*[]`(按 NUL 切分),直接调用前端 `::glShaderSource`(count<1024 上限)
- [x] `glDelete*` 输入向量(count 驱动,elems=1,客户端物化向量走内联通道)
- [x] EGL 小函数补全(M1 bootstrap):`eglGetConfigs` / `eglGetConfigAttrib` / `eglQuerySurface` / `eglReleaseThread`(合成 config 语义 + getproc 登记)
- [x] `glTexImage2D` / `glTexSubImage2D` / `glTexImage3D` 纹理数据上传(手写 shm 通道:按 format/type 估算像素字节(UNSIGNED_BYTE RGB=3/RGBA=4 等,回退 4),`AllocateShm` + memcpy,走 `SendGlTexImage2D/SubImage2D/3D`;空指针走无 shm 路径)
- [x] EGL sync 族 bootstrap(eglCreateSync(合成 token)/ DestroySync / ClientWaitSync(Satisfied)/ GetSyncAttrib / WaitSync)+ `eglSwapInterval` 导出与 getproc 登记
- [x] `glGetActiveAttrib`/`glGetActiveUniform`(最后常用缺口):
- wire `ActiveVariable{program,index,buf_size}` + Command 字段;`Client::SendGetActiveAttrib/Uniform`
- FullServerEntry opcode 拦截:调前端 `::glGetActiveAttrib/Uniform`,打包 `[u32 length][u32 size][u32 type][name\0]` 经 `WireRetProvider` → `Response.ret_bytes`
- 客户端手写两个 gl 导出 + 解析解码(`DecodeActiveVariable`,bufSize≤1023)
- [ ] 剩余不支持面:EGL image/标号类(`eglCreateImage` 等)、`glMap*` 指针返回(typed 已有)
- [ ] FCL 真机安装验证
- [ ] 插件 APK 打包 + FCL 真机验证(下一步)
- ⚠️ 本段**未编译验证**:严格按用户要求在 router phase 2 (dev) 内实现,禁用 shell;仅做了只读符号一致性自检。
## Phase 0 — 契约定稿 ✅
- [x] `docs/CS_Refactor/HandleSessionGeneration.md` — Handle/Session/Generation 语义
- [x] `MobileGL/MG_Protocol/protocol.fbs` — FlatBuffers `Message` + `Payload` union 草案
- [x] `MobileGL/MG_Protocol/bfa.h` — Backend Frontend API strict C ABI
- [x] `MobileGL/MG_Protocol/mgruntime_api.h` — UtilRuntime 分域 sub-vtable C ABI
- [x] `MobileGL/MG_Protocol/transport.h` — Transport ops 定义
- [x] `MobileGL/MG_Protocol/api_manifest.txt` + `scripts/extract_api_manifest.py` — API 清单提取器(1720 条)
- [x] `scripts/generate_protocol_fbs.py` — 从 Definitions.cpp 生成 `protocol_generated.fbs`(2750 个 `Gl*` payload 表)
- [x] `MobileGL/MG_Protocol/CMakeLists.txt` — `MobileGL_Protocol` / `MobileGL_BFA` / `MobileGL_RuntimeApi` INTERFACE targets
## Phase 1 — 构建拆分(脚手架,待完整化)
- [x] 根 CMake 增加 `MOBILEGL_BUILD_CS_REFACTOR`(默认 OFF,保留 monolith 对照)
- [x] `MobileGL/MG_Client` — `MobileGL_Client` SHARED 骨架
- [x] `MobileGL/MG_FullServer` — `MobileGL_FullServer` SHARED(`libMobileGL_FullServer.so`,BigServer host 组件)
- [x] `FullServerEntry.h/.cpp` — C ABI 宿主入口:`mobilegl_fullserver_create/start/attach_transport/service_once/run_socket/destroy`
- [x] **跨进程 E2E(Python 客户端)**:Python + flatbuffers 构建 `Message` → ABC socket → `libMobileGL_FullServer.so` `run_socket` → null backend `Clear` → `Response{status=0}` 返回;验证成功
- [x] **dlopen 验证**:Python ctypes 加载 `libMobileGL_FullServer.so` → create(UtilRuntime.so, BackendObject_DirectGLES.so) → start → destroy 成功
- [x] `MobileGL/MG_UtilRuntime` — `MobileGL_UtilRuntime` SHARED 骨架(`mobilegl_util_api` 导出)
- [x] `MobileGL/MG_Backend/CMakeLists.txt` — `BackendObject_DirectGLES` / `BackendObject_DirectVulkan` MODULE 骨架 + manifest
- [x] 把真实 `MG_Impl / MG_State / MG_Util` 源列表拆入 `MobileGL_MG_FullServerCore`(STATIC,不含 MG_Backend),`MobileGL_FullServer.so` 链接它;monolith 仍保留作对照
- [x] **monolith 切换核对**:保留 monolith 作为对照,暂不删除——DirectVulkan 未迁入 BFA(用户本 session 跳过),等 DV 迁移完成后按 Phase 1 原计划再切
## Phase 2 — FullServer 状态模型(共享对象表迁移 + pGLContext 路由完成)
- [x] `MobileGL/MG_State/GLState/ContextRegistry.h/.cpp` — `GLSharedGroup` / `GLContextSession` / `GLContextRegistry`
- [x] `MobileGL/MG_State/GLState/SharedObjectTables.h` — group 级共享对象表容器(BufferState 起步)
- [x] EGL `CreateContext` / `DestroyContext` / `MakeCurrent` / `ReleaseThread` 接入 registry 生命周期
- [x] `MobileGL/MG_State/GLState/HandleRegistry.h/.cpp` — `(groupId/sessionId, kind, glName) → MobileGLBackendHandle`
- [x] `GLContext::GetObjectHandle` — 前端对象首次访问时分配/复用 C/S handle
- [x] Buffer/Texture 对象创建时分配 handle、删除时释放(`CreateBufferObject` / `CreateTextureObject` / `CreateTextureViewObject` / 对应 Mark*ForDeletion)
- [x] **Buffer 共享对象表迁移**:`SharedBufferObjectTable` 由 `SharedObjectTables` 持有,`BufferState` 的 name/object 表委托给 group;binding slots 仍 per-context(GL shareCtx 语义)
- [x] **Texture 共享对象表迁移**:`SharedTextureObjectTable` 由 `SharedObjectTables` 持有,`TextureState` 的 name/object 表委托给 group;default texture 与 unit bindings 仍 per-context
- [x] **Sampler 共享对象表迁移**:`SharedSamplerObjectTable` 由 `SharedObjectTables` 持有,`SamplerState` 的 name/object 表委托给 group
- [x] **Renderbuffer 共享对象表迁移**:`SharedRenderbufferObjectTable` 由 `SharedObjectTables` 持有,`RenderbufferState` 的 name/object 表委托给 group;binding slots 仍 per-context
- [x] **Framebuffer 共享对象表迁移**:`SharedFramebufferObjectTable` 由 `SharedObjectTables` 持有,`FramebufferState` 的 name/object 表委托给 group(含 FBO 0 语义);binding slots 仍 per-context
- [x] **VertexArray 共享对象表迁移**:`SharedVertexArrayObjectTable`(vector + name generator)由 `SharedObjectTables` 持有,`VertexArrayState` 的 object 表委托给 group;bound index/detached 仍 per-context
- [x] **Program/Shader 共享对象表迁移**:`SharedProgramObjectTable`(program/shaders 两个 vector + 联合 name generator)由 `SharedObjectTables` 持有,`ProgramState` 的 object 表委托给 group;`m_currentProgram` 与 compile caches 仍 per-context
- [x] **TransformFeedback 共享对象表迁移**:`SharedTransformFeedbackObjectTable`(对象 map + name generator)由 `SharedObjectTables` 持有;bound index / live capture state / buffer binding points 仍 per-context
- [x] **ProgramPipeline 共享对象表迁移**:`SharedProgramPipelineObjectTable`(pipeline map + name generator)由 `SharedObjectTables` 持有;bound pipeline index 仍 per-context
- [x] `MobileGL/MG_Test/State/ContextRegistryTest.cpp` / `HandleRegistryTest.cpp` — 单元测试(Buffer/Texture/Sampler/Renderbuffer/Framebuffer/VAO/Program/Shader/TransformFeedback/ProgramPipeline 跨 session 可见性验证)
- [x] **pGLContext 路由完成**:`pGLContext` 改为非拥有 `GLContext*`,EGL `MakeCurrent`/`ReleaseThread` 将其指向/清空当前 session;`SanityTest` 82/82 通过
- [x] **Query/Sync session-private 状态层**:`SessionPrivateState`(GLContext 拥有)落地;`GL_Sync.cpp` 与 `GL_Query.cpp` 的注册表/next-id/active 槽全部迁移到 session-private;`DestroyAll*` 按当前 session 清理;`pGLContext` 在 FullServer session 创建/销毁与每次 wire 分发时同步到当前 session(未编译验证前为代码完成态)
## Phase 3 — BFA 落地(进行中)
- [x] `MobileGL/MG_FullServer/BackendHost.h/.cpp` — FullServer 侧的 BackendHost vtable 骨架
- [x] `MobileGL/MG_FullServer/BackendPluginLoader.h/.cpp` — dlopen + manifest ABI 校验 + Create
- [x] `StateBackendObjectRegistry` 增加 handle-key 并行查找:`RegisterHandle` / `FindByHandle` / `UnregisterHandle`(主 map 仍按 state 指针走热路径;原生 Monolith 编译通过)
- [x] **Display / SharedGroup 生命周期控制**:`control.h` 增加 `DisplayCreate/Destroy` + `SharedGroupCreate/Destroy`;`Client::SubmitDisplayControl/SubmitSharedGroupControl`;`ServerCore` 调 `OnDisplayCreated/Destroyed/OnSharedGroupCreated/Destroyed`;`ClientHierarchyLifecycleTest` 1/1 通过
- [x] **DirectGLES 真实 BFA 插件初版**:`RealBackend.h/.cpp` 自包含 dlopen `libEGL`/`libGLESv2` + `eglGetProcAddress` 解析;`OnDisplayCreated` 初始化 surfaceless/默认 EGLDisplay 并选 config;`OnSessionCreated` 创建真实 EGLContext(ES3→ES2 fallback)+ pbuffer(失败退 surfaceless no-surface)并 `eglMakeCurrent`;`OnSessionDestroyed` 释放;Clear/ClearColor/DrawArrays/DrawElements/BufferSubData/DrawRangeElements/DrawArraysInstanced/DrawElementsInstanced/MemoryBarrier/MemoryBarrierByRegion/PatchParameteri/GenerateMipmap/DispatchCompute/DispatchComputeIndirect/TransformFeedback 全链/BlitFramebuffer/SwapBuffers/FenceSync/DeleteSync/WaitSync 走真实 GLES/EGL entry points(缺失入口安全 no-op);Buffer handle→GLuint、Sync handle→GLsync 映射;`GetRendererInfo/GetDynamicParameters` 由真实 `glGetString/glGetIntegerv` 回填
- [x] **符号/link 调研结论**:`nm -u -C BackendObject_DirectGLES.so` 仅 libc/libstdc++/libm 未定义符号,`ldd` 无任何 MobileGL_* 依赖;`libMobileGL_MG_FullServerCore.a` 里对 `gBackendFunctionsTable`/`pActiveBackendObject` 的引用由 `GlobalObjects.cpp` 定义、MG_Backend 实现源码未进核心库;link 方案 = **插件自包含真实 BFA 适配器**(方案 A),不链接前端静态库,无双份 static 状态问题
- [x] **FullServer 侧 BFA shim 初版**:`MobileGL/MG_FullServer/BfaFrontendShim.h/.cpp` —— 把旧 `gBackendFunctionsTable.GL` 的 Clear/ClearBuffer*/ClearNamedFramebuffer*/BlitNamedFramebuffer/DrawArrays/DrawElements/DrawElementsBaseVertex/DrawArraysIndirect/DrawElementsIndirect/MultiDraw*/DrawArraysInstanced/DrawElementsInstanced/DrawRangeElements/BlitFramebuffer/CopyTexImage2D/CopyTexSubImage2D/CopyImageSubData/GetTexImage/GetTextureImage/GenerateMipmap/ReadPixels/DispatchCompute/DispatchComputeIndirect/MemoryBarrier/MemoryBarrierByRegion/BindImageTexture/PatchParameteri/TransformFeedback 全链/Bind+DeleteTransformFeedback/ShaderStorageBlockBinding/FenceSync/ClientWaitSync/DeleteSync/WaitSync/GetSyncStatus/时间查询全链(BeginTimeElapsed/QueryCounter/IsQueryResultAvailable/GetQueryResult64/DeleteBackendQuery/Occlusion/Xfb 查询)/GetGpuTimestampNs/Present/SetSwapInterval 转发到 BFA vtable;命名对象(NamedFramebuffer/BlitNamed/GetTextureImage/CopyImageSubData)经 `HandleProvider` + `FramebufferNameProvider`/`TextureNameProvider`/`RenderbufferNameProvider` 把前端 GL name 映射为 BFA handle(Provider 由 FullServerEntry 注入,用前端当前 GLContext 的 GetObjectHandle);`ServerCore` 增加 `SetSessionListener`(session create/destroy 通知),`FullServerEntry` 在 start 时 `Install`、session 变化时更新 current session、destroy 时 `Clear`;`BfaFrontendShimTest` 1/1 通过,BigServerE2E/ClientSessionLifecycle 1/1,真实 DirectGLES Python E2E status=0
- [x] **前端 session 绑定**:`FullServerEntry` 的 session listener 同时用 `GLContextRegistry` 创建/销毁以 BFA session id 为 key 的前端 GLContextSession,并把当前线程 current 指到它;shim 增加 `SessionProvider` 回退(ServerCore 未上报时从前端当前 context 取 session id),使旧前端命令的 current session 与 BFA 对齐
- [x] **FullServer 侧 BFA→旧 `BackendObject`/`gBackendFunctionsTable` shim 剩余覆盖(ABI minor 0.1)**:`bfa.h` vtable 追加 `MultiDrawElementsBaseVertex/MultiDrawArraysIndirectCount/MultiDrawElementsIndirectCount/DrawRangeElementsBaseVertex/DrawElementsInstancedBaseVertex/BaseInstance/BaseVertexBaseInstance/DrawArraysInstancedBaseInstance/GetIntegeri_v/GetInteger64i_v/GetProgramiv`;DirectGLES RealBackend 实现(能真实调用的走 GLES 函数,不能的循环/兜底);`BfaFrontendShim` 增加对应 thunk 并全表赋值;`MakeCurrent` 与 session 绑定经 `pGLContext` 修复(OnSessionChanged/WireDispatchWithSession 同步)
- [ ] DirectVulkan 后端迁移到 BFA vtable(device/sharedgroup/session 三层)
## Phase 4 — 外部协议落地(进行中)
- [x] `MobileGL/MG_Transport/LocalSocketShmTransport.h/.cpp` — v1 transport:AF_UNIX socket connect / bind+listen / accept + 长度前缀字节流收发
- [x] **shm arena**:`OpenSharedMemory`(memfd_create + mmap)/ `ReleaseSharedMemory`;`InProcessTransportTest.LocalSocketShmAllocatesSharedMemory` 3/3 通过
- [x] **shm fd 跨进程传递**:`SendShmHandle` / `RecvShmHandle`(SCM_RIGHTS + 控制消息携带 size);`LocalSocketShmTransfersShmFd` 双向读写验证,InProcessTransportTest 4/4 通过
- [x] **shm payload 回读通路**:`Client::SubmitDataCommand` → batch 携带 shm fd → `ServerCore` 用 `ReceiveShmHandle` 接收并读首字节 → `Response.data_byte` 回显;`ClientShmPayloadTest` 1/1 通过
- [x] transport ops 新增 `ReceiveShmHandle`(ABI minor+0.1 兼容追加)
- [x] `MobileGL/MG_Transport/InProcessTransport.h/.cpp` — 同进程 transport 实现(client/server 配对 + 批消息队列)
- [x] `MobileGL/MG_Transport/TransportInternal.h` — 统一 `MobileGLTransport` 内部完成类型(避免 ODR 冲突)
- [x] `MobileGL/MG_Test/Transport/InProcessTransportTest.cpp` — in-process + LocalSocketShm 往返 + shm arena + fd 传递测试 4/4 通过
- [x] `MobileGL/MG_Client` — Client 命令 API:`InitializeWithTransport` + `SendCommand(sessionId, opcode)`(提交/等待响应)+ 异步 `SubmitCommand` / `WaitResponseForToken`
- [x] `MobileGL/MG_Test/Transport/ClientAsyncBatchTest.cpp` — 8 条命令先全部提交、再按 token 收响应,1/1 通过
- [x] `MobileGL/MG_Test/Transport/ClientServerEndToEndTest.cpp` — Client 命令 → InProcess → ServerCore → VTable → 响应,1/1 通过
- [x] `InProcessTransport::WaitResponses` 改为等待语义(timeoutMs=0 无限等待)
- [x] `MobileGL/MG_Transport/CMakeLists.txt` — `MobileGL_Transport` static library
- [x] `scripts/generate_protocol_fbs.py` → `MobileGL/MG_Protocol/protocol_generated.fbs`(2880 个 `Gl*` payload 表;本次补齐 GLenum*/GLdouble*/GLint64*/GLboolean* 等指针/数组映射)
- [x] `scripts/generate_opcode_table.py` → `MobileGL/MG_Protocol/generated_opcodes.h`(1396 个 GL/EGL opcode + 名称表)
- [x] `MobileGL/MG_Test/Transport/ProtocolOpcodeTest.cpp` — 生成表计数与名称查询 1/1 通过
- [x] `MobileGL/MG_Protocol/wire.fbs` — 最小 wire schema + flatc 生成 `gen/wire_generated.h`(8KB)
- [x] `3rdparty/FlatBuffers/include` — vendored flatbuffers 头(flatc v25.12.19 兼容)
- [x] **Client/ServerCore 改用 FlatBuffers 实际编解码**:`Client::SendCommand` 构建 `Message`;`ServerCore` 解析 `Message` 并按 opcode 分发、构建 `Response`
- [x] **typed payload trampoline 起步**:wire 增加 `ClearColor{red,green,blue,alpha}`;`Client::SendClearColor` + `ServerCore` 解包调 BFA `ClearColor`;`ClientClearColorTest` 1/1 通过(float 字段精确校验)
- [x] **DrawArrays typed payload**:wire 增加 `DrawArrays{mode,first,count}`;`Client::SendDrawArrays` + `ServerCore` 解包调 BFA `DrawArrays` + null adapter 存根;`ClientDrawArraysTest` 1/1 通过
- [x] **ClientWaitSync + Query 命令族**:wire 增加 `ClientWaitSync{sync,flags,timeout}`(Response.sync 回传结果码)+ `BeginTimeElapsedQuery/EndTimeElapsedQuery/DeleteBackendQuery/IsQueryResultAvailable/GetQueryResult64/BeginOcclusionQuery/EndOcclusionQuery/BeginXfbPrimitivesQuery/EndXfbPrimitivesQuery`(Response.query_ns 回传 ns);`Client::*` 系列 API;`ServerCore` 分发到 BFA(glClientWaitSync/glBeginQueryIndexed/glEndQueryIndexed/glDeleteQueries + control opcodes 1'000'020-25);`ClientClientWaitSyncTest` 1/1 + `ClientQueryResultsTest` 1/1(result=0x911B、query=0x7777/0x7778/0x7779、available/ns/end/delete 回查)
- [x] FlatBuffers 迁移后回归:`BigServerE2ETest` 2/2、`ClientServerEndToEndTest` 1/1、`InProcessTransportTest` 2/2、`ProtocolOpcodeTest` 1/1 全部通过
- [x] **完整 API merge 流水线**:`scripts/merge_protocol_fbs.py` 将 2750 个生成 payload 表并入 `protocol.fbs` 的插入点,产出 `protocol_full.fbs`(无重复、flatc 校验通过;`GeneratedPayload` union 因 >255 成员改为 opcode 分发)
- [x] `scripts/generate_dispatch_table.py` → `generated_dispatch.h`(1396 条 opcode→API→payload 表元数据)
- [x] `ProtocolOpcodeTest` 增加 dispatch 元数据校验,2/2 通过
- [x] **完整 source-list 运行时分发(trampoline / dispatch / 分类表)**:`scripts/generate_wire_full_fbs.py` 从 `protocol_generated.fbs` 生成 `wire_full.fbs`(2750 个 `Gen*` payload 表,`namespace MobileGL.Protocol.WireFull`);`wire.fbs` Command 增加 `payload_bytes:[ubyte]`;`scripts/generate_wire_dispatch.py` 生成 `generated_wire_dispatch.h/.cpp`(1396 条 opcode 全覆盖:**1171 supported** → 调用导出 `gl*` entry point(含 stub,按 Definitions.cpp 转发声明),**225 unsupported** → 干净 status=1 分类;未覆盖的多级指针/回调签名在 `generated_wire_dispatch_report.txt` 分类);`ServerCore` 增加 `SetWireDispatch` 回调,`payload_bytes` 走生成分发;`FullServerEntry` 注入 `WireDispatchWithSession`(先按 sessionId 设当前 frontend context,再调 `WireDispatchCall`);Client 侧生成 `generated_wire_client.h`(与 dispatch 同 supportedness 的 per-API `SendGl*` wrappers,基于通用 `SendWirePayload`);`ProtocolDispatchCoverageTest` 校验 1396 全覆盖与 supported/unsupported 计数;`ClientWirePayloadTest` 验证 `payload_bytes` 经 `SendWirePayload` → `ServerCore` 回调链路
- [x] **异步命令提交 + 按 token 等待**(`Client::SubmitCommand` / `WaitResponseForToken`;`ClientAsyncBatchTest` 1/1 通过)
- [x] **BufferRespecify 数据通路**:wire 增加 `BufferRespecify{buffer_handle,size,usage}`;`Client::SendBufferRespecify`(shm 初始数据可选);`ServerCore` 调 BFA `BufferRespecify`(`MobileGLBufferOps` 携带 shm 指针);`ClientBufferRespecifyTest` 1/1 通过(handle/size/usage/首字节 0xAB 精确回查)
- [x] **间接绘制 shm 通路**:wire 增加 `DrawArraysIndirect` / `DrawElementsIndirect`(shm_offset);`Client::SendDrawArraysIndirect/SendDrawElementsIndirect`;`ServerCore` 解包 shm 指针后调 BFA `DrawArraysIndirect/DrawElementsIndirect`;`ClientIndirectDrawsTest` 2/2 通过(mode/type/offset 处首字节精确回查)
- [x] **GetString 字符串返回**:wire `Response` 增加 `string_value`;`Client::SendGetString` + `GetLastResponseString`;`ServerCore` 调 BFA `GetRendererInfo` 并按 `GL_VENDOR/GL_RENDERER/GL_VERSION/GL_SHADING_LANGUAGE_VERSION` 回填;`ClientGetStringTest` 4 项字符串精确校验 1/1 通过
- [x] **TextureRespecify 单级上传**:wire 增加 `TextureRespecify{texture,level,format,type,width,height,depth,data_size}`;`Client::SendTextureRespecify`(shm 像素数据);`ServerCore` 组装 `MobileGLTextureUpload` 调 BFA;真实插件懒建 GL 纹理名并调 `glTexImage2D/3D`;`ClientTextureRespecifyTest` 1/1 通过
- [x] **ReadPixels 服务端→客户端 shm 回读**:wire `Response` 增加 `ret_shm_count`;`LocalSocketShmTransport::WaitResponses` 按 count 接收 SCM_RIGHTS shm fd;`ServerCore` 在 ReadPixels 分支 `OpenSharedMemory` 分配 arena、BFA 回填、`SubmitCommands` 携带 handle;`Client::SendReadPixels` 从响应 handle 拷回像素;`ClientReadPixelsTest` 1/1 通过(0xDEADBEEF 精确回查)
- [x] **TextureSubImage 子图像上传**:wire 增加 `TextureSubImage{texture,level,format,type,width,height,depth,data_size}`;`Client::SendTextureSubImage`(shm 像素数据);`ServerCore` 调 BFA `TextureSubImage`;真实插件懒建纹理并调 `glTexSubImage2D/3D`;`ClientTextureSubImageTest` 1/1 通过
- [x] **BufferReadbackFromGpu 服务端→客户端 shm 回读**:wire 增加 `BufferReadbackFromGpu{buffer_handle,offset,size}`;`Client::SendBufferReadbackFromGpu`;`ServerCore` 分配响应 shm 调 BFA bool;真实插件用 `glMapBufferRange(GL_MAP_READ_BIT)` 拷回;`ClientBufferReadbackTest` 1/1 通过(0x12345678 精确回查)
- [x] **Map/Unmap 客户端缓冲映射**:wire 增加 `MapBufferRange{buffer_handle,offset,size,access}` + `UnmapBuffer{buffer_handle,offset,size}`;`Client::MapBufferRange` 经服务端→客户端 shm 返回可写映射指针,`Client::UnmapBuffer` 用新 shm 把修改交回服务端(ServerCore 调 BFA `BufferReadbackFromGpu`/`BufferSubData`);`ClientMapUnmapTest` 1/1 通过(映射读回 0x10203040 → 改写 0x99 → unmap 后服务端收到 0x99)
- [x] **批量零拷贝(Message 多命令帧)**:`wire.fbs Message` 增加 `commands:[Command]`(保持既有 `CreateMessage(command, shm_count)` 兼容);`Client::SubmitDataCommandBatch` 一次 Message 携带 N 条 Command + 单一 shm handle;`ServerCore` 将单命令处理提取为 `processSingle` lambda,批量帧逐条执行并为每条发独立 Response;`ShmPayloadBenchmark` 的 `batch/large-batch` 模式改用该路径(待编译回归实测)
- [x] **Token 透传**:`Command.token` / `Response.token`;`Client::SendCommand` 校验回显 token;Python 跨进程 E2E 仍 status=0
- [x] **shm payload 回读**:`ClientShmPayloadTest` 已验证(0xAB 写入 → fd → server 读回 → data_byte=0xAB)
- [x] **会话生命周期**:`control.h` 定义 `SessionCreate/Destroy` 控制 opcode;`Client::SubmitSessionControl` + `ServerCore` 调 `OnSessionCreated/OnSessionDestroyed`;ServerCore 维护 live-session 集合,destroy 后同一 session 命令被拒绝(status!=0);`ClientSessionLifecycleTest` 1/1 通过
- [x] **Token↔session 完整失效模型(多 socket/超时)**:Client 侧 `PendingToken{sessionId}` 表 + 单调不复用 token;`WaitResponseForToken` 校验 response.session_id,超时/失效后删除 token,迟到响应按“token 已不在 pending 表”丢弃;`InvalidateSession` 清除该 session 全部 pending token;`SubmitSessionControl(destroy)` 自动失效;`Response.session_id` 回显;`LocalSocketShmTransport::WaitResponses` 用 `poll` 实现 timeoutMs;`InProcessTransport` 已有 deadline;`ClientTokenSessionTest` 2/2(失效丢弃迟到响应 + 超时失效)
## Phase 5 — Plugin 化集成(进行中)
- [x] `MobileGL/MG_FullServer/UtilRuntimeLoader.h/.cpp` — dlopen `MobileGL_UtilRuntime.so` + ABI 握手
- [x] `MobileGL/MG_FullServer/BackendPluginLoader.h/.cpp` — dlopen BackendObject + manifest 协商 + Create
- [x] `MobileGL/MG_FullServer/BackendHost.h/.cpp` — Host vtable 注入
- [x] ~~`MobileGL/MG_FullServer/Main.cpp`~~ — 启动流程接线(UtilRuntime→BackendPlugin→Create→Initialize→Shutdown);**已移除**(scaffold 遗留;FullServer 以 SHARED .so + C ABI 交付,启动由 `FullServerEntry` 承担)
- [x] **插件生命周期链路(组件级验证)**:`UtilRuntimeLoader` / `BackendPluginLoader` / `ServerCore` 在 `libMobileGL_FullServer.so` 内编译通过;`BigServerE2ETest` 覆盖 Create→Initialize→command dispatch→Shutdown
- [x] **DrawElements + shm indices(零拷贝 draw 数据路径)**:wire 增加 `DrawElements{mode,count,type,indices_offset}`;`Client::SendDrawElements` 携带 shm fd;`ServerCore` 接收并映射后把 indices 指针传给 BFA `DrawElements`;`ClientDrawElementsShmTest` 1/1 通过(offset=1 读到 0x2B)
- [x] **BufferSubData + shm data(buffer 数据通路)**:wire 增加 `BufferSubData{buffer_handle,offset,size}`;`Client::SendBufferSubData` 携带 shm fd;`ServerCore` 把 shm 指针传给 BFA `BufferSubData`;`ClientBufferSubDataShmTest` 1/1 通过(handle/offset/size/首字节 0x44 精确回查)
- [x] **后续 16 类命令已接入(Client*Test 均 1/1)**:`MemoryBarrier` / `MemoryBarrierByRegion` / `PatchParameteri` / `GenerateMipmap` / `DispatchCompute` / `DispatchComputeIndirect` / `Begin/End/Pause/Resume/BindTransformFeedback` / `BlitFramebuffer` / `SwapBuffers` / `DrawArraysInstanced` / `DrawElementsInstanced` / `DrawRangeElements` / `FenceSync`(handle 回传) / `DeleteSync`(handle) / `WaitSync` —— 全部具备 wire 表 + Client API + ServerCore 分发 + null adapter 存根
- [x] DirectGLES / DirectVulkan null adapter 提供 `Initialize/Shutdown/Display/SharedGroup/Session/Clear/ClearColor/DrawArrays/DrawArraysInstanced/DrawElements/DrawElementsInstanced/DrawRangeElements/BufferSubData/MemoryBarrier/MemoryBarrierByRegion/PatchParameteri/GenerateMipmap/DispatchCompute/DispatchComputeIndirect/Begin/End/Pause/Resume/BindTransformFeedback/BlitFramebuffer/SwapBuffers/FenceSync/DeleteSync/WaitSync` 存根
- [x] **BigServer 全链路 E2E(in-process)**:Client 命令 → InProcessTransport → `FullServer::ServerCore` → Backend VTable → Response → Client;`BigServerE2ETest` 1/1 通过
- [x] **BigServer 全链路 E2E(LocalSocketShm)**:client socket → server accept → `ServerCore` 分发 → 响应返回 client;`BigServerE2ETest` 2/2 通过
- [x] ServerCore 分发改为使用生成 opcode 表(`MobileGLOpcode::glClear`),BigServerE2E 通过
- [x] **BigServer 全链路 E2E(socket transport + FlatBuffers 解码)**:`BigServerE2ETest.LocalSocketShmServerCoreE2E` 覆盖 LocalSocketShm 连接 → FlatBuffers SessionCreate/glClear 解码 → ServerCore → BFA VTable → Response,1/1 通过(另有 InProcessE2E 1/1)
## Phase 6 — 正确性 / 性能 / 平台
- [x] 多 Session / 多 Display / share group 回归:`ContextRegistryTest` 6/6 通过(含跨 session 对象可见性、不同 Display 分组隔离)
- [x] **真实 EGL/GLES 平台初验**:`BackendObject_DirectGLES.so`(自包含 EGL/GLES 加载)经 `libMobileGL_FullServer.so` 的 socket 路径创建真实 session;Python 端 `GetString(GL_VENDOR)` 返回 `NVIDIA Corporation`(真实驱动初始化成功;surfaceless/默认 EGL display 路径工作)
- [x] **平台环境探测**:`DISPLAY=:0`、`WAYLAND_DISPLAY=wayland-0`;`vulkaninfo --summary`:Vulkan 1.4.341、NVIDIA 独显(vendorID 0x10de / deviceID 0x21c4 / driver 610.57.4.0),`VK_KHR_xcb_surface`、`VK_KHR_wayland_surface`、`VK_KHR_surface` 可用;`/usr/share/vulkan/icd.d/` 含 nvidia/lvp/llvmpipe 等 ICD(真实 X11/Wayland C/S Surface 有硬件基础,DirectVulkan 插件仍是 null 存根待迁移)
- [x] **EGL pbuffer surface 生命周期**:wire 增加 `EglCreatePbufferSurface{display,surface,width,height}` + `EglDestroySurface{display,surface}`;`Client::SendEglCreatePbufferSurface/SendEglDestroySurface`;`ServerCore` 分发到 BFA `CreatePbufferSurface/ReleaseEGLSurface`(按 live display 校验);真实插件已实现 pbuffer surface 创建/释放;`ClientEglSurfaceTest` 1/1 通过(display/surface/64x48/释放回查)
- [x] **EGL MakeCurrent / SwapInterval / ResizeSurface**:wire 增加 `EglMakeCurrent{session,draw,read}` + `EglSwapInterval{interval}` + `EglResizeSurface{display,surface,width,height}`;Client/ServerCore 分发到 BFA `MakeEGLCurrent/SetSwapInterval/ResizeSurface`(按 live session/display 校验);`ClientEglCommandsTest` 1/1 通过
- [x] **命令往返基准**:`MobileGL/MG_Benchmark/Transport/CsRoundTripBench.cpp`(mg_bench 原生 C++:FlatBuffers → socket → FullServer.so → backend;原 `scripts/bench_cs_e2e.py` 已并入并删除),含 SessionCreate/Destroy 生命周期,100 次往返 avg 30.5µs / min 25.2µs / max 107.5µs(null backend);**真实 DirectGLES 插件重测**:avg 62.5µs / min 23.9µs / max 1644.1µs
- [x] **shm payload 零拷贝基准**:`ShmPayloadBenchmark`(C++:SessionCreate → 100× SubmitDataCommand+fd 回读 → destroy),avg 34.1µs / min 25.8µs / max 83.4µs(含 SCM_RIGHTS fd + mmap 回读);**当前重测**:avg 36.1µs / min 23.8µs / max 185.2µs(serverOk=1)
- [x] **命令批处理基准(batch 提交 vs 逐条)**:`CsRoundTripBench` 新增 `CsBatchRoundTrip`(16/64/256 批量发送后按 token 收响应);`ShmPayloadBenchmark` 支持 `batch` / `large` / `large-batch` 模式(64 条提交后批量等待 / 4MiB payload shm),输出 per-command/per-batch avg/min/max(待 Linux 构建回归记录实测值)
- [x] **平台 Surface(X11/Win32/Android 条件代码)**:`RealBackend` 增加 `SurfaceByName` handle 映射;`CreateWindowSurfaceBackend` 在 `_WIN32`/`__ANDROID__`/`__APPLE__`/`__linux__` 下走 `eglCreatePlatformWindowSurface` 或 `eglCreateWindowSurface`(Linux X11 用 `EGLNativeWindowType` 从 `nativeWindow` 转换);`ReleaseEGLSurface/ReleaseEGLResources/OnDisplayDestroyed/Shutdown` 同步清理 handle 表面;`SwapBuffers` 按 draw handle 选择表面(Linux 上无真窗口验证,仅代码路径)
## 下一步
1. **Phase 3(用户决策:本 session 跳过 DirectVulkan)**:DirectGLES 真实渲染层已接入;DirectVulkan 仍为 null 存根待后续迁移。
2. Phase 4 本次完成:全量 source-list 运行时分发 codegen(651/1396 supported)与 Token↔session 失效模型;剩余为把 unsupported 签名(多级指针/回调/Get* 输出)逐步补进生成器,以及 Query/Sync session-private 状态层。
3. Phase 6 本次完成:Win32/Android Surface 条件代码 + batch/大 payload 基准;待 Linux 构建回归后记录实测值。
4. 每完成一块:更新本文件 + 提交(`[Feat] (Scope): Subject`);单线串行推进,不使用 subagent 并行。