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:
mageven 2021-03-03 06:09:36 +05:30 committed by GitHub
parent 31fca432a7
commit ca5d8e58dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 148 additions and 19 deletions

View file

@ -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");
} }

View file

@ -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>

View file

@ -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();
} }
} }

View file

@ -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)

View file

@ -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">