From 82d96a63c936736666bb30e11bd463bed923aeda Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 2 Oct 2026 10:31:35 -0400 Subject: [PATCH] [Docs] (Anland): runbook and skill for bringing up MobileGL with anland and KDE Plasma --- .../anland-mobilegl-plasma/.gitattributes | 3 + .../skills/anland-mobilegl-plasma/SKILL.md | 151 +++++++++++++++++ .../scripts/build-android.sh | 24 +++ .../scripts/chrome-launch.sh | 19 +++ .../scripts/container/kwprep.sh | 29 ++++ .../scripts/container/mgrun | 21 +++ .../anland-mobilegl-plasma/scripts/ct.sh | 26 +++ .../anland-mobilegl-plasma/scripts/cyc.sh | 19 +++ .../scripts/device/bringup.sh | 29 ++++ .../scripts/device/restart-daemon.sh | 20 +++ .../scripts/device/run-plasma.sh | 26 +++ .../scripts/device/status.sh | 12 ++ .../scripts/device/swap.sh | 17 ++ .../scripts/device/switch.sh | 15 ++ .../scripts/device/unlock.sh | 8 + .../anland-mobilegl-plasma/scripts/env.sh | 41 +++++ .../scripts/kwin-stage.sh | 46 ++++++ .../scripts/probes/dmahash.c | 34 ++++ .../scripts/probes/texfmt.c | 95 +++++++++++ .../scripts/push-tools.sh | 22 +++ .../anland-mobilegl-plasma/scripts/rec.sh | 29 ++++ .../anland-mobilegl-plasma/scripts/shot.sh | 15 ++ .../scripts/sync-src.sh | 19 +++ .../anland-mobilegl-plasma/scripts/wsl-all.sh | 9 ++ .../scripts/wsl-test.sh | 13 ++ .../anland-mobilegl-plasma/scripts/xbuild.sh | 42 +++++ .../anland-mobilegl-plasma/scripts/xdeploy.sh | 40 +++++ .../scripts/xsysroot/aarch64-arch.cmake | 47 ++++++ .../scripts/xsysroot/refresh-sysroot.sh | 26 +++ docs/Disaggregated/notes/anland/README.md | 1 + .../notes/anland/runbook-plasma.md | 153 ++++++++++++++++++ 31 files changed, 1051 insertions(+) create mode 100644 .claude/skills/anland-mobilegl-plasma/.gitattributes create mode 100644 .claude/skills/anland-mobilegl-plasma/SKILL.md create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/build-android.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/chrome-launch.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/container/kwprep.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/container/mgrun create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/ct.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/cyc.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/device/bringup.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/device/restart-daemon.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/device/run-plasma.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/device/status.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/device/swap.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/device/switch.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/device/unlock.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/env.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/kwin-stage.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/probes/dmahash.c create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/probes/texfmt.c create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/push-tools.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/rec.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/shot.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/sync-src.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/wsl-all.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/wsl-test.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/xbuild.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/xdeploy.sh create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/xsysroot/aarch64-arch.cmake create mode 100644 .claude/skills/anland-mobilegl-plasma/scripts/xsysroot/refresh-sysroot.sh create mode 100644 docs/Disaggregated/notes/anland/runbook-plasma.md diff --git a/.claude/skills/anland-mobilegl-plasma/.gitattributes b/.claude/skills/anland-mobilegl-plasma/.gitattributes new file mode 100644 index 00000000..a90bc12d --- /dev/null +++ b/.claude/skills/anland-mobilegl-plasma/.gitattributes @@ -0,0 +1,3 @@ +# Everything here is executed by bash/sh on Linux, Android or WSL: keep LF even on a Windows checkout +# (core.autocrlf=true would otherwise hand sh a script full of $'\r'). +* text=auto eol=lf diff --git a/.claude/skills/anland-mobilegl-plasma/SKILL.md b/.claude/skills/anland-mobilegl-plasma/SKILL.md new file mode 100644 index 00000000..3585e6b8 --- /dev/null +++ b/.claude/skills/anland-mobilegl-plasma/SKILL.md @@ -0,0 +1,151 @@ +--- +name: anland-mobilegl-plasma +description: Bring up, rebuild, deploy, switch backends on, test and debug the "MobileGL + anland + KDE Plasma" stack - a rooted Android tablet whose anland APK embeds the MobileGL server, plus a Droidspaces Arch Linux ARM container running KWin/plasmashell/Chrome through the MobileGL client library and GBM backend - driven from this Windows machine (Git Bash, WSL archlinux, adb). Use it after a phone reboot, when changing server (NDK) or client (container glibc) MobileGL code or anland's KWin backend/patch, when switching Espryt/Magma, when validating zero-copy dma-buf presentation, and when chasing crashes, black windows, noise or software-rendering fallbacks in the Plasma session. +--- + +# MobileGL on anland KDE Plasma + +Human-readable runbook (Chinese, same content): `docs/Disaggregated/notes/anland/runbook-plasma.md`. +Background: `docs/Disaggregated/notes/anland/handoff-legacy-mobilegl-unified.md` (state, commits, known +issues) and `plan-ahb-dmabuf.md` (zero-copy design). All scripts are in `scripts/` next to this file; +parameters are documented at the top of each script and in `scripts/env.sh`. + +**The phone may be shared with another session.** Before anything that restarts the app, the daemon, +the container session or replaces a library, run the read-only `scripts/device/status.sh` and make sure +nobody else is mid-test. Use your own `ct.sh` channel names (others use c, c2, c3, xd, xr, gbm). + +## Architecture (10 lines) + +1. Phone: Lenovo TB321FU (Y700, Adreno 750, Android 15, kernel 6.1), rooted with **KernelSU** (`/data/adb/ksu`, `ksud`; `su -c` works). USB serial `HA27Q3LQ`, or wireless adb `ip:port`. +2. anland APK `com.anland.consumer.mobilegl` (debuggable build of anland branch `legacy-mobilegl-unified`): UI process + private service process `:mobilegl` (`MobileGLWorker`), which loads the **server** `libMobileGL.so` (NDK, from MobileGL `feat/disaggregated`) and listens on abstract socket `@anland-mobilegl`. One process serves every client (KWin, plasmashell, ksplash, Chrome...), one backend per process. +3. Backend = `setprop debug.mobilegl.backend DirectGLES|DirectVulkan` (Espryt = DirectGLES, Magma = DirectVulkan; prop lost on reboot) and must equal the container's `/etc/mobilegl/backend` (what every client reports; mismatch = "Hello.backendType disagrees with pinned backend"). +4. Experiment display daemon `/data/adb/modules/anland-daemon/display_daemon /data/local/tmp/anland-mobilegl/display.sock` (display/input broker; NOT started at boot - the module only starts the original one on `/data/local/tmp/display_daemon.sock`, leave that alone). +5. Container `arch-kde-mgl` (Droidspaces 6.4.5, Arch Linux ARM aarch64 glibc, host net, `rootfs.img` mounted at `/mnt/Droidspaces/arch-kde-mgl` on the Android side). Bind mounts: `/data/local/tmp/anland-mobilegl` -> `/run/anland-mobilegl`, `/data/local/tmp/display_daemon.sock` -> `/run/display.sock`. +6. `desktop-session.service` (User=swung0x48) has drop-in `ExecStart=/opt/mobilegl/bin/mobilegl-startup.sh plasma`, which writes a user drop-in for `plasma-kwin_wayland.service` (kwin_wayland_wrapper -> `/opt/mobilegl/kwin/bin/kwin_wayland` + `/opt/mobilegl/kwin/lib/libkwin.so.6.7.4`, `ANLAND_MOBILEGL=1`, `MOBILEGL_IPC_SURFACE=server`) and runs `startplasma-wayland`. +7. KWin 6.7.4 with anland's `anland` backend renders straight into the anland Android Surface through the server. Every other GL process is `MOBILEGL_IPC_SURFACE=offscreen` and presents through KWin. +8. Client = `/opt/mobilegl/lib/libMobileGL.so` (glibc aarch64): glvnd EGL vendor (`/opt/mobilegl/share/glvnd/egl_vendor.d/50_mobilegl.json`), GLX vendor (`/usr/lib/libGLX_mobilegl.so.0`, `__GLX_VENDOR_LIBRARY_NAME=mobilegl`), env `MOBILEGL_TRANSPORT=spawn MOBILEGL_IPC_DATA=shm MOBILEGL_IPC_CONTROL=unix:@anland-mobilegl`. +9. Zero-copy windows: client `wl_egl_window` frames are server-allocated AHardwareBuffer "shared images" exported as dma-buf fds over `zwp_linux_dmabuf_v1`; KWin imports them with EGL and the server recognises its own buffer by inode. KWin gets a DRM device via `GBM_BACKEND=mobilegl` -> `/usr/lib/gbm/mobilegl_gbm.so` (node is only an identity, never ioctl'd). Without linux-dmabuf the client falls back to wl_shm readback. +10. X11 apps (Xwayland) use the MobileGL GLX vendor with per-frame readback + `xcb_put_image`. Chrome runs ANGLE-GLES over MobileGL EGL with the GPU in-process (`mobilegl-startup.sh chrome`). + +## First-time prerequisites (Windows host) + +- Git Bash, `adb` (SDK platform-tools), CMake >= 3.22 and Ninja on PATH (seen: CMake 3.27.6, Ninja 1.13.2), Python 3 + Pillow (only `rec.sh`). +- Android NDK **27.2.12479018** at `%LOCALAPPDATA%/Android/Sdk/ndk/27.2.12479018` (override `ANDROID_NDK`). +- WSL distro **archlinux** with clang, lld, llvm, cmake, ninja. **lld's major version must equal clang/llvm-libs'** (lld 23 on llvm 22 broke `ld.lld`; working set: all 22.1.6). Then export the sysroot once: `bash scripts/xsysroot/refresh-sysroot.sh` (-> `~/sysroots/arch-kde-mgl` + `~/sysroots/aarch64-arch.cmake`; re-run after container package upgrades, then `xbuild.sh --reconfigure`). +- MobileGL worktree (never build in the shared main checkout): `GIT_LFS_SKIP_SMUDGE=1 git worktree add ...`, `git submodule update --init --recursive`, and copy `3rdparty/glslang/External/spirv-tools` from the main checkout (the submodule leaves it empty). +- anland worktree on `legacy-mobilegl-unified` (KWin patch/backend, startup script, `mobilegl-tools/`). +- Phone side that already exists and is NOT recreated by this skill: the APK (build: anland `consumers/anland_v5/android_consumer/MOBILEGL.md`, gradle `:app:assemblePlainDebug` with `MOBILEGL_DIST`, `-PmobileglApplicationId=com.anland.consumer.mobilegl`; reinstalling with another key changes the UID and needs the KernelSU grant again - `mobilegl-tools/ksu_grant.c`), the anland KernelSU modules (`anland-daemon`, `anland-awl`), the container with KWin's configured build tree `/root/mobilegl-build/kwin-6.7.4/build` and pristine `/root/gbm-dev/kwin-a/src`. +- Install the helpers once (container must be running): `bash scripts/push-tools.sh` (device/*.sh -> `/data/local/tmp/anl`, `mgrun` -> container `/usr/local/bin`, `kwprep.sh` -> container `/root`). + +Run host scripts from Git Bash as `bash scripts/.sh`. Raw adb with device paths needs `MSYS_NO_PATHCONV=1` and the whole root command in one quoted string: `adb shell 'su -c "..."'`. A device script can also be run without pushing: `MSYS_NO_PATHCONV=1 adb shell 'su -c sh' < scripts/device/status.sh`. + +## Bring-up after a phone reboot + +Nothing of the session survives a reboot. Either `adb shell 'su -c "sh /data/local/tmp/anl/bringup.sh [DirectGLES|DirectVulkan]"'`, or by hand, in this order: + +```sh +adb connect : # only for wireless debugging (e.g. USB cannot power it) +export MSYS_NO_PATHCONV=1 +adb shell 'su -c "svc power stayon true"' +adb shell 'su -c "setprop debug.mobilegl.backend DirectVulkan"' # or DirectGLES; match /etc/mobilegl/backend +adb shell 'su -c "am start -n com.anland.consumer.mobilegl/com.anland.consumer.MainActivity --es socket_path /data/local/tmp/anland-mobilegl/display.sock"' +adb shell 'su -c "/data/local/Droidspaces/bin/droidspaces -C /data/local/Droidspaces/Containers/arch-kde-mgl/container.config start"' +adb shell 'su -c "sh /data/local/tmp/anl/restart-daemon.sh"' # experiment display daemon, chmod 777 dir / 666 socket +adb shell 'su -c "sh /data/local/tmp/anl/run-plasma.sh"' # restarts app + desktop-session, ~90 s +``` + +`droidspaces` has no `status` command; `droidspaces show` lists running containers. Do not use the old +`/data/local/tmp/restart-daemon.sh` (it kills a hard-coded PID). Check with `device/status.sh`. + +## Build and deploy loops + +**Server (Android, NDK) -> APK lib** +```sh +bash scripts/build-android.sh # -> /build-android/libMobileGL.so (RelWithDebInfo, unstripped) +bash scripts/cyc.sh s1 # clear sticky SW-renderer key, push, swap into APK, restart session, screenshot $ANL_DIR/s1.png, print fatals +``` +`device/swap.sh` overwrites `/data/app/.../lib/arm64/libMobileGL.so` keeping owner/mode/SELinux context (original saved as `/data/local/tmp/anland-mobilegl/libMobileGL.so.orig`); no re-signing. To swap without the session restart: push to `/data/local/tmp/anland-mobilegl/libMobileGL.new.so`, `su -c "sh /data/local/tmp/anl/swap.sh"`, then `run-plasma.sh` anyway (KWin does not reconnect to a new server process). + +**Client + GBM backend (container glibc) via WSL cross-build** +```sh +bash scripts/xbuild.sh [--reconfigure] # WSL ~/mgl-xbuild-a64; ~150 s full, seconds incremental +bash scripts/xdeploy.sh # rename-into-place install of libMobileGL.so + mobilegl_gbm.so, aliases, vendor JSON +``` +Running clients keep the old inode; restart the client, or `run-plasma.sh` for KWin/plasmashell. Build server and client from the **same commit** (both stamp `git rev-parse HEAD`), else the logs WARN "compatible wire with different build". Fallback in-container build (slow): `scripts/sync-src.sh` + anland `mobilegl-tools/anland-build-client.sh`. + +**KWin (anland backend / kwin.patch) - built inside the container** +```sh +bash scripts/kwin-stage.sh build # stage CR-stripped patch+backend+startup script, kwprep.sh, background sync-build-kwin.sh +printf 'tail -5 /root/kwin-build.log\n' | bash scripts/ct.sh kw # wait for "== ALL DONE ==" +adb shell 'su -c "sh /data/local/tmp/anl/run-plasma.sh"' +``` +`sync-build-kwin.sh` (anland `producers/kde/Arch_v5/`) copies only the backend sources, then `ninja -j4`, installs `kwin_wayland`, `libkwin.so.6.7.4`, the patched screencast plugin and `/opt/mobilegl/bin/mobilegl-startup.sh` by atomic rename. `kwprep.sh` is what applies changed `kwin.patch` hunks to core KWin files. Repo-root `libdisplay_producer/` is not synced by either. `kwin-stage.sh` is assembled from those two scripts and was not run as one unit yet. + +**Unit tests (no device)** - in WSL (the MSVC build of this branch is broken): +```sh +MSYS2_ARG_CONV_EXCL='*' wsl -d archlinux -- bash /mnt/c//.claude/skills/anland-mobilegl-plasma/scripts/wsl-test.sh MultiSessionTest TwinOwnershipTest +MSYS2_ARG_CONV_EXCL='*' wsl -d archlinux -- bash -lc 'cd ~/mgl-anl-bld && ctest -R "MultiSession|TwinOwnership" -E DirectVulkan --output-on-failure' +``` +`wsl-all.sh` builds and runs every unit test. Never run DirectVulkan integration tests; never two ctest runs at once. + +## Switching backends + +`adb shell 'su -c "sh /data/local/tmp/anl/switch.sh DirectGLES"'` (sets the prop, writes `/etc/mobilegl/backend`, restarts the app), then `run-plasma.sh` - the running session's clients are pinned to the old backend. `cyc.sh` keeps whatever is set. + +## Test clients and how to verify + +Inside the container as root (`printf '...' | bash scripts/ct.sh `), `mgrun offscreen ` runs a client as swung0x48 in the live session (log `/tmp/mgl-run.client.log`, override base with `MGLOG=/tmp/x.log`): +```sh +mgrun offscreen eglinfo -B ; mgrun offscreen glxinfo -B +timeout 25 mgrun offscreen glmark2-es2-wayland -s 1280x720 --run-forever > /tmp/gm.out 2>&1 & +sleep 8; grep -a "presented through" /tmp/mgl-run.client.log +``` +Chrome: `bash scripts/chrome-launch.sh [flags]` (log `/tmp/mgl-chrome-.client.log`, screenshot `ch-.png`). +Probes: `scripts/probes/texfmt.c` (texture formats keep alpha?), `dmahash.c` (hash a process's dma-bufs); build in the container, e.g. `gcc -O1 /root/texfmt.c -o /usr/local/bin/mgl-texfmt -lEGL`, run with `mgrun offscreen`. + +A result counts only if ALL hold: +- client log says `presented through linux-dmabuf shared images` (not `wl_shm`; `could not be presented through a linux-dmabuf shared image` = fell back); +- `bash scripts/shot.sh g 2 1` gives two different hashes while the client animates (a "fast" score can mean frames are not shown); +- `adb logcat -b crash -d` and `adb logcat -d | grep -E "Fatal signal|Abort message|E MobileGL"` are clean (a frozen window is usually a dead server); +- for plasmashell verdicts, the sticky software renderer is off (below) and `/tmp/mgl-plasmashell.client.log` is freshly written. +Reference (glmark2-es2-wayland 1280x720, zero-copy vs wl_shm): Espryt 187 vs 49, Magma 158 vs 34. Rerun any surprising pass. + +## Logs + +| What | Where | +|---|---| +| KWin client side | container `/tmp/mobilegl-compositor.client.log` | +| plasmashell / ksplash | `/tmp/mgl-plasmashell.client.log`, `/tmp/mgl-ksplash.client.log` (user drop-ins `~/.config/systemd/user/plasma-{plasmashell,ksplash}.service.d/mobilegl-log.conf`) | +| mgrun / Chrome | `/tmp/mgl-run.client.log`, `/tmp/mgl-chrome-.client.log` (+ `/tmp/chrome--out.log`) | +| Server | `adb logcat -s MobileGL`; file `/data/data/com.anland.consumer.mobilegl/files/mobilegl-server.server.log` | +| Native crashes | `adb logcat -b crash -d`; container `coredumpctl list` | +| Session / KWin stderr | container `journalctl -u desktop-session --no-pager`, `journalctl --no-pager --since -2min \| grep kwin_wayland` | +| Display daemon | `/data/local/tmp/anland-mobilegl/display-daemon.log` | + +`MOBILEGL_LOG_FILE_PATH=/tmp/x.log` produces `/tmp/x.client.log` (and `.server.log` for forwarded lines); files are truncated on open, so one base per process. Client builds log at INFO. Symbolize server frames with `$ANDROID_NDK/toolchains/llvm/prebuilt/windows-x86_64/bin/llvm-addr2line.exe -Cfe build-android/libMobileGL.so `. + +## Pitfalls + +- **pkill -f self-match**: a `ct.sh`/`droidspaces run bash -lc "