From a08051ac4ccd97100e5f2c546cbc0ed01c97c3e3 Mon Sep 17 00:00:00 2001 From: The Roofer Dev Date: Tue, 16 Jun 2026 17:43:15 -0400 Subject: [PATCH] UI: add a VRR VSync mode using the FifoRelaxed present mode Add a new VSyncMode.Vrr that selects the FifoRelaxed Vulkan present mode, letting the display's variable refresh rate (G-Sync/FreeSync) drive the refresh in fullscreen and smoothing a fluctuating frame rate without tearing. Reachable by cycling the status-bar VSync button; shown in green. Co-Authored-By: Claude Opus 4.8 --- src/Ryujinx.Common/Configuration/VSyncMode.cs | 6 ++++-- src/Ryujinx.Graphics.Vulkan/Window.cs | 9 ++++++++- src/Ryujinx/Assets/Styles/Themes.xaml | 3 +++ src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs | 7 ++++++- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Ryujinx.Common/Configuration/VSyncMode.cs b/src/Ryujinx.Common/Configuration/VSyncMode.cs index 21505bf2a..b2818eb7a 100644 --- a/src/Ryujinx.Common/Configuration/VSyncMode.cs +++ b/src/Ryujinx.Common/Configuration/VSyncMode.cs @@ -4,7 +4,8 @@ namespace Ryujinx.Common.Configuration { Switch, Unbounded, - Custom + Custom, + Vrr } public static class VSyncModeExtensions @@ -13,8 +14,9 @@ namespace Ryujinx.Common.Configuration vsync switch { VSyncMode.Switch => customEnabled ? VSyncMode.Custom : VSyncMode.Unbounded, - VSyncMode.Unbounded => VSyncMode.Switch, VSyncMode.Custom => VSyncMode.Unbounded, + VSyncMode.Unbounded => VSyncMode.Vrr, + VSyncMode.Vrr => VSyncMode.Switch, _ => VSyncMode.Switch }; } diff --git a/src/Ryujinx.Graphics.Vulkan/Window.cs b/src/Ryujinx.Graphics.Vulkan/Window.cs index eb8d433be..8b2a53fc0 100644 --- a/src/Ryujinx.Graphics.Vulkan/Window.cs +++ b/src/Ryujinx.Graphics.Vulkan/Window.cs @@ -282,7 +282,14 @@ namespace Ryujinx.Graphics.Vulkan private static PresentModeKHR ChooseSwapPresentMode(PresentModeKHR[] availablePresentModes, VSyncMode vSyncMode) { - if (vSyncMode == VSyncMode.Unbounded && availablePresentModes.Contains(PresentModeKHR.ImmediateKhr)) + // VRR: FifoRelaxed lets the display's variable refresh rate (G-Sync/FreeSync) drive the refresh + // in fullscreen, smoothing a fluctuating frame rate without tearing. Immediate (full VSync off) + // was tried first but could hang the GPU under load, so FifoRelaxed is used instead. + if (vSyncMode == VSyncMode.Vrr && availablePresentModes.Contains(PresentModeKHR.FifoRelaxedKhr)) + { + return PresentModeKHR.FifoRelaxedKhr; + } + else if (vSyncMode == VSyncMode.Unbounded && availablePresentModes.Contains(PresentModeKHR.ImmediateKhr)) { return PresentModeKHR.ImmediateKhr; } diff --git a/src/Ryujinx/Assets/Styles/Themes.xaml b/src/Ryujinx/Assets/Styles/Themes.xaml index 53c4dcd59..d073786bd 100644 --- a/src/Ryujinx/Assets/Styles/Themes.xaml +++ b/src/Ryujinx/Assets/Styles/Themes.xaml @@ -18,6 +18,7 @@ #FF2EEAC9 #FFFF4554 #6483F5 + #FF4CD964 #800080 #00B5B8 @@ -38,6 +39,7 @@ #13c3a4 #FFFF4554 #6483F5 + #FF4CD964 #800080 #00B5B8 @@ -58,6 +60,7 @@ #FF2EEAC9 #FFFF4554 #6483F5 + #FF4CD964 #FFA500 #00B5B8 diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index 51c05a692..c778ec71c 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -1369,7 +1369,12 @@ namespace Ryujinx.Ava.UI.ViewModels VSyncModeColor = new SolidColorBrush(clr); } - VSyncModeText = args.VSyncMode == "Custom" ? "Custom" : "VSync"; + VSyncModeText = args.VSyncMode switch + { + "Custom" => "Custom", + "Vrr" => "VRR", + _ => "VSync" + }; DockedStatusText = args.DockedMode; AspectRatioStatusText = args.AspectRatio; GameStatusText = args.GameStatus;