Mali pairs draw the display on the phone's own Mali driver; Xwayland falls back without glamor

- Testers' Mali pairs got the guest drawing (gamescope on the stand-in node, Zink on PanVK) but
  the compositor's PanVK Android half failed on Mali gralloc: it probes AHB formats 0x38/0x3b that
  mali_gralloc does not have, and "vkCreateImage w/ native buffer failed". Under Auto a Mali pair
  now leaves the display on the phone's own Vulkan driver (dma-buf, modifiers and AHB all pass the
  testers' checks) and runs the pair's PanVK in the guest; the Android half stays installed for a
  manual pick. "Pair in use" now follows the runtime half.
- A session after one whose Xwayland crashed (segfault, then gamescope's X11 I/O error) starts
  Xwayland with XWAYLAND_NO_GLAMOR=1 on a non-Adreno device, and says so in app.log.
- graphics-report.txt names the display driver the compositor used, and keeps gralloc, dma-buf,
  modifier and import lines from app.log and Xwayland's own lines from the session log.
This commit is contained in:
The412Banner committed 2026-10-12 21:19:49 -04:00
1 parent f12ae2f60d
commit e1b5309593
4 files changed
+31 -6

No files matched your search

@@ -277,7 +277,11 @@ internal class DriverMenus(private val activity: Activity, private val ui: Handl
ui.post {
pairBusy = null
pairPercent = -1
result.onSuccess { (displayId, linuxId) ->
result.onSuccess { (pairDisplayId, linuxId) ->
// A Mali pair under Auto: the compositor draws on the phone's own Mali driver
// (dma-buf, modifiers and AHB all work there) and the guest runs the pair's
// PanVK. Its Android half stays installed for a manual pick.
val displayId = if (auto && gpu.family.mali && DriverPairs.isNonAdreno(pair.key)) TurnipDriver.AUTO else pairDisplayId
val displayChanged = SessionPrefs.androidDriver(activity) != displayId
SessionPrefs.setAndroidDriver(activity, displayId)
SessionPrefs.setLinuxDriver(activity, linuxId)
@@ -30,8 +30,12 @@ object DeviceSupport {
* Whether an open non-Adreno driver pair (PanVK for Mali, RADV for Xclipse) is the one in use:
* it and the bridge are alternatives, and the pair wins. Always false on an Adreno.
*/
fun openDriverActive(context: Context): Boolean =
!adreno() && com.droiddeck.launcher.gpu.DriverPairs.isNonAdreno(com.droiddeck.launcher.gpu.DriverBundle.active(context)?.id)
fun openDriverActive(context: Context): Boolean {
if (adreno()) return false
// The runtime half is what counts: a Mali pair may run with the system driver as its display.
val linux = com.droiddeck.launcher.session.SessionPrefs.linuxDriver(context).ifEmpty { return false }
return com.droiddeck.launcher.gpu.DriverPairs.isNonAdreno(com.droiddeck.launcher.gpu.DriverBundle.containing(context, linux, true)?.id)
}
/**
* A session can draw: Adreno with Turnip, PowerVR/Xclipse on the system driver, an open
@@ -55,7 +55,9 @@ object GraphicsReport {
appendLine("-- path")
appendLine("path: " + path(context))
appendLine("driver mode: " + SessionPrefs.gpuDriverMode(context))
appendLine("display driver: " + SessionPrefs.androidDriver(context).ifEmpty { "(auto)" })
appendLine("display driver (compositor): " + SessionPrefs.androidDriver(context).ifEmpty {
if (DeviceSupport.adreno()) "(auto: bundled Turnip)" else "(auto: the phone's own Vulkan driver, ${SystemVulkanDriver.hal() ?: "vendor HAL"})"
})
appendLine("runtime driver: " + SessionPrefs.linuxDriver(context).ifEmpty { "(runtime default)" })
DriverBundle.active(context)?.let { b ->
appendLine("pair: ${b.name} ${b.version} (bundle ${b.id})")
@@ -137,12 +139,12 @@ object GraphicsReport {
private val COMPOSITOR = Regex(
"""vk_present|waylandcomp|vk_loader|compositor|vkCreateDevice|extension|adrenotools|TurnipDriver|""" +
"""graphics driver|SystemVulkan|vkbridge|VkBridge|mali_gralloc|panvk|PanVK|radv|MESA|native buffer|first frame|present|""" +
"""lsfg|FrameGen|device gates|AAudio|directaudio|pulse""",
"""lsfg|FrameGen|device gates|AAudio|directaudio|pulse|gralloc|dma.?buf|modifier|import""",
RegexOption.IGNORE_CASE,
)
/** The session script's driver lines: what it exported, the bridge's self-test, vulkaninfo, gamescope's Vulkan errors. */
private val GUEST = Regex("""== vulkan driver|== vkbridge|== vulkaninfo|vulkan:|panvk|PanVK|radv|primary node|No compatible|DRM format|kbase|AAUDIO|client sink""", RegexOption.IGNORE_CASE)
private val GUEST = Regex("""== vulkan driver|== vkbridge|== vulkaninfo|vulkan:|panvk|PanVK|radv|primary node|No compatible|DRM format|kbase|AAUDIO|client sink|Xwayland|\(EE\)|glamor|XWAYLAND_NO_GLAMOR""", RegexOption.IGNORE_CASE)
/**
* The end of the report, from the finished folder: the compositor's driver lines out of
@@ -307,6 +307,14 @@ class SessionService : Service() {
return lines
}
/** Whether the newest finished session's log shows Xwayland itself crashing. */
private fun lastXwaylandCrashed(): Boolean = runCatching {
val last = SessionPaths.sessionFolders(this).filter { it != SessionPaths.current() }.lastOrNull() ?: return false
val log = File(last, "session.log").takeIf { it.isFile } ?: return false
log.useLines { lines -> lines.any { it.contains("(EE) Segmentation fault") } } &&
log.useLines { lines -> lines.any { it.contains("X11 I/O error") || it.contains("Xwayland", ignoreCase = true) } }
}.getOrDefault(false)
private fun tuDebug(linuxDriverId: String): String? {
// Turnip's switch; a non-Adreno GPU runs another driver (PanVK, RADV, the bridge).
if (!com.droiddeck.launcher.core.DeviceSupport.adreno()) return null
@@ -648,6 +656,13 @@ class SessionService : Service() {
// An open Mali driver pair: /dev/mali0 stands in as the render node (LinuxRuntime.bindGpuNode)
// and the session shim answers gamescope's PRIME calls on it as on KGSL. It only covers
// libdrm's PRIME/GEM entry points, which PanVK on kbase never calls on its own device.
// Xwayland crashing in glamor (seen on Mali v9 with Zink on PanVK) left the last session at
// "X11 I/O error" before Steam: the next one on this device starts Xwayland without glamor
// (software 2D; Steam's GL still renders). Never on an Adreno.
if (!com.droiddeck.launcher.core.DeviceSupport.adreno() && lastXwaylandCrashed()) {
guest.add("XWAYLAND_NO_GLAMOR=1")
Log.w(TAG, "xwayland: the last session's Xwayland crashed; glamor off for this one (XWAYLAND_NO_GLAMOR=1)")
}
if (!bridge && com.droiddeck.launcher.core.DeviceSupport.openDriverActive(this)) {
LinuxRuntime.gpuStandIn(this)?.takeIf { it == LinuxRuntime.MALI_DEVICE }?.let { guest.add("BL_DRM_STANDIN=$it") }
}