Skip to content

Backends/DRM: add --prefer-drm to select the scanout device independently of the Vulkan device#2220

Open
relil wants to merge 1 commit into
ValveSoftware:masterfrom
relil:feature/prefer-drm
Open

Backends/DRM: add --prefer-drm to select the scanout device independently of the Vulkan device#2220
relil wants to merge 1 commit into
ValveSoftware:masterfrom
relil:feature/prefer-drm

Conversation

@relil

@relil relil commented Jun 16, 2026

Copy link
Copy Markdown

Problem

init_drm() derives the KMS/scanout device from the selected Vulkan physical device (vulkan_primary_dev_id()drmGetDeviceFromDevId()DRM_NODE_PRIMARY). So choosing the render GPU with --prefer-vk-device also forces scanout onto that GPU. On hybrid / eGPU / muxless / split-SoC systems where the render GPU is headless (or is a different device from the display controller), gamescope picks a node with no connectors and fails:

drm: opening DRM node '/dev/dri/cardX'
drm: '/dev/dri/cardX' is not a KMS device
vulkan_make_output failed

i.e. a black screen, with no way to say "render on GPU A, scan out on display GPU B". Requested in #1004; same root cause as #2070 (ARM rockchip + panthor) and #1324.

Change

Add --prefer-drm <device> to choose the DRM/KMS scanout device independently of --prefer-vk-device. -O/--prefer-output still selects the connector within the chosen device. The value is also read from the GAMESCOPE_PREFER_DRM environment variable when the flag is absent, so a session manager can configure a split setup without per-game launch options.

  • Accepts /dev/dri/cardX, the short cardX, and /dev/dri/by-path/…-card symlinks (resolved via realpath).
  • Validated up-front in main() (before Vulkan/session init, so bad input fails fast) by inspecting the device number — DRM primary minors are 0–63, render nodes 128+ — rather than open()ing it, because under seatd/logind the compositor cannot open the primary node directly. The existing drmIsKMS() check still runs once the session opens the fd.
  • Default behaviour is unchanged when neither the flag nor the env var is set.
gamescope --prefer-drm /dev/dri/by-path/pci-0000:00:02.0-card \
          --prefer-vk-device 1002:7360 -O HDMI-A-2 -- steam -gamepadui

Testing

x86 hybrid: Intel UHD 630 (display) + AMD BC-160 (headless render), on CachyOS and Bazzite Game Mode. gamescope composites on the BC-160 and scans out through the Intel iGPU — Steam Big Picture and Cyberpunk 2077 run, no atomic/addfb2/dmabuf errors. Without the flag, gamescope still selects the BC-160 primary node and fails with is not a KMS device (the bug this fixes). Invalid path / render-node input fails fast with a clear message.

Orthogonal to #2197 (runtime connector selection within one device); this selects the scanout device.

Closes #1004.

Decouple the DRM/KMS scanout device from the Vulkan render device. Until
now init_drm() always derived the KMS node from the chosen Vulkan physical
device (vulkan_primary_dev_id -> DRM_NODE_PRIMARY), so on hybrid/eGPU/muxless
setups selecting a headless render GPU via --prefer-vk-device also forced
scanout onto that GPU, which has no connectors -> black screen.

--prefer-drm lets the user pick the KMS device explicitly while
--prefer-vk-device keeps choosing the render GPU and -O selects the
connector within the chosen KMS device. Accepts /dev/dri/cardX, the short
cardX form, and /dev/dri/by-path/...-card symlinks (resolved via realpath).
The node is validated by inspecting its device number (primary minors are
0-63; render nodes 128+) rather than open()ing it, because under seatd/logind
the compositor cannot open the primary node directly. The authoritative
drmIsKMS() check still runs once the session opens the fd.

When the flag is not given, the value is also read from the GAMESCOPE_PREFER_DRM
environment variable, so a session manager can configure a split render/scanout
setup without per-game launch options. Validation runs up-front in main()
(DRMBackendCheckPreferredDevice) before Vulkan/session init, so invalid input
fails fast with a clear message.

Default behavior is unchanged when neither the flag nor the env var is set.
relil added a commit to relil/gamescope-bazzite that referenced this pull request Jun 16, 2026
Decouple the DRM/KMS scanout device from the Vulkan render device. init_drm()
derives the KMS node from the chosen Vulkan physical device
(vulkan_primary_dev_id -> DRM_NODE_PRIMARY), so on hybrid/eGPU/muxless setups
selecting a headless render GPU via --prefer-vk-device also forces scanout onto
that GPU, which has no connectors -> black screen.

--prefer-drm picks the KMS device explicitly while --prefer-vk-device keeps
choosing the render GPU and -O selects the connector within it. Accepts
/dev/dri/cardX, the short cardX form, and /dev/dri/by-path/...-card symlinks.
Also read from $GAMESCOPE_PREFER_DRM when the flag is absent, so a session can
configure a split setup without per-game options. The node is validated by
device number (primary minors 0-63) up-front in main(), not by open() (which the
compositor cannot do for a primary node under seatd/logind); drmIsKMS() still
runs later. Default behavior is unchanged when neither is set.

Also submitted upstream: ValveSoftware#2220.
relil added a commit to relil/gamescope-bazzite that referenced this pull request Jun 16, 2026
Decouple the DRM/KMS scanout device from the Vulkan render device. init_drm()
derives the KMS node from the chosen Vulkan physical device
(vulkan_primary_dev_id -> DRM_NODE_PRIMARY), so on hybrid/eGPU/muxless setups
selecting a headless render GPU via --prefer-vk-device also forces scanout onto
that GPU, which has no connectors -> black screen.

--prefer-drm picks the KMS device explicitly while --prefer-vk-device keeps
choosing the render GPU and -O selects the connector within it. Accepts
/dev/dri/cardX, the short cardX form, and /dev/dri/by-path/...-card symlinks.
Also read from $GAMESCOPE_PREFER_DRM when the flag is absent, so a session can
configure a split setup without per-game options. The node is validated by
device number (primary minors 0-63) up-front in main(), not by open() (which the
compositor cannot do for a primary node under seatd/logind); drmIsKMS() still
runs later. Default behavior is unchanged when neither is set.

Also submitted upstream: ValveSoftware#2220.
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.

Add --prefer-drm option

1 participant