From aef114c3092c08b7707f14857dc845fb30ce604b Mon Sep 17 00:00:00 2001
From: xam <87-xam@users.noreply.git.ryujinx.app>
Date: Mon, 20 Oct 2025 00:06:37 +0200
Subject: [PATCH 1/2] Settings: Debug: add purge all caches button
---
assets/locales.json | 75 +++++++++++++++++++
.../UI/Views/Settings/SettingsDebugView.axaml | 7 ++
.../Views/Settings/SettingsDebugView.axaml.cs | 60 ++++++++++++++-
3 files changed, 141 insertions(+), 1 deletion(-)
diff --git a/assets/locales.json b/assets/locales.json
index 8899bf692..45914a6d1 100644
--- a/assets/locales.json
+++ b/assets/locales.json
@@ -13717,6 +13717,56 @@
"zh_TW": "警告"
}
},
+ {
+ "ID": "DialogDeleteAllCaches",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "You are about to clear all caches for all games.\n\nAre you sure you want to proceed?",
+ "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": "DialogDeleteAllCachesErrorMessage",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "Failed to purge some caches, check log file.",
+ "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": "DialogPPTCDeletionMessage",
"Translations": {
@@ -24217,6 +24267,31 @@
"zh_TW": "在執行首項指令前暫停應用程式,以便從最早的點開始偵錯。"
}
},
+ {
+ "ID": "SettingsTabDebugPurgeAllCaches",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "Purge All Caches",
+ "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": "LdnGameListOpen",
"Translations": {
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml
index f491dda24..f1ff9c5ea 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml
+++ b/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml
@@ -53,12 +53,19 @@
+
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml.cs
index 14a65b8b2..d7924ab52 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml.cs
+++ b/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml.cs
@@ -1,4 +1,11 @@
using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Logging;
+using System;
+using System.IO;
namespace Ryujinx.Ava.UI.Views.Settings
{
@@ -8,6 +15,57 @@ namespace Ryujinx.Ava.UI.Views.Settings
{
InitializeComponent();
}
+
+ private async void PurgeAllSharedCaches_OnClick(object sender, RoutedEventArgs routedEventArgs)
+ {
+ var appList = RyujinxApp.MainWindow.ViewModel.Applications;
+
+ if (appList.Count == 0)
+ {
+ return;
+ }
+
+ UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
+ LocaleManager.Instance[LocaleKeys.DialogWarning],
+ LocaleManager.Instance[LocaleKeys.DialogDeleteAllCaches],
+ LocaleManager.Instance[LocaleKeys.InputDialogYes],
+ LocaleManager.Instance[LocaleKeys.InputDialogNo],
+ LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
+ bool hasErrors = false;
+
+ if (result != UserResult.Yes)
+ {
+ return;
+ }
+
+ foreach (var application in appList)
+ {
+ DirectoryInfo cacheDir = new(Path.Combine(AppDataManager.GamesDirPath, application.IdString, "cache"));
+
+ if (!cacheDir.Exists)
+ {
+ continue;
+ }
+
+ foreach (var finfo in cacheDir.EnumerateDirectories())
+ {
+ try
+ {
+ finfo.Delete(true);
+
+ }
+ catch (Exception ex)
+ {
+ Logger.Error?.Print(LogClass.Application, $"Failed to purge shader cache for {application.Name}({application.IdString}): {ex}");
+ hasErrors = true;
+ }
+ }
+ }
+
+ if (hasErrors)
+ {
+ await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogDeleteAllCachesErrorMessage]);
+ }
+ }
}
}
-
From 71ad102f7332f63df8f5a36dc31d234690fc8ac3 Mon Sep 17 00:00:00 2001
From: GreemDev
Date: Sun, 16 Nov 2025 18:51:10 -0600
Subject: [PATCH 2/2] Cleanup & successful deletion feedback
---
assets/locales.json | 52 +++++++++++++-
.../UI/ViewModels/SettingsViewModel.cs | 71 +++++++++++++++++--
.../UI/Views/Settings/SettingsDebugView.axaml | 4 +-
.../Views/Settings/SettingsDebugView.axaml.cs | 59 ---------------
4 files changed, 118 insertions(+), 68 deletions(-)
diff --git a/assets/locales.json b/assets/locales.json
index 45914a6d1..afb2ecf11 100644
--- a/assets/locales.json
+++ b/assets/locales.json
@@ -24292,6 +24292,56 @@
"zh_TW": ""
}
},
+ {
+ "ID": "SettingsTabDebugPurgeAllCachesSuccessTitle",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "All Shader & CPU caches deleted",
+ "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": "SettingsTabDebugPurgeAllCachesSuccessText",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "Destroyed the caches of {0} applications.",
+ "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": "LdnGameListOpen",
"Translations": {
@@ -24918,4 +24968,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
index 233c30bad..071d83f86 100644
--- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
@@ -4,11 +4,13 @@ using Avalonia.Media.Imaging;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
+using DynamicData.Binding;
using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.OpenAL;
using Ryujinx.Audio.Backends.SDL3;
using Ryujinx.Audio.Backends.SoundIo;
using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Ava.Systems.Configuration.UI;
@@ -19,6 +21,7 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Helper;
+using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.HLE;
@@ -912,7 +915,13 @@ namespace Ryujinx.Ava.UI.ViewModels
CloseWindow?.Invoke();
}
- [ObservableProperty] private bool _wantsToReset;
+ public void CancelButton()
+ {
+ RevertIfNotSaved();
+ CloseWindow?.Invoke();
+ }
+
+ [ObservableProperty] public partial bool WantsToReset { get; set; }
public AsyncRelayCommand ResetButton => Commands.Create(async () =>
{
@@ -932,10 +941,62 @@ namespace Ryujinx.Ava.UI.ViewModels
"Configuration Reset");
});
- public void CancelButton()
+ public AsyncRelayCommand PurgeAllCaches => Commands.Create(async () =>
{
- RevertIfNotSaved();
- CloseWindow?.Invoke();
- }
+ ObservableCollectionExtended appList = RyujinxApp.MainWindow.ViewModel.Applications;
+
+ if (appList.Count == 0)
+ {
+ return;
+ }
+
+ UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
+ LocaleManager.Instance[LocaleKeys.DialogWarning],
+ LocaleManager.Instance[LocaleKeys.DialogDeleteAllCaches],
+ LocaleManager.Instance[LocaleKeys.InputDialogYes],
+ LocaleManager.Instance[LocaleKeys.InputDialogNo],
+ LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
+
+ bool hasErrors = false;
+
+ if (result != UserResult.Yes)
+ {
+ return;
+ }
+
+ foreach (ApplicationData application in appList)
+ {
+ DirectoryInfo cacheDir = new(Path.Combine(AppDataManager.GamesDirPath, application.IdString, "cache"));
+
+ if (!cacheDir.Exists)
+ {
+ continue;
+ }
+
+ foreach (DirectoryInfo dInfo in cacheDir.EnumerateDirectories())
+ {
+ try
+ {
+ dInfo.Delete(recursive: true);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error?.PrintMsg(LogClass.Application, $"Failed to purge shader cache for {application.Name} ({application.IdString}): {ex}");
+ hasErrors = true;
+ }
+ }
+ }
+
+ if (hasErrors)
+ {
+ await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogDeleteAllCachesErrorMessage]);
+ }
+ else
+ {
+ NotificationHelper.ShowSuccess(
+ title: LocaleManager.Instance[LocaleKeys.SettingsTabDebugPurgeAllCachesSuccessTitle],
+ text: LocaleManager.GetFormatted(LocaleKeys.SettingsTabDebugPurgeAllCachesSuccessText, appList.Count));
+ }
+ });
}
}
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml
index f1ff9c5ea..56a049d46 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml
+++ b/src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml
@@ -60,9 +60,7 @@
-