Skip to content

Commit

Permalink
Add custom refresh interval target
Browse files Browse the repository at this point in the history
  • Loading branch information
jcm committed Oct 8, 2023
1 parent e40470b commit 9cc36b5
Show file tree
Hide file tree
Showing 32 changed files with 734 additions and 110 deletions.
102 changes: 92 additions & 10 deletions src/Ryujinx.Ava/AppHost.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using ARMeilleure.Translation;
using ARMeilleure.Translation;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
Expand Down Expand Up @@ -58,6 +58,7 @@
using IRenderer = Ryujinx.Graphics.GAL.IRenderer;
using Key = Ryujinx.Input.Key;
using MouseButton = Ryujinx.Input.MouseButton;
using PresentIntervalState = Ryujinx.Common.Configuration.PresentIntervalState;
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
using Size = Avalonia.Size;
using Switch = Ryujinx.HLE.Switch;
Expand Down Expand Up @@ -189,6 +190,9 @@ public AppHost(
ConfigurationState.Instance.Graphics.ScalingFilter.Event += UpdateScalingFilter;
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel;
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough;
ConfigurationState.Instance.Graphics.PresentIntervalState.Event += UpdatePresentIntervalState;
ConfigurationState.Instance.Graphics.CustomPresentInterval.Event += UpdateCustomPresentIntervalValue;
ConfigurationState.Instance.Graphics.EnableCustomPresentInterval.Event += UpdateCustomPresentIntervalEnabled;

ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState;
ConfigurationState.Instance.Multiplayer.Mode.Event += UpdateMultiplayerModeState;
Expand Down Expand Up @@ -235,6 +239,37 @@ private void UpdateColorSpacePassthrough(object sender, ReactiveEventArgs<bool>
_renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
}

private void UpdatePresentIntervalState(object sender, ReactiveEventArgs<PresentIntervalState> e)
{
if (Device != null)
{
Device.PresentIntervalState = e.NewValue;
Device.UpdatePresentInterval();
}
//vulkan present mode may change in response, so recreate the swapchain
_renderer.Window?.ChangePresentIntervalState((Ryujinx.Graphics.GAL.PresentIntervalState)e.NewValue);
ConfigurationState.Instance.Graphics.PresentIntervalState.Value = e.NewValue;
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
}

private void UpdateCustomPresentIntervalValue(object sender, ReactiveEventArgs<int> e)
{
if (Device != null)
{
Device.TargetPresentInterval = e.NewValue;
Device.UpdatePresentInterval();
}
}

private void UpdateCustomPresentIntervalEnabled(object sender, ReactiveEventArgs<bool> e)
{
if (Device != null)
{
Device.CustomPresentIntervalEnabled = e.NewValue;
Device.UpdatePresentInterval();
}
}

private void ShowCursor()
{
Dispatcher.UIThread.Post(() =>
Expand Down Expand Up @@ -516,6 +551,12 @@ private void HideCursorState_Changed(object sender, ReactiveEventArgs<HideCursor
}
}

public void UpdatePresentInterval(PresentIntervalState presentIntervalState)
{
PresentIntervalState oldState = ConfigurationState.Instance.Graphics.PresentIntervalState.Value;
UpdatePresentIntervalState(this, new ReactiveEventArgs<PresentIntervalState>(oldState, presentIntervalState));
}

public async Task<bool> LoadGuestApplication()
{
InitializeSwitchInstance();
Expand Down Expand Up @@ -775,7 +816,7 @@ private void InitializeSwitchInstance()
_viewModel.UiHandler,
(SystemLanguage)ConfigurationState.Instance.System.Language.Value,
(RegionCode)ConfigurationState.Instance.System.Region.Value,
ConfigurationState.Instance.Graphics.EnableVsync,
ConfigurationState.Instance.Graphics.PresentIntervalState,
ConfigurationState.Instance.System.EnableDockedMode,
ConfigurationState.Instance.System.EnablePtc,
ConfigurationState.Instance.System.EnableInternetAccess,
Expand All @@ -789,7 +830,8 @@ private void InitializeSwitchInstance()
ConfigurationState.Instance.System.AudioVolume,
ConfigurationState.Instance.System.UseHypervisor,
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value,
ConfigurationState.Instance.Multiplayer.Mode);
ConfigurationState.Instance.Multiplayer.Mode,
ConfigurationState.Instance.Graphics.CustomPresentInterval.Value);

Device = new Switch(configuration);
}
Expand Down Expand Up @@ -915,7 +957,7 @@ private void RenderLoop()
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
Translator.IsReadyForTranslation.Set();

_renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync);
_renderer.Window.ChangePresentIntervalState((Ryujinx.Graphics.GAL.PresentIntervalState)Device.PresentIntervalState);

while (_isActive)
{
Expand Down Expand Up @@ -963,14 +1005,15 @@ public void UpdateStatus()
{
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued.
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld];
string presentIntervalState = Device.PresentIntervalState.ToString();

if (GraphicsConfig.ResScale != 1)
{
dockedMode += $" ({GraphicsConfig.ResScale}x)";
}

StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
Device.EnableDeviceVsync,
presentIntervalState,
LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan ? "Vulkan" : "OpenGL",
dockedMode,
Expand Down Expand Up @@ -1062,9 +1105,40 @@ private bool UpdateFrame()
{
switch (currentHotkeyState)
{
case KeyboardHotkeyState.ToggleVSync:
Device.EnableDeviceVsync = !Device.EnableDeviceVsync;

//todo default
case KeyboardHotkeyState.TogglePresentIntervalState:
PresentIntervalState oldState = Device.PresentIntervalState;
PresentIntervalState newState;
if (oldState == PresentIntervalState.Switch)
{
newState = PresentIntervalState.Unbounded;
}
else if (oldState == PresentIntervalState.Unbounded)
{
if (ConfigurationState.Instance.Graphics.EnableCustomPresentInterval)
{
newState = PresentIntervalState.Custom;
}
else
{
newState = PresentIntervalState.Switch;
}
}
else
{
newState = PresentIntervalState.Switch;
}
UpdatePresentIntervalState(this, new ReactiveEventArgs<PresentIntervalState>(oldState, newState));
_viewModel.ShowCustomPresentIntervalPicker =
(newState == PresentIntervalState.Custom);
break;
case KeyboardHotkeyState.CustomPresentIntervalDecrement:
Device.DecrementCustomPresentInterval();
_viewModel.CustomPresentInterval -= 1;
break;
case KeyboardHotkeyState.CustomPresentIntervalIncrement:
Device.IncrementCustomPresentInterval();
_viewModel.CustomPresentInterval += 1;
break;
case KeyboardHotkeyState.Screenshot:
ScreenshotRequested = true;
Expand Down Expand Up @@ -1150,9 +1224,9 @@ private KeyboardHotkeyState GetHotkeyState()
{
KeyboardHotkeyState state = KeyboardHotkeyState.None;

if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleVsync))
if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.PresentIntervalState))
{
state = KeyboardHotkeyState.ToggleVSync;
state = KeyboardHotkeyState.TogglePresentIntervalState;
}
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot))
{
Expand Down Expand Up @@ -1186,6 +1260,14 @@ private KeyboardHotkeyState GetHotkeyState()
{
state = KeyboardHotkeyState.VolumeDown;
}
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CustomPresentIntervalIncrement))
{
state = KeyboardHotkeyState.CustomPresentIntervalIncrement;
}
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CustomPresentIntervalDecrement))
{
state = KeyboardHotkeyState.CustomPresentIntervalDecrement;
}

return state;
}
Expand Down
18 changes: 15 additions & 3 deletions src/Ryujinx.Ava/Assets/Locales/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,26 @@
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Latin American Spanish",
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Simplified Chinese",
"SettingsTabSystemSystemLanguageTraditionalChinese": "Traditional Chinese",
"SettingsTabSystemSystemTimeZone": "System TimeZone:",
"SettingsTabSystemSystemTimeZone": "System Time Zone:",
"SettingsTabSystemSystemTime": "System Time:",
"SettingsTabSystemEnableVsync": "VSync",
"SettingsTabSystemPresentIntervalState": "Present Interval Mode (VSync):",
"SettingsTabSystemEnableCustomPresentInterval": "Enable toggle for custom present interval",
"SettingsTabSystemPresentIntervalStateSwitch": "60 (VSync ON)",
"SettingsTabSystemPresentIntervalStateUnbounded": "Unbounded (VSync OFF)",
"SettingsTabSystemPresentIntervalStateCustom": "Custom",
"SettingsTabSystemPresentIntervalStateTooltip": "Previously VSync. Use the Custom mode to set a specific refresh interval target. In some titles, the custom mode will act as an FPS cap. In others, it may lead to unpredictable behavior or do nothing at all. \n\nLeave at 60 (VSync ON) if unsure.",
"SettingsTabSystemEnableCustomPresentIntervalTooltip": "The present interval mode toggle will also cycle through the custom interval mode.",
"SettingsTabSystemCustomPresentIntervalValueTooltip": "The custom present interval target value.",
"SettingsTabSystemCustomPresentIntervalSliderTooltip": "The custom present interval target, as a percentage of the normal Switch interval.",
"SettingsTabSystemCustomPresentIntervalValue": "Custom Present Interval Value:",
"SettingsTabSystemEnablePptc": "PPTC (Profiled Persistent Translation Cache)",
"SettingsTabSystemEnableFsIntegrityChecks": "FS Integrity Checks",
"SettingsTabSystemAudioBackend": "Audio Backend:",
"SettingsTabSystemAudioBackendDummy": "Dummy",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemCustomPresentInterval": "Interval",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": "May cause instability",
"SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)",
Expand Down Expand Up @@ -571,11 +581,13 @@
"RyujinxUpdater": "Ryujinx Updater",
"SettingsTabHotkeys": "Keyboard Hotkeys",
"SettingsTabHotkeysHotkeys": "Keyboard Hotkeys",
"SettingsTabHotkeysToggleVsyncHotkey": "Toggle VSync:",
"SettingsTabHotkeysTogglePresentIntervalStateHotkey": "Toggle Present Interval state:",
"SettingsTabHotkeysScreenshotHotkey": "Screenshot:",
"SettingsTabHotkeysShowUiHotkey": "Show UI:",
"SettingsTabHotkeysPauseHotkey": "Pause:",
"SettingsTabHotkeysToggleMuteHotkey": "Mute:",
"SettingsTabHotkeysIncrementCustomPresentIntervalHotkey": "Raise custom refresh interval",
"SettingsTabHotkeysDecrementCustomPresentIntervalHotkey": "Lower custom refresh interval",
"ControllerMotionTitle": "Motion Control Settings",
"ControllerRumbleTitle": "Rumble Settings",
"SettingsSelectThemeFileDialogTitle": "Select Theme File",
Expand Down
5 changes: 3 additions & 2 deletions src/Ryujinx.Ava/Assets/Styles/Themes.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
<Color x:Key="SecondaryTextColor">#A0000000</Color>
<Color x:Key="VsyncEnabled">#FF2EEAC9</Color>
<Color x:Key="VsyncDisabled">#FFFF4554</Color>
<Color x:Key="Switch">#FF2EEAC9</Color>
<Color x:Key="Unbounded">#FFFF4554</Color>
<Color x:Key="Custom">#6483F5</Color>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
Expand Down
4 changes: 3 additions & 1 deletion src/Ryujinx.Ava/Common/KeyboardHotkeyState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
public enum KeyboardHotkeyState
{
None,
ToggleVSync,
TogglePresentIntervalState,
Screenshot,
ShowUi,
Pause,
Expand All @@ -12,5 +12,7 @@ public enum KeyboardHotkeyState
ResScaleDown,
VolumeUp,
VolumeDown,
CustomPresentIntervalIncrement,
CustomPresentIntervalDecrement,
}
}
6 changes: 3 additions & 3 deletions src/Ryujinx.Ava/UI/Models/StatusUpdatedEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Ryujinx.Ava.UI.Models
{
internal class StatusUpdatedEventArgs : EventArgs
{
public bool VSyncEnabled { get; }
public string PresentIntervalState { get; }
public string VolumeStatus { get; }
public string GpuBackend { get; }
public string AspectRatio { get; }
Expand All @@ -13,9 +13,9 @@ internal class StatusUpdatedEventArgs : EventArgs
public string GameStatus { get; }
public string GpuName { get; }

public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string gpuBackend, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, string gpuName)
public StatusUpdatedEventArgs(string presentIntervalState, string volumeStatus, string gpuBackend, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, string gpuName)
{
VSyncEnabled = vSyncEnabled;
PresentIntervalState = presentIntervalState;
VolumeStatus = volumeStatus;
GpuBackend = gpuBackend;
DockedMode = dockedMode;
Expand Down
Loading

0 comments on commit 9cc36b5

Please sign in to comment.