From 941301231f874a4f6bbf86193dd7cc7de4afc480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Fri, 10 Apr 2026 16:08:06 +0000 Subject: [PATCH] DRMBackend: Carry pending mode to composite path when direct scanout fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CDRMBackend::Present first attempts to do direct scanout and if that fails it falls back to full compositing. In the case that direct scanout configuration fails, in drm_prepare(), drm_rollback() is called, which overwrites drm->pending with drm->current, discarding any pending mode if there was one, which will now not be applied as part of the full composite commit. In other words, if for some reason no working direct scanout configuration can be found, no display mode changes will be applied. Fix this by saving pending.mode_id before the direct scanout drm_prepare() attempt and restoring it on failure when needs_modeset is set. This was observed on the SteamDeck OLED when displaying an application with resolution 3840x2160 to the internal display, which requires a greater scaling ratio than what the kernel commit abc0ad6d0844 ("drm/amd/display: Limit Scaling Ratio on DCN3.01") [1] allows, resulting in the atomic check failing for the direct scanout path. Under these circumstances, the application is always composited, but only when the "Force Composite" setting is enabled do changes in the panel frequency take effect, since only in that case is direct scanout not even attempted. [1] https://github.com/torvalds/linux/commit/abc0ad6d08440761b199988c329ad7ac83f41c9b Assisted-by: Claude:claude-sonnet-4.6 Signed-off-by: NĂ­colas F. R. A. Prado --- src/Backends/DRMBackend.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp index 1d34eba030..a2fa57fdf2 100644 --- a/src/Backends/DRMBackend.cpp +++ b/src/Backends/DRMBackend.cpp @@ -3511,11 +3511,16 @@ namespace gamescope bool bDoComposite = true; if ( !bNeedsFullComposite && !bWantsPartialComposite ) { + // Save the pending mode so it can be restored after drm_rollback() and carried + // over to the composite path + std::shared_ptr pPendingModeId = g_DRM.pending.mode_id; int ret = drm_prepare( &g_DRM, bAsync, pFrameInfo ); if ( ret == 0 ) bDoComposite = false; else if ( ret == -EACCES ) return 0; + else if ( g_DRM.needs_modeset ) + g_DRM.pending.mode_id = pPendingModeId; } // Update to let the vblank manager know we are currently compositing.