From 90f2b089ebb2da133d27b612e21ae2f5fb4115d5 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sun, 2 Mar 2025 23:51:56 -0600 Subject: [PATCH 1/7] fix nullref when switching vsync mode with turbo mode --- src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index f50ec852e..4620821cb 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -1065,7 +1065,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// private void UpdateIndexBufferState() { - IndexBufferState indexBuffer = _state.State.IndexBufferState; + IndexBufferState? indexBufferNullable = _state?.State.IndexBufferState; + + if (!indexBufferNullable.HasValue) + { + return; + } + + IndexBufferState indexBuffer = indexBufferNullable.Value; if (_drawState.IndexCount == 0) { -- 2.47.1 From c48a2e6ba089d21c15dbfc4b61638834ea18b513 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Mon, 3 Mar 2025 02:30:26 -0600 Subject: [PATCH 2/7] join assignment and declaration for this local variable in ipc service --- src/Ryujinx.HLE/HOS/Services/IpcService.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Ryujinx.HLE/HOS/Services/IpcService.cs b/src/Ryujinx.HLE/HOS/Services/IpcService.cs index 1b95b6712..f1ac7c5ac 100644 --- a/src/Ryujinx.HLE/HOS/Services/IpcService.cs +++ b/src/Ryujinx.HLE/HOS/Services/IpcService.cs @@ -127,10 +127,7 @@ namespace Ryujinx.HLE.HOS.Services } else { - string serviceName; - - - serviceName = (service is not DummyService dummyService) ? service.GetType().FullName : dummyService.ServiceName; + string serviceName = (service is not DummyService dummyService) ? service.GetType().FullName : dummyService.ServiceName; Logger.Warning?.Print(LogClass.KernelIpc, $"Missing service {serviceName}: {commandId} ignored"); } -- 2.47.1 From ed5cb82aa8bbca5a1f2cfe947ef23253c53dfa90 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Mon, 3 Mar 2025 02:33:28 -0600 Subject: [PATCH 3/7] feature: Turbo Mode Adds an elapsed tick multiplier feature which speeds up games which are built upon delta time. More information: https://web.archive.org/web/20240713135029/https://github.com/Ryujinx/Ryujinx/pull/6456 --- .../Configuration/Hid/KeyboardHotkeys.cs | 2 + src/Ryujinx.Cpu/ITickSource.cs | 5 + src/Ryujinx.Cpu/TickSource.cs | 29 +++- src/Ryujinx.HLE/HLEConfiguration.cs | 7 + .../Services/SurfaceFlinger/SurfaceFlinger.cs | 3 +- src/Ryujinx.HLE/PerformanceStatistics.cs | 11 +- src/Ryujinx.HLE/Switch.cs | 21 ++- src/Ryujinx/AppHost.cs | 19 ++- src/Ryujinx/Assets/locales.json | 150 ++++++++++++++++++ src/Ryujinx/Common/KeyboardHotkeyState.cs | 1 + src/Ryujinx/Headless/HeadlessRyujinx.Init.cs | 3 +- src/Ryujinx/UI/Models/Input/HotkeyConfig.cs | 8 + .../UI/ViewModels/SettingsViewModel.cs | 22 +++ .../UI/Views/Settings/SettingsCPUView.axaml | 51 ++++++ .../Views/Settings/SettingsHotkeysView.axaml | 32 ++-- .../Settings/SettingsHotkeysView.axaml.cs | 3 + .../Configuration/ConfigurationFileFormat.cs | 7 +- .../ConfigurationState.Migration.cs | 23 ++- .../Configuration/ConfigurationState.Model.cs | 14 ++ .../Configuration/ConfigurationState.cs | 9 +- 20 files changed, 394 insertions(+), 26 deletions(-) diff --git a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs index 6b8152b9d..efdb422e7 100644 --- a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs +++ b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs @@ -13,5 +13,7 @@ namespace Ryujinx.Common.Configuration.Hid public Key VolumeDown { get; set; } public Key CustomVSyncIntervalIncrement { get; set; } public Key CustomVSyncIntervalDecrement { get; set; } + public Key TurboMode { get; set; } + public bool TurboModeWhileHeld { get; set; } } } diff --git a/src/Ryujinx.Cpu/ITickSource.cs b/src/Ryujinx.Cpu/ITickSource.cs index e65e99e26..c352df85a 100644 --- a/src/Ryujinx.Cpu/ITickSource.cs +++ b/src/Ryujinx.Cpu/ITickSource.cs @@ -12,6 +12,11 @@ namespace Ryujinx.Cpu /// Time elapsed since the counter was created. /// TimeSpan ElapsedTime { get; } + + /// + /// Clock tick scalar, in percent points (100 = 1.0). + /// + long TickScalar { get; set; } /// /// Time elapsed since the counter was created, in seconds. diff --git a/src/Ryujinx.Cpu/TickSource.cs b/src/Ryujinx.Cpu/TickSource.cs index eee83fc62..3bc01d6b9 100644 --- a/src/Ryujinx.Cpu/TickSource.cs +++ b/src/Ryujinx.Cpu/TickSource.cs @@ -14,12 +14,37 @@ namespace Ryujinx.Cpu /// public ulong Counter => (ulong)(ElapsedSeconds * Frequency); + + + public long TickScalar { get; set; } + + + private static long _acumElapsedTicks; + + + private static long _lastElapsedTicks; + + + private long ElapsedTicks + { + get + { + long elapsedTicks = _tickCounter.ElapsedTicks; + + _acumElapsedTicks += (elapsedTicks - _lastElapsedTicks) * TickScalar / 100; + + _lastElapsedTicks = elapsedTicks; + + return _acumElapsedTicks; + } + } /// - public TimeSpan ElapsedTime => _tickCounter.Elapsed; + + public TimeSpan ElapsedTime => Stopwatch.GetElapsedTime(0, ElapsedTicks); /// - public double ElapsedSeconds => _tickCounter.ElapsedTicks * _hostTickFreq; + public double ElapsedSeconds => ElapsedTicks * _hostTickFreq; public TickSource(ulong frequency) { diff --git a/src/Ryujinx.HLE/HLEConfiguration.cs b/src/Ryujinx.HLE/HLEConfiguration.cs index 0b7ae3974..e2132bb5a 100644 --- a/src/Ryujinx.HLE/HLEConfiguration.cs +++ b/src/Ryujinx.HLE/HLEConfiguration.cs @@ -102,6 +102,11 @@ namespace Ryujinx.HLE /// Control if the Profiled Translation Cache (PTC) should be used. /// internal readonly bool EnablePtc; + + /// + /// Control the arbitrary scalar applied to emulated CPU tick timing. + /// + public long TickScalar { get; set; } /// /// Control if the guest application should be told that there is a Internet connection available. @@ -225,6 +230,7 @@ namespace Ryujinx.HLE string multiplayerLdnPassphrase, string multiplayerLdnServer, int customVSyncInterval, + long tickScalar, EnabledDirtyHack[] dirtyHacks = null) { VirtualFileSystem = virtualFileSystem; @@ -257,6 +263,7 @@ namespace Ryujinx.HLE MultiplayerDisableP2p = multiplayerDisableP2p; MultiplayerLdnPassphrase = multiplayerLdnPassphrase; MultiplayerLdnServer = multiplayerLdnServer; + TickScalar = tickScalar; Hacks = dirtyHacks ?? []; } } diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs index 935e9895e..294192363 100644 --- a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs +++ b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs @@ -2,6 +2,7 @@ using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.PreciseSleep; +using Ryujinx.Cpu; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; @@ -89,7 +90,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger } else { - _ticksPerFrame = Stopwatch.Frequency / _device.TargetVSyncInterval; + _ticksPerFrame = ((Stopwatch.Frequency / _device.TargetVSyncInterval) * 100) / _device.TickScalar; _targetVSyncInterval = _device.TargetVSyncInterval; } } diff --git a/src/Ryujinx.HLE/PerformanceStatistics.cs b/src/Ryujinx.HLE/PerformanceStatistics.cs index e80faa7d2..48f4a0575 100644 --- a/src/Ryujinx.HLE/PerformanceStatistics.cs +++ b/src/Ryujinx.HLE/PerformanceStatistics.cs @@ -6,6 +6,8 @@ namespace Ryujinx.HLE { public class PerformanceStatistics { + private readonly Switch _device; + private const int FrameTypeGame = 0; private const int PercentTypeFifo = 0; @@ -28,8 +30,10 @@ namespace Ryujinx.HLE private readonly System.Timers.Timer _resetTimer; - public PerformanceStatistics() + public PerformanceStatistics(Switch device) { + _device = device; + _frameRate = new double[1]; _accumulatedFrameTime = new double[1]; _previousFrameTime = new double[1]; @@ -166,8 +170,11 @@ namespace Ryujinx.HLE { double frameRate = GetGameFrameRate(); double frameTime = GetGameFrameTime(); + string turboSuffix = _device.TurboMode + ? $" Turbo ({_device.TickScalar}%)" + : string.Empty; - return $"{frameRate:00.00} FPS ({frameTime:00.00}ms)"; + return $"{frameRate:00.00} FPS ({frameTime:00.00}ms){turboSuffix}"; } public string FormatFifoPercent() diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index 86b04061e..dfa81b342 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -26,18 +26,26 @@ namespace Ryujinx.HLE public GpuContext Gpu { get; } public VirtualFileSystem FileSystem { get; } public HOS.Horizon System { get; } + + public bool TurboMode = false; + + public long TickScalar + { + get => System?.TickSource?.TickScalar ?? 100; + set => System.TickSource.TickScalar = value; + } + public ProcessLoader Processes { get; } public PerformanceStatistics Statistics { get; } public Hid Hid { get; } public TamperMachine TamperMachine { get; } public IHostUIHandler UIHandler { get; } - public int CpuCoresCount = 4; //Switch 1 has 4 cores + public int CpuCoresCount = 4; // Switch has a quad-core Tegra X1 SoC public VSyncMode VSyncMode { get; set; } public bool CustomVSyncIntervalEnabled { get; set; } public int CustomVSyncInterval { get; set; } - public long TargetVSyncInterval { get; set; } = 60; public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable; @@ -64,7 +72,7 @@ namespace Ryujinx.HLE Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), memoryAllocationFlags); Gpu = new GpuContext(Configuration.GpuRenderer, DirtyHacks); System = new HOS.Horizon(this); - Statistics = new PerformanceStatistics(); + Statistics = new PerformanceStatistics(this); Hid = new Hid(this, System.HidStorage); Processes = new ProcessLoader(this); TamperMachine = new TamperMachine(); @@ -75,6 +83,7 @@ namespace Ryujinx.HLE VSyncMode = Configuration.VSyncMode; CustomVSyncInterval = Configuration.CustomVSyncInterval; + TickScalar = TurboMode ? Configuration.TickScalar : 100; System.State.DockedMode = Configuration.EnableDockedMode; System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default; System.EnablePtc = Configuration.EnablePtc; @@ -122,6 +131,12 @@ namespace Ryujinx.HLE } } + public void ToggleTurbo() + { + TurboMode = !TurboMode; + TickScalar = TurboMode ? Configuration.TickScalar : 100; + } + public bool LoadCart(string exeFsDir, string romFsFile = null) => Processes.LoadUnpackedNca(exeFsDir, romFsFile); public bool LoadXci(string xciFile, ulong applicationId = 0) => Processes.LoadXci(xciFile, applicationId); public bool LoadNca(string ncaFile, BlitStruct? customNacpData = null) => Processes.LoadNca(ncaFile, customNacpData); diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index b741eb977..36716a0cb 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -947,7 +947,8 @@ namespace Ryujinx.Ava ConfigurationState.Instance.Multiplayer.DisableP2p, ConfigurationState.Instance.Multiplayer.LdnPassphrase, ConfigurationState.Instance.Multiplayer.GetLdnServer(), - ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value, + ConfigurationState.Instance.Graphics.CustomVSyncInterval, + ConfigurationState.Instance.System.TickScalar, ConfigurationState.Instance.Hacks.ShowDirtyHacks ? ConfigurationState.Instance.Hacks.EnabledHacks : null)); } @@ -1249,6 +1250,12 @@ namespace Ryujinx.Ava if (currentHotkeyState != _prevHotkeyState) { + if (ConfigurationState.Instance.Hid.Hotkeys.Value.TurboModeWhileHeld && + _keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.TurboMode) != Device.TurboMode) + { + Device.ToggleTurbo(); + } + switch (currentHotkeyState) { case KeyboardHotkeyState.ToggleVSyncMode: @@ -1262,6 +1269,12 @@ namespace Ryujinx.Ava Device.IncrementCustomVSyncInterval(); _viewModel.CustomVSyncInterval += 1; break; + case KeyboardHotkeyState.TurboMode: + if (!ConfigurationState.Instance.Hid.Hotkeys.Value.TurboModeWhileHeld) + { + Device.ToggleTurbo(); + } + break; case KeyboardHotkeyState.Screenshot: ScreenshotRequested = true; break; @@ -1391,6 +1404,10 @@ namespace Ryujinx.Ava { state = KeyboardHotkeyState.CustomVSyncIntervalDecrement; } + else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.TurboMode)) + { + state = KeyboardHotkeyState.TurboMode; + } return state; } diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index d69c3ee9b..659f03f41 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -4897,6 +4897,81 @@ "zh_TW": "低功耗 PPTC" } }, + { + "ID": "SettingsTabSystemTurboMultiplierValue", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Turbo multiplier:", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "SettingsTabSystemTurboMultiplierSliderToolTip", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "The Turbo mode multiplier target value.\n\nLeave at 100 if unsure.", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "SettingsTabSystemTurboMultiplierValueToolTip", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "The Turbo mode multiplier, as a percentage of the normal Switch clock speed.\n\nLeave at 100 if unsure.", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "SettingsTabSystemEnableFsIntegrityChecks", "Translations": { @@ -5097,6 +5172,31 @@ "zh_TW": "可能導致模擬器不穩定" } }, + { + "ID": "SettingsTabCpuHacksNote", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Can and will cause crashing, slow/too fast games, etc. Use with caution.", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "SettingsTabSystemDramSize", "Translations": { @@ -23797,6 +23897,56 @@ "zh_TW": "降低自訂的重新整理頻率" } }, + { + "ID": "SettingsTabHotkeysTurboMode", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Turbo mode:", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "SettingsTabHotkeysOnlyWhilePressed", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Only while pressed", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "CompatibilityListLastUpdated", "Translations": { diff --git a/src/Ryujinx/Common/KeyboardHotkeyState.cs b/src/Ryujinx/Common/KeyboardHotkeyState.cs index 060c678d2..b6fb02f04 100644 --- a/src/Ryujinx/Common/KeyboardHotkeyState.cs +++ b/src/Ryujinx/Common/KeyboardHotkeyState.cs @@ -14,5 +14,6 @@ namespace Ryujinx.Ava.Common VolumeDown, CustomVSyncIntervalIncrement, CustomVSyncIntervalDecrement, + TurboMode, } } diff --git a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs index 3ebfee751..b676b104e 100644 --- a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs +++ b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs @@ -352,7 +352,8 @@ namespace Ryujinx.Headless false, string.Empty, string.Empty, - options.CustomVSyncInterval); + options.CustomVSyncInterval, + 100); return new Switch(configuration); } diff --git a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs index 40f53c673..9e557d7b1 100644 --- a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs +++ b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs @@ -28,6 +28,10 @@ namespace Ryujinx.Ava.UI.Models.Input [ObservableProperty] private Key _customVSyncIntervalDecrement; + [ObservableProperty] private Key _turboMode; + + [ObservableProperty] private bool _turboModeWhileHeld; + public HotkeyConfig(KeyboardHotkeys config) { if (config == null) @@ -44,6 +48,8 @@ namespace Ryujinx.Ava.UI.Models.Input VolumeDown = config.VolumeDown; CustomVSyncIntervalIncrement = config.CustomVSyncIntervalIncrement; CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement; + TurboMode = config.TurboMode; + TurboModeWhileHeld = config.TurboModeWhileHeld; } public KeyboardHotkeys GetConfig() => @@ -60,6 +66,8 @@ namespace Ryujinx.Ava.UI.Models.Input VolumeDown = VolumeDown, CustomVSyncIntervalIncrement = CustomVSyncIntervalIncrement, CustomVSyncIntervalDecrement = CustomVSyncIntervalDecrement, + TurboMode = TurboMode, + TurboModeWhileHeld = TurboModeWhileHeld }; } } diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index d0a6c6d8a..e1ab57709 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -60,6 +60,7 @@ namespace Ryujinx.Ava.UI.ViewModels private bool _enableCustomVSyncInterval; private int _customVSyncIntervalPercentageProxy; private VSyncMode _vSyncMode; + private long _turboModeMultiplier; public event Action CloseWindow; public event Action SaveSettingsEvent; @@ -207,6 +208,25 @@ namespace Ryujinx.Ava.UI.ViewModels } public bool EnablePptc { get; set; } public bool EnableLowPowerPptc { get; set; } + + + public long TurboMultiplier + { + get => _turboModeMultiplier; + set + { + if (_turboModeMultiplier != value) + { + _turboModeMultiplier = value; + + OnPropertyChanged(); + OnPropertyChanged((nameof(TurboMultiplierPercentageText))); + } + } + } + + public string TurboMultiplierPercentageText => $"{TurboMultiplier}%"; + public bool EnableInternetAccess { get; set; } public bool EnableFsIntegrityChecks { get; set; } public bool IgnoreMissingServices { get; set; } @@ -594,6 +614,7 @@ namespace Ryujinx.Ava.UI.ViewModels EnableLowPowerPptc = config.System.EnableLowPowerPtc; MemoryMode = (int)config.System.MemoryManagerMode.Value; UseHypervisor = config.System.UseHypervisor; + TurboMultiplier = config.System.TickScalar; // Graphics GraphicsBackendIndex = (int)config.Graphics.GraphicsBackend.Value; @@ -697,6 +718,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.System.EnableLowPowerPtc.Value = EnableLowPowerPptc; config.System.MemoryManagerMode.Value = (MemoryManagerMode)MemoryMode; config.System.UseHypervisor.Value = UseHypervisor; + config.System.TickScalar.Value = TurboMultiplier; // Graphics config.Graphics.VSyncMode.Value = VSyncMode; diff --git a/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml index 62f087510..976309995 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml @@ -7,6 +7,7 @@ xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:helper="clr-namespace:Ryujinx.Common.Helper;assembly=Ryujinx.Common" + xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" mc:Ignorable="d" x:DataType="viewModels:SettingsViewModel"> @@ -76,6 +77,56 @@ ToolTip.Tip="{ext:Locale UseHypervisorTooltip}" /> + + + + + + + + + + + + + diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml index 87b6dda7d..40121c2e1 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml @@ -19,7 +19,7 @@ - @@ -47,71 +47,79 @@ Classes="h1" Text="{ext:Locale SettingsTabHotkeysHotkeys}" /> - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs index d3d1537e0..17b413b5c 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs +++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs @@ -116,6 +116,9 @@ namespace Ryujinx.Ava.UI.Views.Settings case "CustomVSyncIntervalDecrement": viewModel.KeyboardHotkey.CustomVSyncIntervalDecrement = buttonValue.AsHidType(); break; + case "TurboMode": + viewModel.KeyboardHotkey.TurboMode = buttonValue.AsHidType(); + break; } } }; diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs index 814a48e53..5d70ff5e1 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs @@ -15,7 +15,7 @@ namespace Ryujinx.Ava.Utilities.Configuration /// /// The current version of the file format /// - public const int CurrentVersion = 67; + public const int CurrentVersion = 68; /// /// Version of the configuration file format @@ -258,6 +258,11 @@ namespace Ryujinx.Ava.Utilities.Configuration /// Enables or disables low-power profiled translation cache persistency loading /// public bool EnableLowPowerPtc { get; set; } + + /// + /// Clock tick scalar, in percent points (100 = 1.0). + /// + public long TickScalar { get; set; } /// /// Enables or disables guest Internet access diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs index 8a0ddb560..7e693152e 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs @@ -94,6 +94,7 @@ namespace Ryujinx.Ava.Utilities.Configuration System.EnableDockedMode.Value = cff.DockedMode; System.EnablePtc.Value = cff.EnablePtc; System.EnableLowPowerPtc.Value = cff.EnableLowPowerPtc; + System.TickScalar.Value = cff.TickScalar; System.EnableInternetAccess.Value = cff.EnableInternetAccess; System.EnableFsIntegrityChecks.Value = cff.EnableFsIntegrityChecks; System.FsGlobalAccessLogMode.Value = cff.FsGlobalAccessLogMode; @@ -441,7 +442,27 @@ namespace Ryujinx.Ava.Utilities.Configuration (64, static cff => cff.LoggingEnableAvalonia = false), (65, static cff => cff.UpdateCheckerType = cff.CheckUpdatesOnStart ? UpdaterType.PromptAtStartup : UpdaterType.Off), (66, static cff => cff.DisableInputWhenOutOfFocus = false), - (67, static cff => cff.FocusLostActionType = cff.DisableInputWhenOutOfFocus ? FocusLostType.BlockInput : FocusLostType.DoNothing) + (67, static cff => cff.FocusLostActionType = cff.DisableInputWhenOutOfFocus ? FocusLostType.BlockInput : FocusLostType.DoNothing), + (68, static cff => + { + cff.TickScalar = 200; + cff.Hotkeys = new KeyboardHotkeys + { + ToggleVSyncMode = cff.Hotkeys.ToggleVSyncMode, + Screenshot = cff.Hotkeys.Screenshot, + ShowUI = cff.Hotkeys.ShowUI, + Pause = cff.Hotkeys.Pause, + ToggleMute = cff.Hotkeys.ToggleMute, + ResScaleUp = cff.Hotkeys.ResScaleUp, + ResScaleDown = cff.Hotkeys.ResScaleDown, + VolumeUp = cff.Hotkeys.VolumeUp, + VolumeDown = cff.Hotkeys.VolumeDown, + CustomVSyncIntervalIncrement = cff.Hotkeys.CustomVSyncIntervalIncrement, + CustomVSyncIntervalDecrement = cff.Hotkeys.CustomVSyncIntervalDecrement, + TurboMode = Key.Unbound, + TurboModeWhileHeld = false + }; + }) ); } } diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs index ead99fbac..b27d27492 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs @@ -335,6 +335,11 @@ namespace Ryujinx.Ava.Utilities.Configuration /// Enables or disables persistent profiled translation cache /// public ReactiveObject EnablePtc { get; private set; } + + /// + /// Clock tick scalar, in percent points (100 = 1.0). + /// + public ReactiveObject TickScalar { get; set; } /// /// Enables or disables low-power persistent profiled translation cache loading @@ -411,6 +416,15 @@ namespace Ryujinx.Ava.Utilities.Configuration EnableLowPowerPtc.LogChangesToValue(nameof(EnableLowPowerPtc)); EnableLowPowerPtc.Event += (_, evnt) => Optimizations.LowPower = evnt.NewValue; + TickScalar = new ReactiveObject(); + TickScalar.LogChangesToValue(nameof(TickScalar)); + TickScalar.Event += (_, evnt) => + { + if (Switch.Shared is null) + return; + + Switch.Shared.Configuration.TickScalar = evnt.NewValue; + }; EnableInternetAccess = new ReactiveObject(); EnableInternetAccess.LogChangesToValue(nameof(EnableInternetAccess)); EnableFsIntegrityChecks = new ReactiveObject(); diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs index 4fdf7c4f0..44396aef4 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs @@ -73,6 +73,7 @@ namespace Ryujinx.Ava.Utilities.Configuration EnableColorSpacePassthrough = Graphics.EnableColorSpacePassthrough, EnablePtc = System.EnablePtc, EnableLowPowerPtc = System.EnableLowPowerPtc, + TickScalar = System.TickScalar, EnableInternetAccess = System.EnableInternetAccess, EnableFsIntegrityChecks = System.EnableFsIntegrityChecks, FsGlobalAccessLogMode = System.FsGlobalAccessLogMode, @@ -261,6 +262,10 @@ namespace Ryujinx.Ava.Utilities.Configuration ResScaleDown = Key.Unbound, VolumeUp = Key.Unbound, VolumeDown = Key.Unbound, + CustomVSyncIntervalIncrement = Key.Unbound, + CustomVSyncIntervalDecrement = Key.Unbound, + TurboMode = Key.Unbound, + TurboModeWhileHeld = false }; Hid.RainbowSpeed.Value = 1f; Hid.InputConfig.Value = @@ -327,5 +332,5 @@ namespace Ryujinx.Ava.Utilities.Configuration return GraphicsBackend.OpenGl; } - } - } + } +} -- 2.47.1 From 768406cb67ef91630d571ec1353c9715708c9c89 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Mon, 3 Mar 2025 12:42:00 -0600 Subject: [PATCH 4/7] Improve description of Turbo Mode in the UI and localize FPS/Turbo indicator on status bar --- src/Ryujinx.HLE/PerformanceStatistics.cs | 11 -- src/Ryujinx/AppHost.cs | 15 +- src/Ryujinx/Assets/locales.json | 156 ++++++++++++------ src/Ryujinx/Common/LocaleManager.cs | 7 + .../UI/Views/Settings/SettingsCPUView.axaml | 9 +- .../Views/Settings/SettingsHotkeysView.axaml | 2 +- 6 files changed, 130 insertions(+), 70 deletions(-) diff --git a/src/Ryujinx.HLE/PerformanceStatistics.cs b/src/Ryujinx.HLE/PerformanceStatistics.cs index 48f4a0575..9363ff2d3 100644 --- a/src/Ryujinx.HLE/PerformanceStatistics.cs +++ b/src/Ryujinx.HLE/PerformanceStatistics.cs @@ -166,17 +166,6 @@ namespace Ryujinx.HLE return 1000 / _frameRate[FrameTypeGame]; } - public string FormatGameFrameRate() - { - double frameRate = GetGameFrameRate(); - double frameTime = GetGameFrameTime(); - string turboSuffix = _device.TurboMode - ? $" Turbo ({_device.TickScalar}%)" - : string.Empty; - - return $"{frameRate:00.00} FPS ({frameTime:00.00}ms){turboSuffix}"; - } - public string FormatFifoPercent() { double fifoPercent = GetFifoPercent(); diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index 36716a0cb..9901d4724 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -4,6 +4,7 @@ using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input; using Avalonia.Threading; using DiscordRPC; +using Gommon; using LibHac.Common; using LibHac.Ns; using LibHac.Tools.FsSystem; @@ -1153,11 +1154,23 @@ namespace Ryujinx.Ava LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%", dockedMode, ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), - Device.Statistics.FormatGameFrameRate(), + FormatGameFrameRate(), Device.Statistics.FormatFifoPercent(), _displayCount)); } + private string FormatGameFrameRate() + { + string frameRate = Device.Statistics.GetGameFrameRate().ToString("00.00"); + string frameTime = Device.Statistics.GetGameFrameTime().ToString("00.00"); + + return Device.TurboMode + ? LocaleManager.GetUnformatted(LocaleKeys.FpsTurboStatusBarText) + .Format(frameRate, frameTime, Device.TickScalar) + : LocaleManager.GetUnformatted(LocaleKeys.FpsStatusBarText) + .Format(frameRate, frameTime); + } + public async Task ShowExitPrompt() { bool shouldExit = !ConfigurationState.Instance.ShowConfirmExit; diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 659f03f41..e275be454 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -4898,37 +4898,12 @@ } }, { - "ID": "SettingsTabSystemTurboMultiplierValue", + "ID": "SettingsTabSystemTurboMultiplier", "Translations": { "ar_SA": "", "de_DE": "", "el_GR": "", - "en_US": "Turbo multiplier:", - "es_ES": "", - "fr_FR": "", - "he_IL": "", - "it_IT": "", - "ja_JP": "", - "ko_KR": "", - "no_NO": "", - "pl_PL": "", - "pt_BR": "", - "ru_RU": "", - "sv_SE": "", - "th_TH": "", - "tr_TR": "", - "uk_UA": "", - "zh_CN": "", - "zh_TW": "" - } - }, - { - "ID": "SettingsTabSystemTurboMultiplierSliderToolTip", - "Translations": { - "ar_SA": "", - "de_DE": "", - "el_GR": "", - "en_US": "The Turbo mode multiplier target value.\n\nLeave at 100 if unsure.", + "en_US": "Turbo Mode multiplier:", "es_ES": "", "fr_FR": "", "he_IL": "", @@ -4953,7 +4928,32 @@ "ar_SA": "", "de_DE": "", "el_GR": "", - "en_US": "The Turbo mode multiplier, as a percentage of the normal Switch clock speed.\n\nLeave at 100 if unsure.", + "en_US": "The Turbo mode multiplier target value.\n\nLeave at 200 if unsure.", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "SettingsTabSystemTurboMultiplierToolTip", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Turbo mode is an emulator feature which effectively causes speed up or slow down when a game is not frame-rate sensitive.\nYou can toggle this feature in-game with a hotkey, configurable in Ryujinx Keyboard Hotkeys settings.\n\nLeave at 200 if unsure.", "es_ES": "", "fr_FR": "", "he_IL": "", @@ -5172,31 +5172,6 @@ "zh_TW": "可能導致模擬器不穩定" } }, - { - "ID": "SettingsTabCpuHacksNote", - "Translations": { - "ar_SA": "", - "de_DE": "", - "el_GR": "", - "en_US": "Can and will cause crashing, slow/too fast games, etc. Use with caution.", - "es_ES": "", - "fr_FR": "", - "he_IL": "", - "it_IT": "", - "ja_JP": "", - "ko_KR": "", - "no_NO": "", - "pl_PL": "", - "pt_BR": "", - "ru_RU": "", - "sv_SE": "", - "th_TH": "", - "tr_TR": "", - "uk_UA": "", - "zh_CN": "", - "zh_TW": "" - } - }, { "ID": "SettingsTabSystemDramSize", "Translations": { @@ -18172,6 +18147,56 @@ "zh_TW": "更新已停用!" } }, + { + "ID": "FpsStatusBarText", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "{0} FPS ({1}ms)", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "FpsTurboStatusBarText", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "{0} FPS ({1}ms), Turbo ({2}%)", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "UpdaterBackgroundStatusBarButtonText", "Translations": { @@ -23922,6 +23947,31 @@ "zh_TW": "" } }, + { + "ID": "SettingsTabHotkeysTurboModeToolTip", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "The Turbo mode hotkey.\nConfigure the behavior of Turbo mode in Ryujinx CPU settings.\n\nLeave Unbound if unsure.", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "SettingsTabHotkeysOnlyWhilePressed", "Translations": { diff --git a/src/Ryujinx/Common/LocaleManager.cs b/src/Ryujinx/Common/LocaleManager.cs index f60cff49b..9320985f7 100644 --- a/src/Ryujinx/Common/LocaleManager.cs +++ b/src/Ryujinx/Common/LocaleManager.cs @@ -57,6 +57,13 @@ namespace Ryujinx.Ava.Common.Locale SetDynamicValues(LocaleKeys.RyujinxRebooter, RyujinxApp.FullAppName); } + public static string GetUnformatted(LocaleKeys key) => Instance.Get(key); + + public string Get(LocaleKeys key) => + _localeStrings.TryGetValue(key, out string value) + ? value + : key.ToString(); + public string this[LocaleKeys key] { get diff --git a/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml index 976309995..9c2977ba1 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml @@ -87,7 +87,7 @@ + Text="{ext:Locale SettingsTabSystemHacksNote}" /> - + -- 2.47.1 From ef1529a2d944bd1ef248704e62f2dab2ffbdc38b Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Mon, 3 Mar 2025 13:38:52 -0600 Subject: [PATCH 5/7] localize Turbo Mode for French --- src/Ryujinx/Assets/locales.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index e275be454..cd6775bae 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -4905,7 +4905,7 @@ "el_GR": "", "en_US": "Turbo Mode multiplier:", "es_ES": "", - "fr_FR": "", + "fr_FR": "Multiplicateur du Mode Turbo :", "he_IL": "", "it_IT": "", "ja_JP": "", @@ -4930,7 +4930,7 @@ "el_GR": "", "en_US": "The Turbo mode multiplier target value.\n\nLeave at 200 if unsure.", "es_ES": "", - "fr_FR": "", + "fr_FR": "La valeur souhaitée du multiplicateur du Mode Turbo.\n\nGarder à 200 si incertain.", "he_IL": "", "it_IT": "", "ja_JP": "", @@ -4955,7 +4955,7 @@ "el_GR": "", "en_US": "Turbo mode is an emulator feature which effectively causes speed up or slow down when a game is not frame-rate sensitive.\nYou can toggle this feature in-game with a hotkey, configurable in Ryujinx Keyboard Hotkeys settings.\n\nLeave at 200 if unsure.", "es_ES": "", - "fr_FR": "", + "fr_FR": "Le Mode Turbo est une fonctionnalité de l'émulateur qui accélère ou ralentit le jeu lorsque ce dernier n'est pas sensible au framerate.\nVous pouvez changer cette option en jeu avec un raccourci clavier, configurable dans les paramètres de Raccourcis clavier de Ryujinx.\n\nGarder à 200 si incertain.", "he_IL": "", "it_IT": "", "ja_JP": "", @@ -10555,7 +10555,7 @@ "el_GR": "", "en_US": "Unbound", "es_ES": "", - "fr_FR": "Pas Attribuée", + "fr_FR": "Non Attribuée", "he_IL": "", "it_IT": "Non assegnato", "ja_JP": "", @@ -18175,7 +18175,7 @@ { "ID": "FpsTurboStatusBarText", "Translations": { - "ar_SA": "", + "ar_SA": "{0} FPS ({1}ms), التوربو %{2}", "de_DE": "", "el_GR": "", "en_US": "{0} FPS ({1}ms), Turbo ({2}%)", @@ -23930,7 +23930,7 @@ "el_GR": "", "en_US": "Turbo mode:", "es_ES": "", - "fr_FR": "", + "fr_FR": "Mode Turbo :", "he_IL": "", "it_IT": "", "ja_JP": "", @@ -23955,7 +23955,7 @@ "el_GR": "", "en_US": "The Turbo mode hotkey.\nConfigure the behavior of Turbo mode in Ryujinx CPU settings.\n\nLeave Unbound if unsure.", "es_ES": "", - "fr_FR": "", + "fr_FR": "Le raccourci clavier Mode Turbo.\nConfigurez le comportement du Mode Turbo dans les paramètres de CPU de Ryujinx.\n\nLaisser Non Attribuée si incertain.", "he_IL": "", "it_IT": "", "ja_JP": "", @@ -23980,7 +23980,7 @@ "el_GR": "", "en_US": "Only while pressed", "es_ES": "", - "fr_FR": "", + "fr_FR": "Seulement quand le raccourci est maintenu", "he_IL": "", "it_IT": "", "ja_JP": "", -- 2.47.1 From 94f34a9ed148623f1f412d48b553eda9e58438a4 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Tue, 4 Mar 2025 01:19:18 -0600 Subject: [PATCH 6/7] properly merge + move hleconfig tick scalar parameter --- src/Ryujinx.Cpu/ITickSource.cs | 2 + src/Ryujinx.HLE/HleConfiguration.cs | 4 +- src/Ryujinx.HLE/Switch.cs | 7 +- src/Ryujinx/AppHost.cs | 71 ++++----------- src/Ryujinx/Headless/HeadlessRyujinx.Init.cs | 86 +++++++++---------- .../Configuration/ConfigurationState.Model.cs | 2 +- 6 files changed, 66 insertions(+), 106 deletions(-) diff --git a/src/Ryujinx.Cpu/ITickSource.cs b/src/Ryujinx.Cpu/ITickSource.cs index c352df85a..4aff612f0 100644 --- a/src/Ryujinx.Cpu/ITickSource.cs +++ b/src/Ryujinx.Cpu/ITickSource.cs @@ -8,6 +8,8 @@ namespace Ryujinx.Cpu /// public interface ITickSource : ICounter { + public const long RealityTickScalar = 100; + /// /// Time elapsed since the counter was created. /// diff --git a/src/Ryujinx.HLE/HleConfiguration.cs b/src/Ryujinx.HLE/HleConfiguration.cs index 4d7b9d350..39745ff53 100644 --- a/src/Ryujinx.HLE/HleConfiguration.cs +++ b/src/Ryujinx.HLE/HleConfiguration.cs @@ -206,6 +206,7 @@ namespace Ryujinx.HLE VSyncMode vSyncMode, bool enableDockedMode, bool enablePtc, + long tickScalar, bool enableInternetAccess, IntegrityCheckLevel fsIntegrityCheckLevel, int fsGlobalAccessLogMode, @@ -222,7 +223,6 @@ namespace Ryujinx.HLE string multiplayerLdnPassphrase, string multiplayerLdnServer, int customVSyncInterval, - long tickScalar, EnabledDirtyHack[] dirtyHacks = null) { MemoryConfiguration = memoryConfiguration; @@ -232,6 +232,7 @@ namespace Ryujinx.HLE CustomVSyncInterval = customVSyncInterval; EnableDockedMode = enableDockedMode; EnablePtc = enablePtc; + TickScalar = tickScalar; EnableInternetAccess = enableInternetAccess; FsIntegrityCheckLevel = fsIntegrityCheckLevel; FsGlobalAccessLogMode = fsGlobalAccessLogMode; @@ -247,7 +248,6 @@ namespace Ryujinx.HLE MultiplayerDisableP2p = multiplayerDisableP2p; MultiplayerLdnPassphrase = multiplayerLdnPassphrase; MultiplayerLdnServer = multiplayerLdnServer; - TickScalar = tickScalar; Hacks = dirtyHacks ?? []; } diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index d973a30fc..e52b3df15 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -4,6 +4,7 @@ using Ryujinx.Audio.Backends.CompatLayer; using Ryujinx.Audio.Integration; using Ryujinx.Common; using Ryujinx.Common.Configuration; +using Ryujinx.Cpu; using Ryujinx.Graphics.Gpu; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; @@ -31,7 +32,7 @@ namespace Ryujinx.HLE public long TickScalar { - get => System?.TickSource?.TickScalar ?? 100; + get => System?.TickSource?.TickScalar ?? ITickSource.RealityTickScalar; set => System.TickSource.TickScalar = value; } @@ -83,7 +84,7 @@ namespace Ryujinx.HLE VSyncMode = Configuration.VSyncMode; CustomVSyncInterval = Configuration.CustomVSyncInterval; - TickScalar = TurboMode ? Configuration.TickScalar : 100; + TickScalar = TurboMode ? Configuration.TickScalar : ITickSource.RealityTickScalar; System.State.DockedMode = Configuration.EnableDockedMode; System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default; System.EnablePtc = Configuration.EnablePtc; @@ -138,7 +139,7 @@ namespace Ryujinx.HLE public void ToggleTurbo() { TurboMode = !TurboMode; - TickScalar = TurboMode ? Configuration.TickScalar : 100; + TickScalar = TurboMode ? Configuration.TickScalar : ITickSource.RealityTickScalar; } public bool LoadCart(string exeFsDir, string romFsFile = null) => Processes.LoadUnpackedNca(exeFsDir, romFsFile); diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index 9901d4724..c2fb8b873 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -7,7 +7,6 @@ using DiscordRPC; using Gommon; using LibHac.Common; using LibHac.Ns; -using LibHac.Tools.FsSystem; using Ryujinx.Audio.Backends.Dummy; using Ryujinx.Audio.Backends.OpenAL; using Ryujinx.Audio.Backends.SDL2; @@ -36,11 +35,9 @@ using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.OpenGL; using Ryujinx.Graphics.Vulkan; -using Ryujinx.HLE; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.SystemState; using Ryujinx.Input; using Ryujinx.Input.HLE; using SkiaSharp; @@ -903,54 +900,19 @@ namespace Ryujinx.Ava _ => new OpenGLRenderer() }; - BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; - - bool isGALThreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading); - if (isGALThreaded) - { - renderer = new ThreadedRenderer(renderer); - } - - Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}"); - // Initialize Configuration. - MemoryConfiguration memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value; - - Device = new Switch(new HLEConfiguration( - VirtualFileSystem, - _viewModel.LibHacHorizonManager, - ContentManager, - _accountManager, - _userChannelPersistence, - renderer, - InitializeAudio(), - memoryConfiguration, - _viewModel.UiHandler, - (SystemLanguage)ConfigurationState.Instance.System.Language.Value, - (RegionCode)ConfigurationState.Instance.System.Region.Value, - ConfigurationState.Instance.Graphics.VSyncMode, - ConfigurationState.Instance.System.EnableDockedMode, - ConfigurationState.Instance.System.EnablePtc, - ConfigurationState.Instance.System.EnableInternetAccess, - ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None, - ConfigurationState.Instance.System.FsGlobalAccessLogMode, - ConfigurationState.Instance.System.MatchSystemTime - ? 0 - : ConfigurationState.Instance.System.SystemTimeOffset, - ConfigurationState.Instance.System.TimeZone, - ConfigurationState.Instance.System.MemoryManagerMode, - ConfigurationState.Instance.System.IgnoreMissingServices, - ConfigurationState.Instance.Graphics.AspectRatio, - ConfigurationState.Instance.System.AudioVolume, - ConfigurationState.Instance.System.UseHypervisor, - ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value, - ConfigurationState.Instance.Multiplayer.Mode, - ConfigurationState.Instance.Multiplayer.DisableP2p, - ConfigurationState.Instance.Multiplayer.LdnPassphrase, - ConfigurationState.Instance.Multiplayer.GetLdnServer(), - ConfigurationState.Instance.Graphics.CustomVSyncInterval, - ConfigurationState.Instance.System.TickScalar, - ConfigurationState.Instance.Hacks.ShowDirtyHacks ? ConfigurationState.Instance.Hacks.EnabledHacks : null)); + Device = new Switch(ConfigurationState.Instance.CreateHleConfiguration() + .Configure( + VirtualFileSystem, + _viewModel.LibHacHorizonManager, + ContentManager, + _accountManager, + _userChannelPersistence, + renderer.TryMakeThreaded(ConfigurationState.Instance.Graphics.BackendThreading), + InitializeAudio(), + _viewModel.UiHandler + ) + ); } private static IHardwareDeviceDriver InitializeAudio() @@ -1196,6 +1158,9 @@ namespace Ryujinx.Ava private void UpdateShaderCount() { + if (_displayCount is 0 && _renderer.ProgramCount is 0) + return; + // If there is a mismatch between total program compile and previous count // this means new shaders have been compiled and should be displayed. if (_renderer.ProgramCount != _previousCount) @@ -1275,12 +1240,10 @@ namespace Ryujinx.Ava VSyncModeToggle(); break; case KeyboardHotkeyState.CustomVSyncIntervalDecrement: - Device.DecrementCustomVSyncInterval(); - _viewModel.CustomVSyncInterval -= 1; + _viewModel.CustomVSyncInterval = Device.DecrementCustomVSyncInterval(); break; case KeyboardHotkeyState.CustomVSyncIntervalIncrement: - Device.IncrementCustomVSyncInterval(); - _viewModel.CustomVSyncInterval += 1; + _viewModel.CustomVSyncInterval = Device.IncrementCustomVSyncInterval(); break; case KeyboardHotkeyState.TurboMode: if (!ConfigurationState.Instance.Hid.Hotkeys.Value.TurboModeWhileHeld) diff --git a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs index b676b104e..beb28e885 100644 --- a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs +++ b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs @@ -10,6 +10,7 @@ using Ryujinx.Common.Configuration.Hid.Controller.Motion; using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; +using Ryujinx.Cpu; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.OpenGL; @@ -311,51 +312,44 @@ namespace Ryujinx.Headless return new OpenGLRenderer(); } - - private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options) - { - BackendThreading threadingMode = options.BackendThreading; - - bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading); - - if (threadedGAL) - { - renderer = new ThreadedRenderer(renderer); - } - - HLEConfiguration configuration = new(_virtualFileSystem, - _libHacHorizonManager, - _contentManager, - _accountManager, - _userChannelPersistence, - renderer, - new SDL2HardwareDeviceDriver(), - options.DramSize, - window, - options.SystemLanguage, - options.SystemRegion, - options.VSyncMode, - !options.DisableDockedMode, - !options.DisablePTC, - options.EnableInternetAccess, - !options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None, - options.FsGlobalAccessLogMode, - options.SystemTimeOffset, - options.SystemTimeZone, - options.MemoryManagerMode, - options.IgnoreMissingServices, - options.AspectRatio, - options.AudioVolume, - options.UseHypervisor ?? true, - options.MultiplayerLanInterfaceId, - Common.Configuration.Multiplayer.MultiplayerMode.Disabled, - false, - string.Empty, - string.Empty, - options.CustomVSyncInterval, - 100); - - return new Switch(configuration); - } + + private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options) => + new( + new HleConfiguration( + options.DramSize, + options.SystemLanguage, + options.SystemRegion, + options.VSyncMode, + !options.DisableDockedMode, + !options.DisablePTC, + ITickSource.RealityTickScalar, + options.EnableInternetAccess, + !options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None, + options.FsGlobalAccessLogMode, + options.SystemTimeOffset, + options.SystemTimeZone, + options.MemoryManagerMode, + options.IgnoreMissingServices, + options.AspectRatio, + options.AudioVolume, + options.UseHypervisor ?? true, + options.MultiplayerLanInterfaceId, + Common.Configuration.Multiplayer.MultiplayerMode.Disabled, + false, + string.Empty, + string.Empty, + options.CustomVSyncInterval + ) + .Configure( + _virtualFileSystem, + _libHacHorizonManager, + _contentManager, + _accountManager, + _userChannelPersistence, + renderer.TryMakeThreaded(options.BackendThreading), + new SDL2HardwareDeviceDriver(), + window + ) + ); } } diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs index 82d1fc179..2d839f9b1 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs @@ -862,6 +862,7 @@ namespace Ryujinx.Ava.Utilities.Configuration Graphics.VSyncMode, System.EnableDockedMode, System.EnablePtc, + System.TickScalar, System.EnableInternetAccess, System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid @@ -882,7 +883,6 @@ namespace Ryujinx.Ava.Utilities.Configuration Multiplayer.LdnPassphrase, Multiplayer.GetLdnServer(), Graphics.CustomVSyncInterval, - System.TickScalar, Hacks.ShowDirtyHacks ? Hacks.EnabledHacks : null); } } -- 2.47.1 From 51f3554f82ef2ed8b619ea7a597ddd103c76856d Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Mon, 10 Mar 2025 01:27:24 -0500 Subject: [PATCH 7/7] cap turbo to 300% --- src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml index 9c2977ba1..b3a4b66f9 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml @@ -109,7 +109,7 @@ SimpleNumberFormat="F0" SpinButtonPlacementMode="Hidden" Minimum="50" - Maximum="500" /> + Maximum="300" />