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..4aff612f0 100644
--- a/src/Ryujinx.Cpu/ITickSource.cs
+++ b/src/Ryujinx.Cpu/ITickSource.cs
@@ -8,10 +8,17 @@ namespace Ryujinx.Cpu
///
public interface ITickSource : ICounter
{
+ public const long RealityTickScalar = 100;
+
///
/// 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.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index 720722feb..3ecece63e 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -1072,7 +1072,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
///
private void UpdateIndexBufferState()
{
- var indexBuffer = _state.State.IndexBufferState;
+ var indexBufferNullable = _state?.State.IndexBufferState;
+
+ if (!indexBufferNullable.HasValue)
+ {
+ return;
+ }
+
+ IndexBufferState indexBuffer = indexBufferNullable.Value;
if (_drawState.IndexCount == 0)
{
diff --git a/src/Ryujinx.HLE/HLEConfiguration.cs b/src/Ryujinx.HLE/HLEConfiguration.cs
index a6c22cb69..e4ce7cf38 100644
--- a/src/Ryujinx.HLE/HLEConfiguration.cs
+++ b/src/Ryujinx.HLE/HLEConfiguration.cs
@@ -103,6 +103,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.
@@ -219,6 +224,7 @@ namespace Ryujinx.HLE
VSyncMode vSyncMode,
bool enableDockedMode,
bool enablePtc,
+ long tickScalar,
bool enableInternetAccess,
IntegrityCheckLevel fsIntegrityCheckLevel,
int fsGlobalAccessLogMode,
@@ -254,6 +260,7 @@ namespace Ryujinx.HLE
CustomVSyncInterval = customVSyncInterval;
EnableDockedMode = enableDockedMode;
EnablePtc = enablePtc;
+ TickScalar = tickScalar;
EnableInternetAccess = enableInternetAccess;
FsIntegrityCheckLevel = fsIntegrityCheckLevel;
FsGlobalAccessLogMode = fsGlobalAccessLogMode;
diff --git a/src/Ryujinx.HLE/HOS/Services/IpcService.cs b/src/Ryujinx.HLE/HOS/Services/IpcService.cs
index c4376a91d..94c8a15c3 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");
}
diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
index 23bf8bcfc..eaa3a69f7 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;
@@ -90,7 +91,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 890bce8bc..97f1ff7ce 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];
diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs
index e58be05bd..3b89b34a7 100644
--- a/src/Ryujinx.HLE/Switch.cs
+++ b/src/Ryujinx.HLE/Switch.cs
@@ -1,6 +1,7 @@
using Ryujinx.Audio.Backends.CompatLayer;
using Ryujinx.Audio.Integration;
using Ryujinx.Common.Configuration;
+using Ryujinx.Cpu;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
@@ -17,12 +18,23 @@ namespace Ryujinx.HLE
{
public class Switch : IDisposable
{
+ public static Switch Shared { get; private set; }
+
public HLEConfiguration Configuration { get; }
public IHardwareDeviceDriver AudioDeviceDriver { get; }
public MemoryBlock Memory { get; }
public GpuContext Gpu { get; }
public VirtualFileSystem FileSystem { get; }
public HOS.Horizon System { get; }
+
+ public bool TurboMode = false;
+
+ public long TickScalar
+ {
+ get => System?.TickSource?.TickScalar ?? ITickSource.RealityTickScalar;
+ set => System.TickSource.TickScalar = value;
+ }
+
public ProcessLoader Processes { get; }
public PerformanceStatistics Statistics { get; }
public Hid Hid { get; }
@@ -30,12 +42,11 @@ namespace Ryujinx.HLE
public IHostUIHandler UIHandler { get; }
public Debugger.Debugger Debugger { 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; } = VSyncMode.Switch;
public bool CustomVSyncIntervalEnabled { get; set; } = false;
public int CustomVSyncInterval { get; set; }
-
public long TargetVSyncInterval { get; set; } = 60;
public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable;
@@ -60,7 +71,7 @@ namespace Ryujinx.HLE
Gpu = new GpuContext(Configuration.GpuRenderer);
Debugger = Configuration.EnableGdbStub ? new Debugger.Debugger(this, Configuration.GdbStubPort) : null;
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();
@@ -71,6 +82,7 @@ namespace Ryujinx.HLE
VSyncMode = Configuration.VSyncMode;
CustomVSyncInterval = Configuration.CustomVSyncInterval;
+ 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;
@@ -78,6 +90,8 @@ namespace Ryujinx.HLE
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
UpdateVSyncInterval();
#pragma warning restore IDE0055
+
+ Shared = this;
}
public bool LoadCart(string exeFsDir, string romFsFile = null)
@@ -175,6 +189,12 @@ namespace Ryujinx.HLE
}
}
+ public void ToggleTurbo()
+ {
+ TurboMode = !TurboMode;
+ TickScalar = TurboMode ? Configuration.TickScalar : ITickSource.RealityTickScalar;
+ }
+
public void SetVolume(float volume)
{
AudioDeviceDriver.Volume = Math.Clamp(volume, 0f, 1f);
@@ -215,6 +235,8 @@ namespace Ryujinx.HLE
FileSystem.Dispose();
Memory.Dispose();
Debugger?.Dispose();
+
+ Shared = null;
}
}
}
diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs
index 75e9ab2a1..8b29736ff 100644
--- a/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs
+++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs
@@ -239,6 +239,11 @@ namespace Ryujinx.UI.Common.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.UI.Common/Configuration/ConfigurationState.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs
index ef4784d57..e5e29cd2a 100644
--- a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs
+++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs
@@ -12,7 +12,6 @@ using Ryujinx.UI.Common.Configuration.UI;
using Ryujinx.UI.Common.Helper;
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Globalization;
namespace Ryujinx.UI.Common.Configuration
@@ -341,6 +340,11 @@ namespace Ryujinx.UI.Common.Configuration
///
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 profiled translation cache persistency loading
///
@@ -406,6 +410,15 @@ namespace Ryujinx.UI.Common.Configuration
EnablePtc.Event += static (sender, e) => LogValueChange(e, nameof(EnablePtc));
EnableLowPowerPtc = new ReactiveObject();
EnableLowPowerPtc.Event += static (sender, e) => LogValueChange(e, nameof(EnableLowPowerPtc));
+ TickScalar = new ReactiveObject();
+ TickScalar.Event += static (sender, e) => LogValueChange(e, nameof(TickScalar));
+ TickScalar.Event += static (sender, e) =>
+ {
+ if (Switch.Shared is null)
+ return;
+
+ Switch.Shared.Configuration.TickScalar = e.NewValue;
+ };
EnableInternetAccess = new ReactiveObject();
EnableInternetAccess.Event += static (sender, e) => LogValueChange(e, nameof(EnableInternetAccess));
EnableFsIntegrityChecks = new ReactiveObject();
@@ -813,6 +826,7 @@ namespace Ryujinx.UI.Common.Configuration
EnableColorSpacePassthrough = Graphics.EnableColorSpacePassthrough,
EnablePtc = System.EnablePtc,
EnableLowPowerPtc = System.EnableLowPowerPtc,
+ TickScalar = System.TickScalar,
EnableInternetAccess = System.EnableInternetAccess,
EnableFsIntegrityChecks = System.EnableFsIntegrityChecks,
FsGlobalAccessLogMode = System.FsGlobalAccessLogMode,
@@ -1000,6 +1014,10 @@ namespace Ryujinx.UI.Common.Configuration
ResScaleDown = Key.Unbound,
VolumeUp = Key.Unbound,
VolumeDown = Key.Unbound,
+ CustomVSyncIntervalIncrement = Key.Unbound,
+ CustomVSyncIntervalDecrement = Key.Unbound,
+ TurboMode = Key.Unbound,
+ TurboModeWhileHeld = false
};
Hid.InputConfig.Value =
[
@@ -1690,6 +1708,26 @@ namespace Ryujinx.UI.Common.Configuration
configurationFileFormat.MatchSystemTime = false;
+ // Turbo Mode should be version 59 - KeatonTheBot
+ // TODO: Fix config migration for Turbo Mode
+ configurationFileFormat.TickScalar = 200;
+ configurationFileFormat.Hotkeys = new KeyboardHotkeys
+ {
+ ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
+ Screenshot = configurationFileFormat.Hotkeys.Screenshot,
+ ShowUI = configurationFileFormat.Hotkeys.ShowUI,
+ Pause = configurationFileFormat.Hotkeys.Pause,
+ ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
+ ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
+ ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
+ VolumeUp = configurationFileFormat.Hotkeys.VolumeUp,
+ VolumeDown = configurationFileFormat.Hotkeys.VolumeDown,
+ CustomVSyncIntervalIncrement = configurationFileFormat.Hotkeys.CustomVSyncIntervalIncrement,
+ CustomVSyncIntervalDecrement = configurationFileFormat.Hotkeys.CustomVSyncIntervalDecrement,
+ TurboMode = Key.Unbound,
+ TurboModeWhileHeld = false
+ };
+
configurationFileUpdated = true;
}
@@ -1737,6 +1775,7 @@ namespace Ryujinx.UI.Common.Configuration
Graphics.EnableColorSpacePassthrough.Value = configurationFileFormat.EnableColorSpacePassthrough;
System.EnablePtc.Value = configurationFileFormat.EnablePtc;
System.EnableLowPowerPtc.Value = configurationFileFormat.EnableLowPowerPtc;
+ System.TickScalar.Value = configurationFileFormat.TickScalar;
System.EnableInternetAccess.Value = configurationFileFormat.EnableInternetAccess;
System.EnableFsIntegrityChecks.Value = configurationFileFormat.EnableFsIntegrityChecks;
System.FsGlobalAccessLogMode.Value = configurationFileFormat.FsGlobalAccessLogMode;
diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs
index 2be4671f5..7a48efdbe 100644
--- a/src/Ryujinx/AppHost.cs
+++ b/src/Ryujinx/AppHost.cs
@@ -3,6 +3,7 @@ using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input;
using Avalonia.Threading;
+using Gommon;
using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.Dummy;
using Ryujinx.Audio.Backends.OpenAL;
@@ -939,6 +940,7 @@ namespace Ryujinx.Ava
ConfigurationState.Instance.Graphics.VSyncMode,
ConfigurationState.Instance.System.EnableDockedMode,
ConfigurationState.Instance.System.EnablePtc,
+ ConfigurationState.Instance.System.TickScalar,
ConfigurationState.Instance.System.EnableInternetAccess,
ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
ConfigurationState.Instance.System.FsGlobalAccessLogMode,
@@ -1162,6 +1164,18 @@ namespace Ryujinx.Ava
_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;
@@ -1272,6 +1286,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:
@@ -1282,9 +1302,14 @@ namespace Ryujinx.Ava
_viewModel.CustomVSyncInterval -= 1;
break;
case KeyboardHotkeyState.CustomVSyncIntervalIncrement:
- 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;
@@ -1414,6 +1439,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/ar_SA.json b/src/Ryujinx/Assets/Locales/ar_SA.json
index 07bfbc34f..eb40ab1fc 100644
--- a/src/Ryujinx/Assets/Locales/ar_SA.json
+++ b/src/Ryujinx/Assets/Locales/ar_SA.json
@@ -803,5 +803,6 @@
"MultiplayerMode": "الوضع:",
"MultiplayerModeTooltip": "تغيير وضع LDN متعدد اللاعبين.\n\nسوف يقوم LdnMitm بتعديل وظيفة اللعب المحلية/اللاسلكية المحلية في الألعاب لتعمل كما لو كانت شبكة LAN، مما يسمح باتصالات الشبكة المحلية نفسها مع محاكيات ريوجينكس الأخرى وأجهزة نينتندو سويتش المخترقة التي تم تثبيت وحدة ldn_mitm عليها.\n\nيتطلب وضع اللاعبين المتعددين أن يكون جميع اللاعبين على نفس إصدار اللعبة (على سبيل المثال، يتعذر على الإصدار 13.0.1 من سوبر سماش برذرز ألتميت الاتصال بالإصدار 13.0.0).\n\nاتركه معطلا إذا لم تكن متأكدا.",
"MultiplayerModeDisabled": "معطل",
- "MultiplayerModeLdnMitm": "ldn_mitm"
+ "MultiplayerModeLdnMitm": "ldn_mitm",
+ "FpsTurboStatusBarText": "{0} FPS ({1}ms), التوربو %{2}"
}
diff --git a/src/Ryujinx/Assets/Locales/en_US.json b/src/Ryujinx/Assets/Locales/en_US.json
index 7cab870fd..e0b042bb1 100644
--- a/src/Ryujinx/Assets/Locales/en_US.json
+++ b/src/Ryujinx/Assets/Locales/en_US.json
@@ -905,5 +905,13 @@
"SettingsTabDebugGDBStubToggleTooltip": "Enables the GDB stub, which makes it possible to debug the running application. For development use only!",
"SettingsTabDebugGDBStubPort": "GDB Stub Port:",
"SettingsTabDebugSuspendOnStart": "Suspend Application on Start",
- "SettingsTabDebugSuspendOnStartTooltip": "Suspends the application before executing the first instruction, allowing for debugging from the earliest point."
+ "SettingsTabDebugSuspendOnStartTooltip": "Suspends the application before executing the first instruction, allowing for debugging from the earliest point.",
+ "SettingsTabSystemTurboMultiplier": "Turbo Mode multiplier:",
+ "SettingsTabSystemTurboMultiplierValueToolTip": "The Turbo mode multiplier target value.\\n\\nLeave at 200 if unsure.",
+ "SettingsTabSystemTurboMultiplierToolTip": "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.",
+ "FpsStatusBarText": "{0} FPS ({1}ms)",
+ "FpsTurboStatusBarText": "{0} FPS ({1}ms), Turbo ({2}%)",
+ "SettingsTabHotkeysTurboMode": "Turbo mode:",
+ "SettingsTabHotkeysTurboModeToolTip": "The Turbo mode hotkey.\\nConfigure the behavior of Turbo mode in Ryujinx CPU settings.\\n\\nLeave Unbound if unsure.",
+ "SettingsTabHotkeysOnlyWhilePressed": "Only while pressed"
}
diff --git a/src/Ryujinx/Assets/Locales/fr_FR.json b/src/Ryujinx/Assets/Locales/fr_FR.json
index 7a02346e8..64fcbd93e 100644
--- a/src/Ryujinx/Assets/Locales/fr_FR.json
+++ b/src/Ryujinx/Assets/Locales/fr_FR.json
@@ -814,5 +814,12 @@
"MultiplayerMode": "Mode :",
"MultiplayerModeTooltip": "Changer le mode multijoueur LDN.\n\nLdnMitm modifiera la fonctionnalité de jeu sans fil local/jeu local dans les jeux pour fonctionner comme s'il s'agissait d'un LAN, permettant des connexions locales sur le même réseau avec d'autres instances de Ryujinx et des consoles Nintendo Switch piratées ayant le module ldn_mitm installé.\n\nLe multijoueur nécessite que tous les joueurs soient sur la même version du jeu (par exemple, Super Smash Bros. Ultimate v13.0.1 ne peut pas se connecter à v13.0.0).\n\nLaissez DÉSACTIVÉ si vous n'êtes pas sûr.",
"MultiplayerModeDisabled": "Désactivé",
- "MultiplayerModeLdnMitm": "ldn_mitm"
+ "MultiplayerModeLdnMitm": "ldn_mitm",
+ "SettingsTabSystemTurboMultiplier": "Multiplicateur du Mode Turbo :",
+ "SettingsTabSystemTurboMultiplierValueToolTip": "La valeur souhaitée du multiplicateur du Mode Turbo.\\n\\nGarder à 200 si incertain.",
+ "SettingsTabSystemTurboMultiplierToolTip": "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.",
+ "FpsStatusBarText": "{0} FPS ({1}ms)",
+ "SettingsTabHotkeysTurboMode": "Mode Turbo :",
+ "SettingsTabHotkeysTurboModeToolTip": "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.",
+ "SettingsTabHotkeysOnlyWhilePressed": "Seulement quand le raccourci est maintenu"
}
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/Common/Locale/LocaleManager.cs b/src/Ryujinx/Common/Locale/LocaleManager.cs
index 96f648761..6970094ed 100644
--- a/src/Ryujinx/Common/Locale/LocaleManager.cs
+++ b/src/Ryujinx/Common/Locale/LocaleManager.cs
@@ -48,6 +48,13 @@ namespace Ryujinx.Ava.Common.Locale
}
}
+ 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/Headless/HeadlessRyujinx.Init.cs b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
index 6fa04cb94..0bc53775c 100644
--- a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
+++ b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
@@ -9,6 +9,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;
@@ -339,6 +340,7 @@ namespace Ryujinx.Headless
options.VSyncMode,
!options.DisableDockedMode,
!options.DisablePTC,
+ ITickSource.RealityTickScalar,
options.EnableInternetAccess,
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
options.FsGlobalAccessLogMode,
diff --git a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs
index 4c7a6bd02..173fa6c99 100644
--- a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs
+++ b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs
@@ -126,22 +126,46 @@ namespace Ryujinx.Ava.UI.Models.Input
}
}
+ private Key _turboMode;
+ public Key TurboMode
+ {
+ get => _turboMode;
+ set
+ {
+ _turboMode = value;
+ OnPropertyChanged();
+ }
+ }
+
+ private bool _turboModeWhileHeld;
+ public bool TurboModeWhileHeld
+ {
+ get => _turboModeWhileHeld;
+ set
+ {
+ _turboModeWhileHeld = value;
+ OnPropertyChanged();
+ }
+ }
+
public HotkeyConfig(KeyboardHotkeys config)
{
- if (config != null)
- {
- ToggleVSyncMode = config.ToggleVSyncMode;
- Screenshot = config.Screenshot;
- ShowUI = config.ShowUI;
- Pause = config.Pause;
- ToggleMute = config.ToggleMute;
- ResScaleUp = config.ResScaleUp;
- ResScaleDown = config.ResScaleDown;
- VolumeUp = config.VolumeUp;
- VolumeDown = config.VolumeDown;
- CustomVSyncIntervalIncrement = config.CustomVSyncIntervalIncrement;
- CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement;
- }
+ if (config == null)
+ return;
+
+ ToggleVSyncMode = config.ToggleVSyncMode;
+ Screenshot = config.Screenshot;
+ ShowUI = config.ShowUI;
+ Pause = config.Pause;
+ ToggleMute = config.ToggleMute;
+ ResScaleUp = config.ResScaleUp;
+ ResScaleDown = config.ResScaleDown;
+ VolumeUp = config.VolumeUp;
+ VolumeDown = config.VolumeDown;
+ CustomVSyncIntervalIncrement = config.CustomVSyncIntervalIncrement;
+ CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement;
+ TurboMode = config.TurboMode;
+ TurboModeWhileHeld = config.TurboModeWhileHeld;
}
public KeyboardHotkeys GetConfig()
@@ -159,6 +183,8 @@ namespace Ryujinx.Ava.UI.Models.Input
VolumeDown = VolumeDown,
CustomVSyncIntervalIncrement = CustomVSyncIntervalIncrement,
CustomVSyncIntervalDecrement = CustomVSyncIntervalDecrement,
+ TurboMode = TurboMode,
+ TurboModeWhileHeld = TurboModeWhileHeld
};
return config;
diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
index 0a033129c..164e8281b 100644
--- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
@@ -56,6 +56,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;
@@ -232,6 +233,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; }
@@ -617,6 +637,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;
@@ -731,6 +752,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.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex;
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml
index 4c3546fca..3cab61a64 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml
+++ b/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml
@@ -6,6 +6,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+ xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d"
x:DataType="viewModels:SettingsViewModel">
@@ -70,6 +71,57 @@
ToolTip.Tip="{locale:Locale UseHypervisorTooltip}" />
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml
index baadfdd0c..2ce98ac1d 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml
+++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml
@@ -22,7 +22,7 @@
-
@@ -50,71 +50,79 @@
Classes="h1"
Text="{locale:Locale SettingsTabHotkeysHotkeys}" />
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs
index 5740a895d..86fcbe749 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs
+++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs
@@ -106,6 +106,9 @@ namespace Ryujinx.Ava.UI.Views.Settings
case "CustomVSyncIntervalDecrement":
viewModel.KeyboardHotkey.CustomVSyncIntervalDecrement = buttonValue.AsHidType();
break;
+ case "TurboMode":
+ viewModel.KeyboardHotkey.TurboMode = buttonValue.AsHidType();
+ break;
}
}
}