Runtime display selection in DRM backend#2197
Open
matte-schwartz wants to merge 3 commits into
Open
Conversation
Collaborator
Author
|
I'm about to leave on vacation for a few days, but my goal is to finish up testing and undraft this sometime next week. |
This was referenced Jun 16, 2026
…election
The output was previously only selectable with --prefer-output at
startup, which gamescope-session can't adjust. Add
available_display_info / available_display_info_done events to
enumerate the connected outputs, set_display / unset_display requests
to pick one by connector name or fall back to --prefer-output, and a
matching set_display console command that also accepts a
make/model/serial substring. A "current" display flag marks the output
being driven.
The connector name is authoritative for the switch, but connectors can
be renumbered on replug, across reboots, or on MST topology changes, so
the selection is persisted as an EDID-derived identifier, "{make}
{model} {serial}", and resolved identifier-first among the connected
outputs. The serial prefers the per-unit descriptor string, since the
numeric serial field is commonly a per-model constant. Physically
identical, serial-less monitors that collide get a " [connector]"
suffix, with the hinted connector as tiebreak. The persisted key is
reloaded at startup from GAMESCOPE_DISPLAY_SELECTION_FILE, and writing
the file is owned by the session/Steam side. display_selection.h is a
standalone header so the resolution logic is unit-testable.
Connected outputs are mirrored into a snapshot rebuilt on the
steamcompmgr thread. It is the only connector state other threads read,
so protocol requests don't stall behind EDID probes or share a lock
with refresh_state, whose EDID parsing can run user Lua that itself
calls set_display. Display info is re-broadcast only when a poll
reconfigured the output or changed the snapshot, and re-setting the
current preference is a no-op. A selection sent before a deferred
backend has initialized its child is queued and replayed at init.
Physically identical, serial-less monitors collide on the same EDID
identifier, so the selection key falls back to a " [connector]" suffix to
tell them apart. However, the connector name keys on connector_type_id,
which the kernel reassigns when the MST sink connectors are torn down and
recreated on reprobe, so the selection jumps around unexpectedly.
Instead, read the DRM MST PATH blob ("mst:<conn>-<port>") and use it as
the tiebreak hint when present. The port numbers are topology-derived
(which port of the dock the sink hangs off), and the "mst:" prefix is the
upstream connector id, which is fixed at output setup and not re-init'd on
a downstream reprobe. So the PATH survives the connector renumber that
connector_type_id does not. Non-MST and single-stream connections have no
PATH and fall back to the connector name as before.
GAMESCOPE_DISPLAY_PREFERRED_IDENTIFIER sets the preferred display by its EDID identifier, GAMESCOPE_DISPLAY_AVAILABLE_LIST mirrors the connected outputs. The handler only honors the root window's property - any other client interning the same atom on its own window would otherwise clear the preference with the unset root value - and both sides skip no-op rewrites to avoid notify/reprobe churn.
matte-schwartz
force-pushed
the
display-selection-control-with-tests
branch
from
July 13, 2026 00:10
d85e510 to
42028df
Compare
matte-schwartz
marked this pull request as ready for review
July 13, 2026 00:11
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.
The goal for this PR is to provide runtime controls to select a preferred display in the DRM backend without relying on the commandline argument -O. The exact details are explained in the commits, but generally this is what's expected:
you can also run
gamescopectl set_display <connector name>rather than substrings of the monitor identifiers. the choice from Steam is meant to be written to~/.config/gamescope/display.cfg, similar tomodes.cfg, but[HACK] DRMBackend: Temporarily write preferred-display file on set_displaymoves this write into gamescope for testing purposes:there is an xatom path for this as well:
tests are included so it was easier to check the code around some of the weird edge cases. this is also why display_selection.h is its own header file, to pull into the testing framework.
marked as draft for now so additional testing can be done, but before bringing it out of draft I will drop hack commit.