Support streaming a disconnected display after booting headless - #2372
Merged
matte-schwartz merged 5 commits intoSep 23, 2026
Merged
Conversation
3 of 6 tasks
init_drm aborts with "Failed to find a primary plane" when nothing is connected at boot, because find_primary_plane needs a CRTC and a CRTC needs a connected connector. Fall back to any primary plane so format selection has something to work from. Without a CRTC have_overlay_planes is false, so the overlay-less format switch also learns the alpha variants the picker can return.
GetNextVBlank walks forward from the last marked vblank one interval at a time. Nothing marks a vblank while no display is connected, so every wakeup replays the whole uptime, roughly 60 iterations per second of uptime per call. A headless streaming box eventually burns a core on it. Compute the number of missed intervals directly.
drm_unset_mode falls back to 1280x720 whenever no display is connected, so Steam sees a 720p virtual screen after a TV is turned off or on a cold headless boot. Keep the current mode when a connected display goes away. On a cold start, identify the last driven display from the persisted patched EDID and use its saved mode, else its EDID preferred mode. An explicit -W/-H or -r still wins for the part it sets.
Nothing records which modes the last connected display offered, so a later headless session has no mode list to work from. Store one WxH@R line per mode next to the patched EDID file. Only the DRM backend writes it, so a nested session cannot clobber it.
Headless is a null current connector, so consumers each need their own null path for the mode list, identity, saved mode picks and the EDID games read, and none of that state has a home. Serve a headless connector while no real one is connected, keeping the backend's own paths on the real connector so nothing writes the persisted EDID for a screen that does not exist. It owns the headless mode list, identity and saved mode key, offering the modes the last display really had, and games read a copy of that display's EDID stamped with Gamescope's identity. It reads as an external SDR screen, so color management targets sRGB and the vblank red zone, external touch handling and the app refresh cycle take the external paths.
matte-schwartz
force-pushed
the
headless-display-fix
branch
from
September 23, 2026 20:06
4125632 to
9d52c52
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Gamescope currently fails to start on a Steam Machine that boots with no display connected, aborting in init_drm because finding a primary plane requires a CRTC and a CRTC requires a connected connector. That leaves the session in a login loop until something is plugged in.
This makes the DRM backend serve a stand-in connector while nothing is connected, so a headless machine comes up and can be streamed through Remote Play. The virtual screen keeps the resolution of the display that was last driven rather than falling back to 720p, and it offers that display's real mode list, so if you were on an ultrawide you can stay at 5120x2160 or drop to 1920x1080 from Steam's display settings even though the machine booted with the monitor disconnected or off. The mode list and the last display's identity come from a small sidecar file written next to the patched EDID whenever a real display is driven.
Deliberately not included are synthetic streaming resolutions beyond what the display really offered, and inheriting the last display's HDR support. Both need the Steam client side worked out first. I could see how a virtual-connector-based approach would fit a per-app streaming model better, but it pulls in focus and composite changes across steamcompmgr plus Steam-side work, so this tries to match how Remote Play streams a whole session today.