gndrm-shim: redirect ION allocations on kernels without dma-buf heaps

Merged
UT
13d ago
+48-0

OpenGL games show a black screen with audio under gamescope on Snapdragon 865 devices (Retroid Pocket Flip 2, Galaxy Tab S7; Adreno 650, kernel 4.19 class) while the same games render on Adreno 735/830, and DXVK games render everywhere. Reported by RAHBOOTS for Gravity Circuit (LÖVE2D).

Why. Under gamescope a zink guest never creates a Vulkan surface (LIBGL_KOPPER_DISABLE, zink override), so its frames reach the screen through Xwayland's window buffers. Xwayland's Turnip allocates those through the kgsl backend: /dev/dma_heap/system when the kernel has heaps, otherwise /dev/ion with ION_IOC_NEW_ALLOC. The preload shim only redirects DMA_HEAP_IOCTL_ALLOC into the daemon's AHardwareBuffer pool, so on ION kernels the window buffers are plain ION dma-bufs, unknown to the daemon, and every commit is dropped. Vulkan guests get their slots over the explicit scan-out channel, which is why DXVK was unaffected.

Change. ion_scanout_redirect handles ION_IOC_NEW_ALLOC (0xc0184900, 24-byte struct, fd at offset 16) with the same scanout_redirect path, for system-heap requests only; everything else, and the legacy handle-based ION ABI, goes to the kernel as before. The fall-through log line prints the heap mask.

Verified on BrowserStack Galaxy Tab S7 (SM-T875, Android 11, board kona, dma_heap_system=false ion=true), Legacy app flavor, wrapper test gl/ under gamescope with the window held 90 s, payload base 20261027.1:

payloadshim logscreen
shipped 20261027.1no scanout: alloc lines at allblack for the whole hold
this shim (gamescope-ionredirect-b874c26-base20261027.1.tzst)scanout: alloc len=4096000 -> length-only request, heap alloc 4096000 B -> daemon buffer (by length) ... stride=5120 for every 1280x800 window buffer; small (106496 B) requests declined by the daemon and left to the kernelGL window visible, colour cycling

Test payload: https://downloads.gamenative.app/browserstack/gamescope-ionredirect-b874c26-base20261027.1.tzst (sha256 e1adb3df1917fbaba707435ac6df845dc30e4b6e341768d5bc57cfaef311b81c), only lib/libgndrm_shim.so replaced (sha256 a00773e4680896074c22b58565f5258529c96efb2068dce68f4810440775e648).

Seen in the fixed run and not addressed here: the daemon turned down the first three 4096000 B requests with "unsupported geometry/format" (errno 22) for about 1.2 s after start before accepting them; the window still appeared. A daemon-side fallback that copies any non-pool buffer into the pool, so a missed allocator never goes black again, is coming as a separate PR.