mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
6.5 KiB
6.5 KiB
帧节奏、进程、EGL 与平台(原 ARCHITECTURE §14–§15)
设计细节。设计要点与全部章节的索引见
../ARCHITECTURE.md。章节编号沿用原ARCHITECTURE.md,代码注释里的ARCHITECTURE.md §N按编号在这里找到。
14. Present、线程与帧节奏
eglSwapBuffers→present{frameSerial}→ publish + 敲门铃 → 返回,除非超出 credit;present与eglSwapBuffers严格 1:1(后端的帧边界排空只在Present内发生)。MOBILEGL_IPC_PRESENT_CREDIT默认 1(range 1..8):credit 是 run-ahead 唯一的稳态背压,FrameSerial由 client 铸造、1 起算,server 在Present()返回后归还 credit;等待发生在编码之前。credit > 1 从未量过(P10)。- 预算(~850 draw/帧):
SEG_CMD~70 KB/帧,SEG_STAGE~1 MB/帧;跨机时这 ~1 MB/帧对着的是 Wi-Fi。 - 线程:client v1 不加线程,编码在 GL 线程直接写 ring;server 有 io 线程与终身持有原生 context 的
mgl-srv-apply。全库无有效亲和性控制(Redmi 内核忽略 app 线程的sched_setaffinity)。 - 拆机顺序:publish + server 排空 → 停 apply 线程 → 关传输 → client 排空编译池 →
MobileGL::Destroy()(落地形状见 §17)。
15. 进程、EGL 与平台(P6 / P6.5 / P12)
15.1 启动与握手
- 端点:
fork(socketpair+fork/execve,fd 3 = socket;server 由MOBILEGL_IPC_SERVER_PATH或dladdr同目录的libMobileGLServer.so定位)、unix:<path>、tcp://host:port。设备侧 supervisormobilegl_server_main <endpoint> --serve:listen → 认证 → 每会话 fork 一个子进程(或进程内线程,P12),同时只服务一个会话,第二个连接Refuse{Busy}。 - server 进程里
Transport读作Spawn,不强制 monolith(两百多处Transport != Monolith判断靠它选 server 臂;CONTRACT-P6.md§3.1 修订了原"子进程强制 monolith"的规则)。防无界 fork 链靠不继承的Dial == No(MOBILEGL_IPC_DIAL=no),spawn 时构造的 envp 剔除MOBILEGL_TRANSPORT与MOBILEGL_IPC_*作第二道独立保险;server 主程序自设MOBILEGL_IPC_ROLE=server。 Hello(abi、后端类型、指纹、配置、令牌、LinkTerms请求)→Welcome(server 陈述的尺寸、段 / aux 名、dataNonce、真实 pid)或Refuse{code, detail, 对端值};握手路径零 abort。非 loopback 监听必须有令牌(≥16 字节、常量时间比较、数据面按dataNonce绑定到已认证的控制连接、fork 前认证;Ph,OQ-21 裁定不做 TLS)。- TCP keepalive / 心跳失败由传输层报告为挂断,进 device-lost 闩;"闩绝不取自 apply 超时"不因此松动。冷启动期 server 发
SurfaceProgress,client 预算这段沉默(控制修订 2)。
15.2 Android
- 交付链(spike A 已证):APK 唯一可 exec 的位置是
lib/<abi>/,server 以add_executable+lib*.so命名构建;从untrusted_app进程fork+execve同域、零 avc denial;posix_spawn在 minSdk 26 不可用。一份共享库两个角色(stubdlopen+dlsym("mobilegl_server_main"))。 - 离屏 server:前台
MobileGLServerService(:mglsrv),从nativeLibraryDirexec,fork-per-session,EGL 是 pbuffer / surfaceless。 - 上屏 server(P12 子集):窗口归 server 自己(client 的窗口不跨进程)。
MobileGLDisplayActivity(:mglwin)持全屏 SurfaceView,在自己的进程里用一个线程跑 TCP server(会话串行、会话间重置闩、后端按进程钉住);ServerDisplay以 acquire / release / 几何三个钩子持有窗口,apply 线程以租约使用它。client 设MOBILEGL_IPC_SURFACE=server后无头:eglCreateWindowSurface(NULL)发一帧WindowKind::ServerOwned(控制修订 3),不发SetWindowHandle,尺寸由 reply 带回,resize 变成对 server 窗口的几何请求;client 没给EGL_WIDTH/HEIGHT(SDL)时取 native window 的大小作请求,server 把窗口缓冲固定成它并等比留黑边(不然横屏游戏在竖屏窗口里被裁)。FCL 只能接外部 server(自带 spawn 会把窗口指针发过来,被 Rule H 拒),且要开版本设置「游戏退到后台时不暂停」,否则 FCL 一退后台游戏就暂停(MG_Remote/CONTRACT-P12.md)。一台设备同一时刻一个 server;一个会话一种表面模式(SurfaceModeMismatch);无显示的 server 对 ServerOwned 具名拒绝(NoServerDisplay)。 - 失窗:
surfaceDestroyed有界(3 s)阻塞,直到 apply 线程(批内每条记录前也检查)放掉后端表面并以Fatal{ServerWindowLost}闩住会话;server 继续监听。进程内会话结束时手动做进程退出本来白给的清理(Espryt twin 与单元影子、swap interval、Magma renderer)。 HeadlessGL的 fork 预检会产生孤儿 server:server 的 EOF 检测即时且无条件退出。
15.3 Linux / Windows / 崩溃
- Linux / WSL / CI 永不开窗(
EGL_PLATFORM=surfaceless);Wayland 不支持。Windows / 桌面 client 在 TCP 终局下是真实形态(Windows 是第二批,开放问题 22);macOS 不拆分;Windows 机器不是正确性门。 - server 死:client 读到挂断 → device-lost 闩(GL 调用 no-op、
eglSwapBuffers返回EGL_CONTEXT_LOST、reset statusGL_UNKNOWN_CONTEXT_RESET);Session::Fail漏斗向对端发SessionFault帧命名家族(FatalFamilies.def)。闩之前创建的 context 永久丢失(eglMakeCurrent/eglSwapBuffers返回EGL_CONTEXT_LOST,glGetError报一次GL_CONTEXT_LOST,销毁时不往新 session 发任何记录)。进程可恢复(MOBILEGL_IPC_RECOVER,默认 1):应用下一次eglCreateContext/eglCreate*Surface/eglInitialize拆掉丢失的 session、重新拨号得到新 session,client 侧描述旧 server 的缓存全部清空(发布闩、CSO/sampler 缓存、emitter 闩、create window、applier-reset 序号、persistent map),wire epoch 前进使旧 GLContext 一律视为丢失;surface 保留并在下次 make-current 时于新 session 重建(EGL 对 power-management 事件的语义),Wayland 窗口的 shared image 在新 session 重新分配。in-process server 与fd:对不可重拨,仍是永久丢失。MOBILEGL_IPC_RESPAWN(server 重启后全量重推)仍是具名拒绝。client 死:server 读到 EOF 立即销毁 context 并退出(supervisor 继续服务下一连接)。