diff --git a/assets/Locales/Root.json b/assets/Locales/Root.json
index 757ddeec8..db84fd3ae 100644
--- a/assets/Locales/Root.json
+++ b/assets/Locales/Root.json
@@ -200,6 +200,31 @@
"zh_TW": "使用 Hypervisor"
}
},
+ {
+ "ID": "SettingsTabSystemGCLowLatency",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "Use Low-latency Garbage Collector",
+ "es_ES": "Usa recolección de basura de baja latencia",
+ "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": "MenuBarFile",
"Translations": {
@@ -16500,6 +16525,31 @@
"zh_TW": "變更客體記憶體的映射和存取方式。這會極大地影響模擬 CPU 效能。\n\n如果不確定,請設定為主體略過檢查模式。"
}
},
+ {
+ "ID": "GCLowLatencyTooltip",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "Sets the garbage collector for the CLR to low-latency mode.\n\nThis may decrease stuttering at the cost of performance.\n\nLeave OFF 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": "MemoryManagerSoftwareTooltip",
"Translations": {
diff --git a/src/Ryujinx/Systems/AppHost.cs b/src/Ryujinx/Systems/AppHost.cs
index afad7bc7b..627e486d2 100644
--- a/src/Ryujinx/Systems/AppHost.cs
+++ b/src/Ryujinx/Systems/AppHost.cs
@@ -580,7 +580,12 @@ namespace Ryujinx.Ava.Systems
{
_isActive = false;
_playTimer.Stop();
+
GCSettings.LatencyMode = GCLatencyMode.Interactive;
+ if (ConfigurationState.Instance.System.GCLowLatency)
+ {
+ Logger.Info?.Print(LogClass.Application, "Garbage collector set to interactive mode.");
+ }
}
private void Exit()
@@ -664,7 +669,12 @@ namespace Ryujinx.Ava.Systems
_chrono.Stop();
_playTimer.Stop();
+
GCSettings.LatencyMode = GCLatencyMode.Interactive;
+ if (ConfigurationState.Instance.System.GCLowLatency)
+ {
+ Logger.Info?.Print(LogClass.Application, "Garbage collector set to interactive mode.");
+ }
}
public void DisposeGpu()
@@ -918,8 +928,14 @@ namespace Ryujinx.Ava.Systems
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
appMetadata => appMetadata.UpdatePreGame()
);
+
_playTimer.Start();
- GCSettings.LatencyMode = GCLatencyMode.LowLatency;
+
+ if (ConfigurationState.Instance.System.GCLowLatency)
+ {
+ GCSettings.LatencyMode = GCLatencyMode.LowLatency;
+ Logger.Info?.Print(LogClass.Application, "Garbage collector set to low latency mode.");
+ }
}
internal void Resume()
@@ -930,7 +946,12 @@ namespace Ryujinx.Ava.Systems
_playTimer.Start();
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI);
Logger.Info?.Print(LogClass.Emulation, "Emulation was resumed.");
- GCSettings.LatencyMode = GCLatencyMode.LowLatency;
+
+ if (ConfigurationState.Instance.System.GCLowLatency)
+ {
+ GCSettings.LatencyMode = GCLatencyMode.LowLatency;
+ Logger.Info?.Print(LogClass.Application, "Garbage collector set to low latency mode.");
+ }
}
internal void Pause()
@@ -941,7 +962,12 @@ namespace Ryujinx.Ava.Systems
_playTimer.Stop();
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI, LocaleManager.Instance[LocaleKeys.Paused]);
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused.");
+
GCSettings.LatencyMode = GCLatencyMode.Interactive;
+ if (ConfigurationState.Instance.System.GCLowLatency)
+ {
+ Logger.Info?.Print(LogClass.Application, "Garbage collector set to interactive mode.");
+ }
}
private void InitEmulatedSwitch()
diff --git a/src/Ryujinx/Systems/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx/Systems/Configuration/ConfigurationFileFormat.cs
index 0b451eacb..55b2d2cac 100644
--- a/src/Ryujinx/Systems/Configuration/ConfigurationFileFormat.cs
+++ b/src/Ryujinx/Systems/Configuration/ConfigurationFileFormat.cs
@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.Systems.Configuration
///
/// The current version of the file format
///
- public const int CurrentVersion = 72;
+ public const int CurrentVersion = 73;
///
/// Version of the configuration file format
@@ -470,6 +470,11 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Uses Hypervisor over JIT if available
///
public bool UseHypervisor { get; set; }
+
+ ///
+ /// Enable or disable low-latency mode for garbage collection
+ ///
+ public bool GCLowLatency { get; set; }
///
/// Enables or disables the GDB stub
diff --git a/src/Ryujinx/Systems/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx/Systems/Configuration/ConfigurationState.Migration.cs
index 90a045a67..8890055ac 100644
--- a/src/Ryujinx/Systems/Configuration/ConfigurationState.Migration.cs
+++ b/src/Ryujinx/Systems/Configuration/ConfigurationState.Migration.cs
@@ -112,6 +112,7 @@ namespace Ryujinx.Ava.Systems.Configuration
System.IgnoreControllerApplet.Value = cff.IgnoreApplet;
System.SkipUserProfilesManager.Value = cff.SkipUserProfiles;
System.UseHypervisor.Value = cff.UseHypervisor;
+ System.GCLowLatency.Value = cff.GCLowLatency;
UI.GuiColumns.FavColumn.Value = shouldLoadFromFile ? cff.GuiColumns.FavColumn : UI.GuiColumns.FavColumn.Value;
UI.GuiColumns.IconColumn.Value = shouldLoadFromFile ? cff.GuiColumns.IconColumn : UI.GuiColumns.IconColumn.Value;
@@ -534,7 +535,8 @@ namespace Ryujinx.Ava.Systems.Configuration
{
if (cff.AudioBackend is AudioBackend.SDL2)
cff.AudioBackend = AudioBackend.SDL3;
- })
+ }),
+ (72, static cff => cff.GCLowLatency = false)
);
}
}
diff --git a/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs b/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs
index 7775125d4..c66f74ed5 100644
--- a/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs
+++ b/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs
@@ -417,6 +417,11 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Uses Hypervisor over JIT if available
///
public ReactiveObject UseHypervisor { get; private set; }
+
+ ///
+ /// Enable or disable low-latency garbage collection
+ ///
+ public ReactiveObject GCLowLatency { get; private set; }
public SystemSection()
{
@@ -471,6 +476,8 @@ namespace Ryujinx.Ava.Systems.Configuration
AudioVolume.LogChangesToValue(nameof(AudioVolume));
UseHypervisor = new ReactiveObject();
UseHypervisor.LogChangesToValue(nameof(UseHypervisor));
+ GCLowLatency = new ReactiveObject();
+ GCLowLatency.LogChangesToValue(nameof(GCLowLatency));
}
}
diff --git a/src/Ryujinx/Systems/Configuration/ConfigurationState.cs b/src/Ryujinx/Systems/Configuration/ConfigurationState.cs
index e4874963d..b4b5e8029 100644
--- a/src/Ryujinx/Systems/Configuration/ConfigurationState.cs
+++ b/src/Ryujinx/Systems/Configuration/ConfigurationState.cs
@@ -87,6 +87,7 @@ namespace Ryujinx.Ava.Systems.Configuration
IgnoreApplet = System.IgnoreControllerApplet,
SkipUserProfiles = System.SkipUserProfilesManager,
UseHypervisor = System.UseHypervisor,
+ GCLowLatency = System.GCLowLatency,
GuiColumns = new GuiColumns
{
FavColumn = UI.GuiColumns.FavColumn,
diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
index 6904d4ebc..d4532e8ca 100644
--- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
@@ -286,6 +286,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsVulkanSelected =>
GraphicsBackendIndex == 1 || (GraphicsBackendIndex == 0 && !OperatingSystem.IsMacOS());
public bool UseHypervisor { get; set; }
+ public bool GCLowLatency { get; set; }
public bool DisableP2P { get; set; }
public bool ShowDirtyHacks => ConfigurationState.Instance.Hacks.ShowDirtyHacks;
@@ -689,6 +690,7 @@ namespace Ryujinx.Ava.UI.ViewModels
EnableLowPowerPptc = config.System.EnableLowPowerPtc;
MemoryMode = (int)config.System.MemoryManagerMode.Value;
UseHypervisor = config.System.UseHypervisor;
+ GCLowLatency = config.System.GCLowLatency;
TurboMultiplier = config.System.TickScalar;
// Graphics
@@ -800,6 +802,7 @@ namespace Ryujinx.Ava.UI.ViewModels
config.System.EnableLowPowerPtc.Value = EnableLowPowerPptc;
config.System.MemoryManagerMode.Value = (MemoryManagerMode)MemoryMode;
config.System.UseHypervisor.Value = UseHypervisor;
+ config.System.GCLowLatency.Value = GCLowLatency;
config.System.TickScalar.Value = TurboMultiplier;
// Graphics
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml
index 2424aca97..c253c1aa0 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml
+++ b/src/Ryujinx/UI/Views/Settings/SettingsCPUView.axaml
@@ -71,6 +71,11 @@
+
+
+