Skip to content

[Draft] freedreno/kgsl: add opt-in renderonly and X11 presentation support for leased KMS displays - #101

Draft
KiralyCraft wants to merge 16 commits into
lfdevs:dev/adreno-mainfrom
KiralyCraft:fix/kgsl-leased-screen
Draft

[Draft] freedreno/kgsl: add opt-in renderonly and X11 presentation support for leased KMS displays#101
KiralyCraft wants to merge 16 commits into
lfdevs:dev/adreno-mainfrom
KiralyCraft:fix/kgsl-leased-screen

Conversation

@KiralyCraft

Copy link
Copy Markdown

I have been working on getting a normal accelerated Xorg desktop onto the external display of an Android device, while Android keeps running on the phone's own screen. This is the Mesa side of that work, tested on a Sony Xperia 1 V / Adreno 740 with LineageOS and a Linux chroot. This patch would only work on chroot devices with REAL ROOT. Moreover, it requires patched OS composer binaries, but this can be done with Magisk for your particular device.

This is separate from #96's ordinary Termux:X11 fence/performance work, but currently depends on its native render-fence support. Please keep this as a draft until that dependency is resolved and the remaining correctness checks below pass. Installing this Mesa alone does not enable HDMI leasing.

What this adds

  • An opt-in FD_KGSL_RENDERONLY=1 path, keeping the KMS/control descriptor separate from /dev/kgsl-3d0, which is used for GPU submission. It uses Mesa's renderonly helpers for KMS-compatible scanout allocation and recognizes downstream Qualcomm's msm_drm device name.
  • An opt-in X11 bridge for the case where ordinary client-exported KGSL buffers render correctly in the client but appear black when Xorg consumes them. The application renders into native KGSL buffers; a worker imports Xorg-owned destination pixmaps and GPU-blits the selected frame into them. X Present then displays those pixmaps. There is a CPU/MIT-SHM fallback when the GPU destination path is unavailable.
  • Event-driven presentation and buffer reuse, with producer render fences and Present events rather than polling timers. This is one GPU copy for a selected frame on the GPU path, not a claim of end-to-end zero-copy.
  • Ordinary MESA_LOADER_DRIVER_OVERRIDE=kgsl clients still open KGSL directly unless renderonly is explicitly requested. Termux:X11 does not supply a DRI3 Open device fd, so unconditionally requesting one breaks ordinary GLX context creation. The HDMI compatibility fix covers this with an eight-case device-selection regression test.

The working client path uses MESA_KGSL_X11_SHM_BRIDGE=1 together with MESA_KGSL_X11_GPU_BRIDGE=1. The SHM name is historical: GPU mode imports server-owned DRI3 pixmaps and does not normally perform the CPU readback. The Xorg server uses renderonly; bridge clients render directly on KGSL. These roles must not be given the same renderonly environment indiscriminately. Our bridge configuration keeps ordinary Freedreno tiling enabled; noubwc is used for the CPU-visible fallback, not notile.

What Android's composer must provide

Mesa does not create the lease or speak an Android composer protocol. It needs a working KMS-backed Xorg/DRI3 server. In our Android setup, making that server possible requires a cooperating, patched Qualcomm composer:

  1. Composer remains the DRM master and identifies the active external connector, CRTC and that CRTC's fixed primary plane. It pauses external HWC updates without shutting off the negotiated external timing. The internal phone display is not part of the lease.
  2. The final handoff is serialized against SurfaceFlinger command batches. Every plane still assigned to the external CRTC must be detached and sanitized, not just the primary. On this Qualcomm stack that includes source/destination geometry and supported private scaler/exclusion state. Otherwise Android overlays can remain above Xorg, or stale state can make the first modeset fail. Our implementation tests, commits and verifies the reset before proceeding.
  3. Composer calls drmModeCreateLease() for the external connector, CRTC and fixed primary plane, and transfers the fd to the trusted broker using SCM_RIGHTS. Our implementation has a root-only abstract Unix socket, hdmi-los-composer-v1, authenticated with SO_PEERCRED. That socket is project-specific plumbing, not a new Mesa requirement or standard HWC API.
  4. The handoff reports physical connection, lease readiness and active mode. The agent starts Xorg with the lease fd via -masterfd, inheriting the established Android timing rather than forcing 1080p. Composer must keep its HWC/SurfaceFlinger power, fence and hotplug lifecycle coherent while the external display is leased; stopping SurfaceFlinger is not the design.
  5. Release must revoke the lease and restore composer's cached plane/CRTC and power/update state. Broker loss, lease expiry, secure-display entry, and physical unplug need recovery paths. Continuous sessions renew an independent composer watchdog; they do not disable recovery. Unplug teardown is coordinated with stopping Xorg, not performed unsafely inside the HWC hotplug callback.

The kernel/display stack also needs DRM leases, usable KMS buffer allocation, PRIME/dma-buf sharing between KMS and KGSL, and working page-flip/vblank events. This is device-specific: stock composer does not expose our lease endpoint, and the Qualcomm patches must preserve the vendor display-extension ABI and have suitable SELinux permissions. They are not portable drop-in binaries.

The companion implementation and exact patch series are in LineageOS-Linux-HDMI, particularly its architecture and composer patches. Those Android changes are outside this Mesa PR. The tested Xorg also uses the upstream modesetting TearFree work to avoid cursor-motion cadence collapse; the Mesa bridge alone is not a replacement for that server-side behavior.

What has actually been tested

The tested combined candidate is a522d4e1 (HDMI plus the current #96 fixes), on its existing 26.2.0-devel base, not a newly rebased 26.3 upstream build. Its GLX/EGL/Gallium/GBM stack passed ordinary Termux:X11 pixel, MSAA, resize, context-switch and imported-native-fence checks. Short uncapped gears A/B testing showed no meaningful ordinary Termux:X11 regression from adding HDMI.

On a real leased 1280x720@60 output, LXDE and OpenGL applications were visible. A 30-second SDL test with a visible cursor moving at 120 Hz measured about 59.997 active captured updates/s, with no detected torn frames or skipped source IDs. This was a source-frame/capture check, not just client FPS. The capture timestamps are quantized, so these are not exact scanout timings.

The combined client libraries also improved the same-server HDMI comparison from about 908 to 2027 FPS in uncapped glxgears, and from 688.5 to 2086 in glmark2, at 640x480. Those gains include the #96 performance fixes: they are NOT an isolated speedup claim for this HDMI-only series.

Still unresolved

  • Strict GLX post-swap pixel checks can read the previous image. The bridge advances recv_sbc when work is queued rather than when its presentation completes, so glXWaitForSbcOML can return too early. This also reproduces with the older HDMI client libraries and must be fixed in the HDMI path.
  • Some failing test clients abort during cleanup with glsl_type_cache.users > 0.
  • vkmark ran but its HDMI window was black with the unchanged Turnip library. Its score is not a valid displayed-performance result, and this Gallium/DRI bridge is not a Vulkan WSI fix.
  • The optional shadow-present path and unplug/replug recovery still need validation on the combined candidate. The initial pixel-check failure also prevents claiming the later HDMI resize/front-buffer/context checks passed.

I do not call this merge-ready. It works, it's reliable, but it's currently brittle. The performance on the leased X display is amazing, however! It's like a real desktop. It works flawlessly; I could not tell I am on a phone.

This work was assisted by Codex GPT 5.6 Sol xHigh. I used up 3 resets on this!

KiralyCraft and others added 16 commits August 14, 2026 00:54
Keep deferred submit objects alive until KGSL has consumed their command lists and populated the shared kernel timestamp. This prevents BO teardown from freeing GPU addresses that the merged submission still references.
The HDMI loader stopped honoring the ordinary KGSL device override and always requested a server DRI3 fd. Termux:X11 supports imported DRI3 pixmaps but has no open-device callback, so the otherwise clean PR96/HDMI merge could not create a GLX context.

Preserve direct KGSL selection unless renderonly is explicitly enabled. Bridge clients also retain native KGSL rendering. Parse the bridge option consistently with the DRI loader, including true/false values. Do not add a fallback that could discard a required KMS fd.

Add a hardware device-selection regression test covering eight ordinary, bridge, renderonly and other-driver configurations without GPU submission or display changes. The merged AArch64 GLX/EGL/Gallium/GBM stack passed Termux:X11 pixel, MSAA, resize, context-switch, imported-fence, burst and cadence checks, plus native BO-handle and real KMS framebuffer allocation tests. Full leased HDMI scanout remains a separate acceptance gate.

(cherry picked from commit a522d4e1a1fd1ff610d8d13dfefeb6ec6171a44d)
@KiralyCraft

Copy link
Copy Markdown
Author

I should look into whether any further copies take place here, because we currently copy from the GPU into an xorg-owned pixmap (and who knows what Xorg is doing then); Otherwise things appear to be rendering fine, but the actual render is black when presented to the user. So far it works, but improvements may be done for the actual data path, to make it more efficient. Since Qualcomm's implementation can also crash my SoC, I'm taking a break for now. We'll see how long I can put this off 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant