diff --git a/docs/Disaggregated/notes/anland/handoff-legacy-mobilegl-unified.md b/docs/Disaggregated/notes/anland/handoff-legacy-mobilegl-unified.md index 38e3b804..ef8386b2 100644 --- a/docs/Disaggregated/notes/anland/handoff-legacy-mobilegl-unified.md +++ b/docs/Disaggregated/notes/anland/handoff-legacy-mobilegl-unified.md @@ -15,6 +15,10 @@ anland 5.x 用 MobileGL:容器(Droidspaces,arch-kde-mgl)里的 Linux cli | Commit | 内容 | |---|---| +| `4b388950` | Magma:VAO/元素缓冲指向一个 server 没有存储的 buffer(client 构造时就铸 handle,create 只随第一次 respecify 过线)时拒绝该 draw 而非 Fatal;纹理的内置 sampler CSO 缺失或已回收(CSO 按内容寻址、满 256 回收)时按 GL 默认参数采样——两处都与 DirectGLES 的「decline」行为对齐。glmark2 全场景(refract/effect2d 此前带走 server)通过 | +| `7e76a98d` | **Magma 多 surface + 多 context**:一个 session 一个 `VulkanRenderer`(device 与全部 GL 资源),每个客户端 EGLSurface 只是一个「surface target」(VkSurfaceKHR + swapchain + render-finished 信号量 + 已获取图像 + pbuffer 的 AImageReader),切换时提交当前工作、用一次空提交消耗挂起的 acquire 信号量后停放,回来时原样换回(`ActivateSurfaceTarget`/`DestroySurfaceTarget`,此前每次切 surface 都重建整个 VkInstance/VkDevice,所有 buffer/纹理丢失 → Chrome `unknown-buffer-respecify`);默认帧缓冲 render pass 的 hash 带 target 序号;`bind_context` 时 Magma 后端切回该 context 最后一次 make-current 的 surface(`OnClientContextBound`,Qt 每窗口一线程一 context,此前读回落到别的窗口的 pbuffer);**wire resource ops 表在 server 进程里只要有 session 活着就不注销**(此前任一 session 的 renderer 关闭——比如 ksplash 退出——都把进程级表清空,之后所有 session 的 buffer create 被静默丢弃:plasmashell 面板/弹窗全透明) | +| `15dbe78c` | **Magma 按 session 隔离**:Magma 原本一进程一 renderer,`pVulkanRenderer`、`g_activeBufferManager`、动态状态影子、render pass manager 的静态指针、各 `s_device`、renderer generation、swap interval 都是进程全局——多 session 下 KWin 的 buffer 写落进别的 session 的表(`buffer-write-range` Fatal)。新增 `MagmaSession`/`SessionLocal`(`MG_Backend/DirectVulkan/MagmaSession.h`):按调用线程绑定的 session 解析,未绑定线程(monolith、client、单测)用进程默认 session,行为不变;served session 的 apply 线程在 `ServerLoop::ApplyThreadMain` 里经 `BackendObject::BindSessionStateToThisThread` 绑定;扩展函数指针改成 renderer 成员;哈希 scratch 状态、scratch 向量改 thread_local | +| `168808d1` | Magma 也广告 GL_ARB_shader_objects/vertex_shader/fragment_shader/texture_non_power_of_two(KWin `checkSupported` 门槛,此前 KWin 在 Magma 上 "Could not initialize rendering context");Android 上 `debug.mobilegl.backend` 系统属性可覆盖 `MOBILEGL_BACKEND_TYPE`(可调试 APK 换后端无需重签) | | `cd610934` | **锁屏花屏/桌面变噪点的根因**:`object_death` 记录到达 server 时,`SlotTable::ReleaseTwinByHandle` 遍历进程内**所有** slot table(所有 session 的所有 bucket)释放该 handle 的 twin。handle 是各 client 自己的分配器编号,不同 session 的同一 `{slot, gen}` 是各自不相干的活对象——锁屏 greeter 退出时删除自己的纹理,同时把 KWin 同 handle 的 twin 也释放了(KWin 正在用的 driver 纹理被删,plasmashell 窗口采样到已释放显存:噪点 + 别的窗口的残影)。现在 slot table 记录自己所属 session,释放只走调用线程 session 的 bucket(同 session 的各 share group 都释放;无 session 的线程保持全进程遍历)。顺带修掉另外两类跨 session 隐患:DirectGLES 进程级「容器对象」(scratch/blit/resolve FBO、staging FBO、模拟绘制的 VAO)改为按原生 context 分(`PerNativeContext`/`NativeContextName`,按 context 生命期序号,context 销毁时遗忘);UBO/unpack/upload 三个持久映射 ring 改为每原生 context 一套,帧 fence 完成水位改为「连续」(任一更早的 fence 未 signal 都不前进,fence 环加深到 32 且回绕时等待旧 fence 而非丢弃) | | `4236b42a` | server:配置只在进程内第一个 session 接入时初始化一次——此前每个新 session 接入都重跑 `MG_ConfigLoader::Init()`,它先把 `Transport` 写回 Monolith 再被改回 Spawn,正在 apply 的别的 session 恰好读到就跳过 server stamp,`Fatal{UnmigratedPipeInput, "GetBoundVertexArray@DrawArrays"}` 带走整个 server 进程(整个桌面);转译:保留下来的非零 `layout(index = 1)`(双源混合)在 ESSL 里加 `#extension GL_EXT_blend_func_extended : require`(此前 Adreno 拒绝该 stage,程序整体不画) | | `0b6842ac` | 让 ANGLE 的 GL 后端跑在 MobileGL 上:EGL 声明 `EGL_KHR_platform_gbm`/`EGL_MESA_platform_gbm`(GBM display 当离屏 display,拒绝 gbm 窗口 surface;Chrome 的 Wayland GL 层对每个 display 都标 GBM 平台);平台标 GBM 但 native display 实为 wl_display 时按 Wayland 处理,wl_display 识别兼容自带一份 libwayland 的程序(按接口名 "wl_display" 判断,经 `process_vm_readv` 读,野指针不会崩);实现 `glGetShaderPrecisionFormat`(此前是空 stub,ANGLE 读到 0 精度即拒绝 ES 2.0);`GL_VERSION` 里不再出现 "OpenGL ES" 子串(ANGLE 用子串搜索判断 ES 驱动,"Direct (OpenGL ES) Backend" 让它把 MobileGL 当 ES 驱动、按 ES 扩展名查 BGRA 等能力,Chrome 的 shared image 全部创建失败) | @@ -34,6 +38,7 @@ anland 5.x 用 MobileGL:容器(Droidspaces,arch-kde-mgl)里的 Linux cli | Commit | 内容 | |---|---| +| `5f15240` | 会话可选后端:APK 的 `:mobilegl` worker 从 `files/mobilegl-backend` 读后端(`am start ... --es mobilegl_backend DirectVulkan` 写入),容器侧 `mobilegl-startup.sh` 从 `/etc/mobilegl/backend` 读并导出给 KWin drop-in 与 dbus 激活环境(server 一进程只服务一种后端,client 必须报同一种,否则 "Hello.backendType disagrees with pinned backend") | | `56b060c` | 恢复工具链入库 `producers/kde/Arch_v5/mobilegl-tools/`(KernelSU grant helper、源码同步与容器内 client 构建、EGL smoke 探针、设备侧部署/daemon 脚本) | | `1fb419a` | mobilegl-startup.sh:默认 socket 指向实验 daemon(/etc/environment 的 pam_env 会盖掉 systemd drop-in);plasma 模式改走 kwin_wayland_wrapper(BusName=org.kde.KWinWrapper 只在 wrapper 注册,直跑 kwin 90 秒被 systemd 杀);KWin 直写 surface 不加 FlipY(此前画面上下颠倒);sync-build-kwin.sh 容器侧 canonical 同步/增量构建/原子安装管线 | | `118ae52` | `MOBILEGL_BACKEND_TYPE=DirectGLES`(Espryt 只是别名,写错会被 pinned-backend 拒);eglChooseConfig 收 count≥1(MobileGL 默认有两份配置);compositor client 日志落文件 | @@ -55,6 +60,7 @@ anland 5.x 用 MobileGL:容器(Droidspaces,arch-kde-mgl)里的 Linux cli - **多 session**:两个 win-smoke 连续运行同一窗口均 exit 0(stale surface 修复生效)。 - **Chrome 跑在 MobileGL 上(2026-10-02)**:会话的 Chrome 启动项(`mobilegl-startup.sh chrome`,plasma 模式写入用户级 `google-chrome.desktop` 覆盖)用 `--use-gl=angle --use-angle=gles --in-process-gpu --render-node-override=<不存在的节点> --disable-features=WaylandFractionalScaleV1`:ANGLE 报 `ANGLE (MobileGL-Dev…, Espryt…, OpenGL 4.6.0 MobileGL…)`,GPU 合成开启,标签栏/工具栏/网页正确合成,缩放正确。为什么这样配:Chrome 的独立 GPU 进程在 Wayland 上只能经 GBM dma-buf 上屏(MobileGL 与本 KWin 都不收),放进浏览器进程后改走 wl_egl_window(MobileGL 的 wl_shm 呈现);该路径下 Chrome 不发 fractional-scale 的 viewport,整数缩放才会发 `set_buffer_scale`。此前镜像自带的 `/usr/local/bin/google-chrome` 是 `--use-angle=vulkan` + renderD128,走的是容器里的 Turnip。 - **Plasma 桌面可用(2026-10-02,`ccf8eb65`:server 与容器 client 同源)**:壁纸、面板、托盘、时钟、桌面图标、Kickoff 开始菜单、通知窗口都正确渲染;鼠标/触摸输入可用(点击打开 Kickoff);KWin 过渡动画正常;开/关托盘弹窗不再花屏;按返回键收起快捷键栏时输出 resize 跟随。三线程/三 context/三 surface 并发回读探针(`anland-egl-mt-readback-probe.c`)与大纹理分块上传探针(`anland-egl-upload-probe.c`)全过。 +- **Magma(DirectVulkan)与 Espryt 同等可用(2026-10-02,`4b388950`)**:KWin 合成(约 140 fps,apply 2–3 ms/帧)、plasmashell 真正经 Magma GPU 渲染(壁纸、面板、托盘、桌面图标、带模糊的 Kickoff、通知弹窗;托盘里不再有「正在使用的软件渲染器」)、glxinfo 报 `Magma (MobileGL Core) (Adreno (TM) 750, Vulkan 1.3.128…)`、glmark2(X11)全 16 场景跑完 score 47、glmark2-es2-wayland score 50、Chrome 正常(剩余问题与 Espryt 相同:WebGL 画布空白、扩展图标黑块)、`kscreenlocker_greet --testing` 正确渲染且退出后桌面无噪点。切后端:`setprop debug.mobilegl.backend DirectVulkan` + `/etc/mobilegl/backend` 写同名 + 重启 APK 与会话。 - **Plasma 会话(早期,`30fef23d` 的 server + `ff212061` 的容器 client)**:`desktop-session.service` 持续 active(>1 分钟,此前约 7 秒必拆);面板完整渲染(启动器、固定应用、托盘、时钟);光标尺寸正常;多个 session 并发、逐个 reap 而其余继续服务。截图里壁纸有横向条带错位(见下面第 1 条)。 ## 未完成 / 已知问题(按优先级) @@ -67,6 +73,8 @@ anland 5.x 用 MobileGL:容器(Droidspaces,arch-kde-mgl)里的 Linux cli - DirectGLES 里少量进程级「容器」对象(resolve FBO、scratch FBO、XFB helper、timer query 探测)不在 share group 里共享,多 session 交替使用时理论上会拿到别的 context 的名字——尚未观察到症状。 - **Chrome 剩余渲染问题**:WebGL 画布不显示(get.webgl.org 的立方体区域空白、aquarium 只有底色,fps 计数正常),工具栏两个扩展图标是黑块;两边日志都无报错,待查(怀疑 shared image 的某种格式/swizzle 或画布合成路径)。 - ~~锁屏界面花屏~~ 已修(见上表):复现方式 `kscreenlocker_greet --testing` 起一个测试模式 greeter 再杀掉(本会话的 logind session 类型不支持 `loginctl lock-session`,真锁屏后只能输密码解锁);修复前几乎每次都让桌面/面板变噪点,修复后多次 + 并发 client 压测均正常。定位手段:给 `BackendTextureObject` 记录创建 session,析构时 session 不符就打 `_Unwind_Backtrace` 栈(符号用 NDK `llvm-addr2line` 对未 strip 的 build-android/libMobileGL.so 解)。 + - **Plasma 的软件渲染回退是粘滞的**:server 崩溃时 plasmashell 收到 device lost,Plasma 会把 `[QtQuickRendererSettings] SceneGraphBackend=software` 写进 `~/.config/kdeglobals`,之后每次会话都用 CPU 渲染 Qt Quick(托盘出现「正在使用的软件渲染器」图标),即使 GL 已经修好。排查任何 plasmashell 渲染问题前先确认该键不存在:`kwriteconfig6 --file kdeglobals --group QtQuickRendererSettings --key SceneGraphBackend --delete`。 + - Magma 每个 session 自建 VkInstance/VkDevice(无跨 session 共享),首帧 apply 约 100 ms;内存开销随 client 数线性增长。 2. **光标巨大化**:2026-10-02 的 Plasma 会话截图里光标尺寸正常,未再复现;若再现,查 output scale 与 cursor layer 的 buffer scale。 3. **CPU blit 禁令**:用户明确要求最终形态上屏路径无 CPU blit——当前 Wayland wl_shm client 走 readback(`32c79f41`),只是过渡。目标:应用窗口内容也由 server 在 GPU 侧直接给 KWin 合成(server 侧 GPU buffer → 同进程共享给 compositor 的 share group → 合成上屏),不经过 CPU 回读。设计要进 11-state-ownership.md 的后续切片。 4. **GLX 上屏是 CPU 回读**:每帧整幅 glReadPixels + `xcb_put_image`,同第 3 条的过渡方案;只处理 24/32 位深窗口;直接拿 X 窗口(未经 glXCreateWindow)当 drawable 的 surface 不会随窗口销毁回收。