forked from Mirror/Ryujinx
Add progress reporting to PTC and Shader Cache (#2057)
* UI changes * Add progress reporting to PTC & ShaderCache * Account for null events and expand docs Co-authored-by: Joshi234 <46032261+Joshi234@users.noreply.github.com>
This commit is contained in:
parent
31fca432a7
commit
ca5d8e58dd
5 changed files with 148 additions and 19 deletions
|
@ -70,6 +70,10 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
internal static PtcState State { get; private set; }
|
internal static PtcState State { get; private set; }
|
||||||
|
|
||||||
|
// Progress update events
|
||||||
|
public static event Action<bool> PtcTranslationStateChanged;
|
||||||
|
public static event Action<int, int> PtcTranslationProgressChanged;
|
||||||
|
|
||||||
static Ptc()
|
static Ptc()
|
||||||
{
|
{
|
||||||
InitializeMemoryStreams();
|
InitializeMemoryStreams();
|
||||||
|
@ -772,6 +776,8 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
ThreadPool.QueueUserWorkItem(TranslationLogger, profiledFuncsToTranslate.Count);
|
ThreadPool.QueueUserWorkItem(TranslationLogger, profiledFuncsToTranslate.Count);
|
||||||
|
|
||||||
|
PtcTranslationStateChanged?.Invoke(true);
|
||||||
|
|
||||||
void TranslateFuncs()
|
void TranslateFuncs()
|
||||||
{
|
{
|
||||||
while (profiledFuncsToTranslate.TryDequeue(out var item))
|
while (profiledFuncsToTranslate.TryDequeue(out var item))
|
||||||
|
@ -820,6 +826,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
threads.Clear();
|
threads.Clear();
|
||||||
|
|
||||||
_loggerEvent.Set();
|
_loggerEvent.Set();
|
||||||
|
PtcTranslationStateChanged?.Invoke(false);
|
||||||
|
|
||||||
PtcJumpTable.Initialize(jumpTable);
|
PtcJumpTable.Initialize(jumpTable);
|
||||||
|
|
||||||
|
@ -833,15 +840,15 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
private static void TranslationLogger(object state)
|
private static void TranslationLogger(object state)
|
||||||
{
|
{
|
||||||
const int refreshRate = 1; // Seconds.
|
const int refreshRate = 100; // ms
|
||||||
|
|
||||||
int profiledFuncsToTranslateCount = (int)state;
|
int profiledFuncsToTranslateCount = (int)state;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {profiledFuncsToTranslateCount} functions translated");
|
PtcTranslationProgressChanged?.Invoke(_translateCount, profiledFuncsToTranslateCount);
|
||||||
}
|
}
|
||||||
while (!_loggerEvent.WaitOne(refreshRate * 1000));
|
while (!_loggerEvent.WaitOne(refreshRate));
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {profiledFuncsToTranslateCount} functions translated");
|
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {profiledFuncsToTranslateCount} functions translated");
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,26 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal Capabilities Capabilities => _caps.Value;
|
internal Capabilities Capabilities => _caps.Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signaled when shader cache begins and ends loading.
|
||||||
|
/// Signals true when loading has started, false when ended.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<bool> ShaderCacheStateChanged
|
||||||
|
{
|
||||||
|
add => Methods.ShaderCache.ShaderCacheStateChanged += value;
|
||||||
|
remove => Methods.ShaderCache.ShaderCacheStateChanged -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signaled while shader cache is loading to indicate current progress.
|
||||||
|
/// Provides current and total number of shaders loaded.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<int, int> ShaderCacheProgressChanged
|
||||||
|
{
|
||||||
|
add => Methods.ShaderCache.ShaderCacheProgressChanged += value;
|
||||||
|
remove => Methods.ShaderCache.ShaderCacheProgressChanged -= value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the GPU emulation context.
|
/// Creates a new instance of the GPU emulation context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -9,6 +9,7 @@ using Ryujinx.Graphics.Shader.Translation;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Shader
|
namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
{
|
{
|
||||||
|
@ -36,6 +37,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const ulong ShaderCodeGenVersion = 1961;
|
private const ulong ShaderCodeGenVersion = 1961;
|
||||||
|
|
||||||
|
// Progress reporting helpers
|
||||||
|
private int _shaderCount;
|
||||||
|
private readonly AutoResetEvent _progressReportEvent;
|
||||||
|
public event Action<bool> ShaderCacheStateChanged;
|
||||||
|
public event Action<int, int> ShaderCacheProgressChanged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the shader cache.
|
/// Creates a new instance of the shader cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -50,6 +57,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
_gpPrograms = new Dictionary<ShaderAddresses, List<ShaderBundle>>();
|
_gpPrograms = new Dictionary<ShaderAddresses, List<ShaderBundle>>();
|
||||||
_gpProgramsDiskCache = new Dictionary<Hash128, ShaderBundle>();
|
_gpProgramsDiskCache = new Dictionary<Hash128, ShaderBundle>();
|
||||||
_cpProgramsDiskCache = new Dictionary<Hash128, ShaderBundle>();
|
_cpProgramsDiskCache = new Dictionary<Hash128, ShaderBundle>();
|
||||||
|
|
||||||
|
_progressReportEvent = new AutoResetEvent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -76,12 +85,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
ReadOnlySpan<Hash128> guestProgramList = _cacheManager.GetGuestProgramList();
|
ReadOnlySpan<Hash128> guestProgramList = _cacheManager.GetGuestProgramList();
|
||||||
|
|
||||||
|
_progressReportEvent.Reset();
|
||||||
|
_shaderCount = 0;
|
||||||
|
|
||||||
|
ShaderCacheStateChanged?.Invoke(true);
|
||||||
|
ThreadPool.QueueUserWorkItem(ProgressLogger, guestProgramList.Length);
|
||||||
|
|
||||||
for (int programIndex = 0; programIndex < guestProgramList.Length; programIndex++)
|
for (int programIndex = 0; programIndex < guestProgramList.Length; programIndex++)
|
||||||
{
|
{
|
||||||
Hash128 key = guestProgramList[programIndex];
|
Hash128 key = guestProgramList[programIndex];
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Gpu, $"Compiling shader {key} ({programIndex + 1} / {guestProgramList.Length})");
|
|
||||||
|
|
||||||
byte[] hostProgramBinary = _cacheManager.GetHostProgramByHash(ref key);
|
byte[] hostProgramBinary = _cacheManager.GetHostProgramByHash(ref key);
|
||||||
bool hasHostCache = hostProgramBinary != null;
|
bool hasHostCache = hostProgramBinary != null;
|
||||||
|
|
||||||
|
@ -304,6 +317,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
_gpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shaders));
|
_gpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shaders));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_shaderCount = programIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isReadOnly)
|
if (!isReadOnly)
|
||||||
|
@ -314,10 +329,28 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
_cacheManager.Synchronize();
|
_cacheManager.Synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Gpu, "Shader cache loaded.");
|
_progressReportEvent.Set();
|
||||||
|
ShaderCacheStateChanged?.Invoke(false);
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Gpu, $"Shader cache loaded {_shaderCount} entries.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises ShaderCacheProgressChanged events periodically.
|
||||||
|
/// </summary>
|
||||||
|
private void ProgressLogger(object state)
|
||||||
|
{
|
||||||
|
const int refreshRate = 100; // ms
|
||||||
|
|
||||||
|
int totalCount = (int)state;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ShaderCacheProgressChanged?.Invoke(_shaderCount, totalCount);
|
||||||
|
}
|
||||||
|
while (!_progressReportEvent.WaitOne(refreshRate));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a compute shader from the cache.
|
/// Gets a compute shader from the cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -787,6 +820,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_progressReportEvent?.Dispose();
|
||||||
_cacheManager?.Dispose();
|
_cacheManager?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,10 +92,14 @@ namespace Ryujinx.Ui
|
||||||
[GUI] Label _gpuName;
|
[GUI] Label _gpuName;
|
||||||
[GUI] Label _progressLabel;
|
[GUI] Label _progressLabel;
|
||||||
[GUI] Label _firmwareVersionLabel;
|
[GUI] Label _firmwareVersionLabel;
|
||||||
[GUI] LevelBar _progressBar;
|
[GUI] ProgressBar _progressBar;
|
||||||
[GUI] Box _viewBox;
|
[GUI] Box _viewBox;
|
||||||
[GUI] Label _vSyncStatus;
|
[GUI] Label _vSyncStatus;
|
||||||
[GUI] Box _listStatusBox;
|
[GUI] Box _listStatusBox;
|
||||||
|
[GUI] Label _loadingStatusLabel;
|
||||||
|
[GUI] ProgressBar _loadingStatusBar;
|
||||||
|
|
||||||
|
private string _loadingStatusTitle = "";
|
||||||
|
|
||||||
#pragma warning restore CS0649, IDE0044, CS0169
|
#pragma warning restore CS0649, IDE0044, CS0169
|
||||||
|
|
||||||
|
@ -333,6 +337,48 @@ namespace Ryujinx.Ui
|
||||||
_emulationContext.Initialize();
|
_emulationContext.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetupProgressUiHandlers()
|
||||||
|
{
|
||||||
|
Ptc.PtcTranslationStateChanged -= PtcStatusChanged;
|
||||||
|
Ptc.PtcTranslationStateChanged += PtcStatusChanged;
|
||||||
|
|
||||||
|
Ptc.PtcTranslationProgressChanged -= LoadingProgressChanged;
|
||||||
|
Ptc.PtcTranslationProgressChanged += LoadingProgressChanged;
|
||||||
|
|
||||||
|
_emulationContext.Gpu.ShaderCacheStateChanged -= ShaderCacheStatusChanged;
|
||||||
|
_emulationContext.Gpu.ShaderCacheStateChanged += ShaderCacheStatusChanged;
|
||||||
|
|
||||||
|
_emulationContext.Gpu.ShaderCacheProgressChanged -= LoadingProgressChanged;
|
||||||
|
_emulationContext.Gpu.ShaderCacheProgressChanged += LoadingProgressChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShaderCacheStatusChanged(bool state)
|
||||||
|
{
|
||||||
|
_loadingStatusTitle = "Shaders";
|
||||||
|
Application.Invoke(delegate
|
||||||
|
{
|
||||||
|
_loadingStatusBar.Visible = _loadingStatusLabel.Visible = state;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PtcStatusChanged(bool state)
|
||||||
|
{
|
||||||
|
_loadingStatusTitle = "PTC";
|
||||||
|
Application.Invoke(delegate
|
||||||
|
{
|
||||||
|
_loadingStatusBar.Visible = _loadingStatusLabel.Visible = state;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadingProgressChanged(int value, int total)
|
||||||
|
{
|
||||||
|
Application.Invoke(delegate
|
||||||
|
{
|
||||||
|
_loadingStatusBar.Fraction = (double)value / total;
|
||||||
|
_loadingStatusLabel.Text = $"{_loadingStatusTitle} : {value}/{total}";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateGameTable()
|
public void UpdateGameTable()
|
||||||
{
|
{
|
||||||
if (_updatingGameTable || _gameLoaded)
|
if (_updatingGameTable || _gameLoaded)
|
||||||
|
@ -531,6 +577,8 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
_deviceExitStatus.Reset();
|
_deviceExitStatus.Reset();
|
||||||
|
|
||||||
|
SetupProgressUiHandlers();
|
||||||
|
|
||||||
Translator.IsReadyForTranslation.Reset();
|
Translator.IsReadyForTranslation.Reset();
|
||||||
#if MACOS_BUILD
|
#if MACOS_BUILD
|
||||||
CreateGameWindow();
|
CreateGameWindow();
|
||||||
|
@ -775,7 +823,7 @@ namespace Ryujinx.Ui
|
||||||
barValue = (float)args.NumAppsLoaded / args.NumAppsFound;
|
barValue = (float)args.NumAppsLoaded / args.NumAppsFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
_progressBar.Value = barValue;
|
_progressBar.Fraction = barValue;
|
||||||
|
|
||||||
// Reset the vertical scrollbar to the top when titles finish loading
|
// Reset the vertical scrollbar to the top when titles finish loading
|
||||||
if (args.NumAppsLoaded == args.NumAppsFound)
|
if (args.NumAppsLoaded == args.NumAppsFound)
|
||||||
|
|
|
@ -459,13 +459,14 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkLevelBar" id="_progressBar">
|
<object class="GtkProgressBar" id="_progressBar">
|
||||||
<property name="width_request">200</property>
|
<property name="width_request">200</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="halign">start</property>
|
<property name="halign">start</property>
|
||||||
<property name="margin_left">10</property>
|
<property name="margin_left">10</property>
|
||||||
<property name="margin_right">5</property>
|
<property name="margin_right">5</property>
|
||||||
|
<property name="margin_bottom">6</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
|
@ -640,6 +641,7 @@
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="halign">start</property>
|
<property name="halign">start</property>
|
||||||
<property name="margin_left">5</property>
|
<property name="margin_left">5</property>
|
||||||
|
<property name="margin_right">5</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
|
@ -654,16 +656,34 @@
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkSeparator">
|
<object class="GtkLabel" id="_loadingStatusLabel">
|
||||||
<property name="visible">True</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="margin_left">5</property>
|
||||||
</object>
|
<property name="margin_right">5</property>
|
||||||
<packing>
|
<property name="label" translatable="yes">0/0 </property>
|
||||||
<property name="expand">False</property>
|
<property name="visible">False</property>
|
||||||
<property name="fill">True</property>
|
</object>
|
||||||
<property name="position">3</property>
|
<packing>
|
||||||
</packing>
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">11</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkProgressBar" id="_loadingStatusBar">
|
||||||
|
<property name="width_request">200</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_left">5</property>
|
||||||
|
<property name="margin_right">5</property>
|
||||||
|
<property name="margin_bottom">6</property>
|
||||||
|
<property name="visible">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">12</property>
|
||||||
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
|
|
Reference in a new issue