Salieri: shader cache (#1701)

Here come Salieri, my implementation of a disk shader cache!

"I'm sure you know why I named it that."
"It doesn't really mean anything."

This implementation collects shaders at runtime and cache them to be later compiled when starting a game.
This commit is contained in:
Mary 2020-11-13 00:15:34 +01:00 committed by GitHub
parent 7166e82c3c
commit 48f6570557
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 3589 additions and 396 deletions

View file

@ -21,6 +21,7 @@
"enable_discord_integration": true,
"check_updates_on_start": true,
"enable_vsync": true,
"enable_shader_cache": true,
"enable_multicore_scheduling": true,
"enable_ptc": false,
"enable_fs_integrity_checks": true,

View file

@ -199,19 +199,6 @@ namespace Ryujinx.Ui
Gtk.Application.Invoke(delegate
{
parent.Present();
string titleNameSection = string.IsNullOrWhiteSpace(_device.Application.TitleName) ? string.Empty
: $" - {_device.Application.TitleName}";
string titleVersionSection = string.IsNullOrWhiteSpace(_device.Application.DisplayVersion) ? string.Empty
: $" v{_device.Application.DisplayVersion}";
string titleIdSection = string.IsNullOrWhiteSpace(_device.Application.TitleIdText) ? string.Empty
: $" ({_device.Application.TitleIdText.ToUpper()})";
string titleArchSection = _device.Application.TitleIs64Bit ? " (64-bit)" : " (32-bit)";
parent.Title = $"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
});
Thread renderLoopThread = new Thread(Render)
@ -313,7 +300,7 @@ namespace Ryujinx.Ui
{
if (!(_device.Gpu.Renderer is Renderer))
{
throw new NotSupportedException($"GPU renderer must be an OpenGL renderer when using GLRenderer!");
throw new NotSupportedException($"GPU renderer must be an OpenGL renderer when using {typeof(Renderer).Name}!");
}
_renderer = (Renderer)_device.Gpu.Renderer;
@ -327,7 +314,7 @@ namespace Ryujinx.Ui
parent.Present();
GraphicsContext.MakeCurrent(WindowInfo);
_renderer.Initialize(_glLogLevel);
_device.Gpu.Initialize(_glLogLevel);
// Make sure the first frame is not transparent.
GL.ClearColor(OpenTK.Color.Black);

View file

@ -111,22 +111,34 @@ namespace Ryujinx.Ui
MenuItem managePtcMenu = new MenuItem("Cache Management");
MenuItem purgePtcCache = new MenuItem("Purge PPTC cache")
MenuItem purgePtcCache = new MenuItem("Purge PPTC Cache")
{
TooltipText = "Delete the Application's PPTC cache."
};
MenuItem openPtcDir = new MenuItem("Open PPTC directory")
MenuItem purgeShaderCache = new MenuItem("Purge Shader Cache")
{
TooltipText = "Open the directory which contains Application's PPTC cache."
TooltipText = "Delete the Application's shader cache."
};
MenuItem openPtcDir = new MenuItem("Open PPTC Directory")
{
TooltipText = "Open the directory which contains the Application's PPTC cache."
};
MenuItem openShaderCacheDir = new MenuItem("Open Shader Cache Directory")
{
TooltipText = "Open the directory which contains the Application's shader cache."
};
Menu manageSubMenu = new Menu();
Menu managePtcSubMenu = new Menu();
manageSubMenu.Append(purgePtcCache);
manageSubMenu.Append(purgeShaderCache);
manageSubMenu.Append(openPtcDir);
manageSubMenu.Append(openShaderCacheDir);
managePtcSubMenu.Append(purgePtcCache);
managePtcSubMenu.Append(openPtcDir);
managePtcMenu.Submenu = managePtcSubMenu;
managePtcMenu.Submenu = manageSubMenu;
openSaveUserDir.Activated += OpenSaveUserDir_Clicked;
openSaveDeviceDir.Activated += OpenSaveDeviceDir_Clicked;
@ -138,8 +150,10 @@ namespace Ryujinx.Ui
extractExeFs.Activated += ExtractExeFs_Clicked;
extractLogo.Activated += ExtractLogo_Clicked;
purgePtcCache.Activated += PurgePtcCache_Clicked;
purgeShaderCache.Activated += PurgeShaderCache_Clicked;
openPtcDir.Activated += OpenPtcDir_Clicked;
openShaderCacheDir.Activated += OpenShaderCacheDir_Clicked;
this.Add(openSaveUserDir);
this.Add(openSaveDeviceDir);
this.Add(openSaveBcatDir);
@ -640,6 +654,24 @@ namespace Ryujinx.Ui
Verb = "open"
});
}
private void OpenShaderCacheDir_Clicked(object sender, EventArgs args)
{
string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
string shaderCacheDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "shader");
if (!Directory.Exists(shaderCacheDir))
{
Directory.CreateDirectory(shaderCacheDir);
}
Process.Start(new ProcessStartInfo
{
FileName = shaderCacheDir,
UseShellExecute = true,
Verb = "open"
});
}
private void PurgePtcCache_Clicked(object sender, EventArgs args)
{
@ -678,5 +710,41 @@ namespace Ryujinx.Ui
warningDialog.Dispose();
}
private void PurgeShaderCache_Clicked(object sender, EventArgs args)
{
string[] tableEntry = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n");
string titleId = tableEntry[1].ToLower();
DirectoryInfo shaderCacheDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "shader"));
MessageDialog warningDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
{
Title = "Ryujinx - Warning",
Text = $"You are about to delete the shader cache for '{tableEntry[0]}'. Are you sure you want to proceed?",
WindowPosition = WindowPosition.Center
};
List<DirectoryInfo> cacheDirectory = new List<DirectoryInfo>();
if (shaderCacheDir.Exists) { cacheDirectory.AddRange(shaderCacheDir.EnumerateDirectories("*")); }
if (cacheDirectory.Count > 0 && warningDialog.Run() == (int)ResponseType.Yes)
{
foreach (DirectoryInfo directory in cacheDirectory)
{
try
{
directory.Delete(true);
}
catch (Exception e)
{
Logger.Error?.Print(LogClass.Application, $"Error purging shader cache {directory.Name}: {e}");
}
}
}
warningDialog.Dispose();
}
}
}

View file

@ -39,6 +39,7 @@ namespace Ryujinx.Ui
public static GlRenderer GlWidget => _glWidget;
private static AutoResetEvent _deviceExitStatus = new AutoResetEvent(false);
private static AutoResetEvent _widgetInitEvent = new AutoResetEvent(false);
private static ListStore _tableStore;
@ -433,6 +434,30 @@ namespace Ryujinx.Ui
}
}
_widgetInitEvent.Reset();
#if MACOS_BUILD
CreateGameWindow(device);
#else
Thread windowThread = new Thread(() =>
{
CreateGameWindow(device);
})
{
Name = "GUI.WindowThread"
};
windowThread.Start();
#endif
_widgetInitEvent.WaitOne();
// Make sure the widget get initialized by forcing an update of GTK
while (Application.EventsPending())
{
Application.RunIteration();
}
Logger.Notice.Print(LogClass.Application, $"Using Firmware Version: {firmwareVersion?.VersionString}");
if (Directory.Exists(path))
@ -493,25 +518,24 @@ namespace Ryujinx.Ui
return;
}
string titleNameSection = string.IsNullOrWhiteSpace(device.Application.TitleName) ? string.Empty
: $" - {device.Application.TitleName}";
string titleVersionSection = string.IsNullOrWhiteSpace(device.Application.DisplayVersion) ? string.Empty
: $" v{device.Application.DisplayVersion}";
string titleIdSection = string.IsNullOrWhiteSpace(device.Application.TitleIdText) ? string.Empty
: $" ({device.Application.TitleIdText.ToUpper()})";
string titleArchSection = device.Application.TitleIs64Bit ? " (64-bit)" : " (32-bit)";
Title = $"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
_emulationContext = device;
_gamePath = path;
_deviceExitStatus.Reset();
#if MACOS_BUILD
CreateGameWindow(device);
#else
Thread windowThread = new Thread(() =>
{
CreateGameWindow(device);
})
{
Name = "GUI.WindowThread"
};
windowThread.Start();
#endif
_gameLoaded = true;
_stopEmulation.Sensitive = true;
@ -534,7 +558,7 @@ namespace Ryujinx.Ui
_windowsMultimediaTimerResolution = new WindowsMultimediaTimerResolution(1);
}
_glWidget = new GlRenderer(_emulationContext, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
_glWidget = new GlRenderer(device, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
Application.Invoke(delegate
{
@ -551,6 +575,8 @@ namespace Ryujinx.Ui
}
});
_widgetInitEvent.Set();
_glWidget.WaitEvent.WaitOne();
_glWidget.Start();
@ -658,6 +684,7 @@ namespace Ryujinx.Ui
Graphics.Gpu.GraphicsConfig.ResScale = (resScale == -1) ? resScaleCustom : resScale;
Graphics.Gpu.GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
Graphics.Gpu.GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
Graphics.Gpu.GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
}
public static void SaveConfig()

View file

@ -42,6 +42,7 @@ namespace Ryujinx.Ui
[GUI] CheckButton _discordToggle;
[GUI] CheckButton _checkUpdatesToggle;
[GUI] CheckButton _vSyncToggle;
[GUI] CheckButton _shaderCacheToggle;
[GUI] CheckButton _multiSchedToggle;
[GUI] CheckButton _ptcToggle;
[GUI] CheckButton _fsicToggle;
@ -182,6 +183,11 @@ namespace Ryujinx.Ui
_vSyncToggle.Click();
}
if (ConfigurationState.Instance.Graphics.EnableShaderCache)
{
_shaderCacheToggle.Click();
}
if (ConfigurationState.Instance.System.EnableMulticoreScheduling)
{
_multiSchedToggle.Click();
@ -528,6 +534,7 @@ namespace Ryujinx.Ui
ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active;
ConfigurationState.Instance.CheckUpdatesOnStart.Value = _checkUpdatesToggle.Active;
ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active;
ConfigurationState.Instance.Graphics.EnableShaderCache.Value = _shaderCacheToggle.Active;
ConfigurationState.Instance.System.EnableMulticoreScheduling.Value = _multiSchedToggle.Active;
ConfigurationState.Instance.System.EnablePtc.Value = _ptcToggle.Active;
ConfigurationState.Instance.System.EnableFsIntegrityChecks.Value = _fsicToggle.Active;

View file

@ -1701,6 +1701,24 @@
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkCheckButton" id="_shaderCacheToggle">
<property name="label" translatable="yes">Enable Shader Cache</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Enables or disables Shader Cache</property>
<property name="halign">start</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
@ -1762,7 +1780,7 @@
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">0</property>
<property name="position">1</property>
</packing>
</child>
<child>
@ -1817,7 +1835,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="position">2</property>
</packing>
</child>
</object>