Skip to content

Add rotation via composition for devices that don't support rotation at scanout#2228

Open
matte-schwartz wants to merge 2 commits into
ValveSoftware:masterfrom
matte-schwartz:matts/composite-rotation
Open

Add rotation via composition for devices that don't support rotation at scanout#2228
matte-schwartz wants to merge 2 commits into
ValveSoftware:masterfrom
matte-schwartz:matts/composite-rotation

Conversation

@matte-schwartz

Copy link
Copy Markdown

Alternative to #1655. Rather than add a separate rotation shader, this rotates the output inside the existing composite. Only the final store coordinate is rotated, so the scene graph, sampling and blending are unchanged. It engages automatically when the scanout plane can't rotate to the panel's orientation, so on i915/Xe 90/270 are rotated via composition while 180 scans out.

I don't have any ARM devices, but I would expect all rotations to composite if the driver doesn't support it at scanout. My Intel handheld with a native landscape panel composites automatically for left + right and scans out upsidedown. I'd be interested to hear if this fits the usecase as described in #819 and #1655 or if there are still any gaps.

cc @joshuatam @Drakulix @yshui @kcxt

Attempting to use --force-orientation on drivers that can't rotate planes
at scanout (i915 can't do 90/270, some ARM devices can't rotate at all)
leaves gamescope without any output when an unsupported rotation is
scanned out. To work around this, bake a rotation pass into our composite
scenegraph to allow rotation through composition rather than only at
scanout.

The scene is laid out in logical space and only the final store
coordinate is rotated into a physically-oriented output image, so
sampling, blending, input, cursor and EDID are untouched.

It engages automatically when the primary plane can't do the needed
90/180/270 rotation, or via --force-composition-rotation. Hardware that
rotates at scanout is unaffected. Screenshots and the upscale cache stay
logical-sized and unrotated.
… fixed 1200px

The overlay-vs-notification heuristic gated the focusable overlay on a
hardcoded width > 1200, so a full-screen QAM on a panel whose logical width is
<= 1200 (e.g. a 1920x1200 panel in portrait) was misclassified as a
notification and denied seat and cursor focus, breaking touch and controller
input over a game. Key off the window spanning the output (>= root_width) or
asking for input (STEAM_INPUT_FOCUS) instead. On landscape this tightens the
gate from > 1200 to >= root_width, but the interactive overlay sets
STEAM_INPUT_FOCUS so it still qualifies regardless of width.
@yshui

yshui commented Jun 24, 2026

Copy link
Copy Markdown

Can confirm this works on my Ayn Thor (SM8550)

@Drakulix

Copy link
Copy Markdown

Works great here as well on an Ayaneo Pocket S2 (SM8650).

@matte-schwartz

Copy link
Copy Markdown
Author

Awesome, glad to hear it. @misyltoad could I get your review on this when you have a chance? Should be closer to what you suggested in the other PR.

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.

3 participants