From a01a06cd3fa9d24cd9ee603f65560b03e4fb2ca4 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Thu, 24 Oct 2024 14:14:12 -0500 Subject: [PATCH] 2 unmerged PRs from original Ryujinx: Implement shader compile counter (currently not translated, will change, need to pull changes.) Remove event logic in favor of a single init function. Thanks @MutantAura --- src/Ryujinx.Common/ReactiveObject.cs | 10 ++-- src/Ryujinx.Graphics.GAL/IRenderer.cs | 2 + .../Multithreading/ThreadedRenderer.cs | 4 ++ src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs | 4 ++ src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs | 4 ++ src/Ryujinx/AppHost.cs | 47 ++++++++++++++----- .../UI/Models/StatusUpdatedEventArgs.cs | 5 +- .../UI/ViewModels/MainWindowViewModel.cs | 41 ++++++++++------ .../UI/ViewModels/ModManagerViewModel.cs | 7 +-- .../UI/Views/Main/MainStatusBarView.axaml | 13 +++++ 10 files changed, 101 insertions(+), 36 deletions(-) diff --git a/src/Ryujinx.Common/ReactiveObject.cs b/src/Ryujinx.Common/ReactiveObject.cs index b25f778fb..4f27af546 100644 --- a/src/Ryujinx.Common/ReactiveObject.cs +++ b/src/Ryujinx.Common/ReactiveObject.cs @@ -41,10 +41,12 @@ namespace Ryujinx.Common } } - public static implicit operator T(ReactiveObject obj) - { - return obj.Value; - } + public static implicit operator T(ReactiveObject obj) => obj.Value; + } + + public static class ReactiveObjectHelper + { + public static void Toggle(this ReactiveObject rBoolean) => rBoolean.Value = !rBoolean.Value; } public class ReactiveEventArgs(T oldValue, T newValue) diff --git a/src/Ryujinx.Graphics.GAL/IRenderer.cs b/src/Ryujinx.Graphics.GAL/IRenderer.cs index 85d0bd729..9b5e2cc42 100644 --- a/src/Ryujinx.Graphics.GAL/IRenderer.cs +++ b/src/Ryujinx.Graphics.GAL/IRenderer.cs @@ -13,6 +13,8 @@ namespace Ryujinx.Graphics.GAL IPipeline Pipeline { get; } IWindow Window { get; } + + uint ProgramCount { get; } void BackgroundContextAction(Action action, bool alwaysBackground = false); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs index cc3d2e5c1..0bd3dc592 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs @@ -55,6 +55,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading private int _refProducerPtr; private int _refConsumerPtr; + public uint ProgramCount { get; set; } = 0; + private Action _interruptAction; private readonly object _interruptLock = new(); @@ -307,6 +309,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading Programs.Add(request); + ProgramCount++; + New().Set(Ref((IProgramRequest)request)); QueueCommand(); diff --git a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs index 377cad386..2deee045c 100644 --- a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs +++ b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs @@ -29,6 +29,8 @@ namespace Ryujinx.Graphics.OpenGL private readonly Sync _sync; + public uint ProgramCount { get; set; } = 0; + public event EventHandler ScreenCaptured; internal PersistentBuffers PersistentBuffers { get; } @@ -94,6 +96,8 @@ namespace Ryujinx.Graphics.OpenGL public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info) { + ProgramCount++; + return new Program(shaders, info.FragmentOutputMap); } diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 0faaec82a..a40b20f14 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -27,6 +27,8 @@ namespace Ryujinx.Graphics.Vulkan private bool _initialized; + public uint ProgramCount { get; set; } = 0; + internal FormatCapabilities FormatCapabilities { get; private set; } internal HardwareCapabilities Capabilities; @@ -544,6 +546,8 @@ namespace Ryujinx.Graphics.Vulkan public IProgram CreateProgram(ShaderSource[] sources, ShaderInfo info) { + ProgramCount++; + bool isCompute = sources.Length == 1 && sources[0].Stage == ShaderStage.Compute; if (info.State.HasValue || isCompute) diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index eafcbb13a..242b4b37d 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -103,6 +103,10 @@ namespace Ryujinx.Ava private CursorStates _cursorState = !ConfigurationState.Instance.Hid.EnableMouse.Value ? CursorStates.CursorIsVisible : CursorStates.CursorIsHidden; + private DateTime _lastShaderReset; + private uint _displayCount; + private uint _previousCount = 0; + private bool _isStopped; private bool _isActive; private bool _renderingStarted; @@ -120,7 +124,6 @@ namespace Ryujinx.Ava private readonly object _lockObject = new(); public event EventHandler AppExit; - public event EventHandler StatusInitEvent; public event EventHandler StatusUpdatedEvent; public VirtualFileSystem VirtualFileSystem { get; } @@ -511,8 +514,7 @@ namespace Ryujinx.Ava } _isStopped = true; - _isActive = false; - DiscordIntegrationModule.SwitchToMainState(); + Stop(); } public void DisposeContext() @@ -1043,14 +1045,14 @@ namespace Ryujinx.Ava public void InitStatus() { - StatusInitEvent?.Invoke(this, new StatusInitEventArgs( - ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch - { - GraphicsBackend.Vulkan => "Vulkan", - GraphicsBackend.OpenGl => "OpenGL", - _ => throw new NotImplementedException() - }, - $"GPU: {_renderer.GetHardwareInfo().GpuDriver}")); + _viewModel.BackendText = ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch + { + GraphicsBackend.Vulkan => "Vulkan", + GraphicsBackend.OpenGl => "OpenGL", + _ => throw new NotImplementedException() + }; + + _viewModel.GpuNameText = $"GPU: {_renderer.GetHardwareInfo().GpuDriver}"; } public void UpdateStatus() @@ -1058,6 +1060,8 @@ namespace Ryujinx.Ava // Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued. string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld]; + UpdateShaderCount(); + if (GraphicsConfig.ResScale != 1) { dockedMode += $" ({GraphicsConfig.ResScale}x)"; @@ -1069,7 +1073,8 @@ namespace Ryujinx.Ava dockedMode, ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), LocaleManager.Instance[LocaleKeys.Game] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", - $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %")); + $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %", + _displayCount)); } public async Task ShowExitPrompt() @@ -1095,6 +1100,24 @@ namespace Ryujinx.Ava } } + private void UpdateShaderCount() + { + // If there is a mismatch between total program compile and previous count + // this means new shaders have been compiled and should be displayed. + if (_renderer.ProgramCount != _previousCount) + { + _displayCount += _renderer.ProgramCount - _previousCount; + _lastShaderReset = DateTime.Now; + _previousCount = _renderer.ProgramCount; + } + // Check if 5s has passed since any new shaders were compiled. + // If yes, reset the counter. + else if (_lastShaderReset.AddSeconds(5) <= DateTime.Now) + { + _displayCount = 0; + } + } + private bool UpdateFrame() { if (!_isActive) diff --git a/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs b/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs index ee5648faf..f12cf0aa6 100644 --- a/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs +++ b/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs @@ -10,8 +10,10 @@ namespace Ryujinx.Ava.UI.Models public string DockedMode { get; } public string FifoStatus { get; } public string GameStatus { get; } + + public uint ShaderCount { get; } - public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus) + public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, uint shaderCount) { VSyncEnabled = vSyncEnabled; VolumeStatus = volumeStatus; @@ -19,6 +21,7 @@ namespace Ryujinx.Ava.UI.Models AspectRatio = aspectRatio; GameStatus = gameStatus; FifoStatus = fifoStatus; + ShaderCount = shaderCount; } } } diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index f201bba6f..e31b5f13a 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -8,6 +8,7 @@ using Avalonia.Threading; using DynamicData; using DynamicData.Binding; using FluentAvalonia.UI.Controls; +using Gommon; using LibHac.Common; using Ryujinx.Ava.Common; using Ryujinx.Ava.Common.Locale; @@ -64,7 +65,9 @@ namespace Ryujinx.Ava.UI.ViewModels private string _gameStatusText; private string _volumeStatusText; private string _gpuStatusText; + private string _shaderCountText; private bool _isAmiiboRequested; + private bool _showRightmostSeparator; private bool _isGameRunning; private bool _isFullScreen; private int _progressMaximum; @@ -256,6 +259,17 @@ namespace Ryujinx.Ava.UI.ViewModels public bool ShowFirmwareStatus => !ShowLoadProgress; + public bool ShowRightmostSeparator + { + get => _showRightmostSeparator; + set + { + _showRightmostSeparator = value; + + OnPropertyChanged(); + } + } + public bool IsGameRunning { get => _isGameRunning; @@ -506,6 +520,16 @@ namespace Ryujinx.Ava.UI.ViewModels OnPropertyChanged(); } } + + public string ShaderCountText + { + get => _shaderCountText; + set + { + _shaderCountText = value; + OnPropertyChanged(); + } + } public string BackendText { @@ -1187,8 +1211,7 @@ namespace Ryujinx.Ava.UI.ViewModels private void InitializeGame() { RendererHostControl.WindowCreated += RendererHost_Created; - - AppHost.StatusInitEvent += Init_StatusBar; + AppHost.StatusUpdatedEvent += Update_StatusBar; AppHost.AppExit += AppHost_AppExit; @@ -1215,18 +1238,6 @@ namespace Ryujinx.Ava.UI.ViewModels } } - private void Init_StatusBar(object sender, StatusInitEventArgs args) - { - if (ShowMenuAndStatusBar && !ShowLoadProgress) - { - Dispatcher.UIThread.InvokeAsync(() => - { - GpuNameText = args.GpuName; - BackendText = args.GpuBackend; - }); - } - } - private void Update_StatusBar(object sender, StatusUpdatedEventArgs args) { if (ShowMenuAndStatusBar && !ShowLoadProgress) @@ -1249,6 +1260,8 @@ namespace Ryujinx.Ava.UI.ViewModels GameStatusText = args.GameStatus; VolumeStatusText = args.VolumeStatus; FifoStatusText = args.FifoStatus; + ShaderCountText = args.ShaderCount > 0 ? $"Compiling shaders: {args.ShaderCount}" : string.Empty; + ShowRightmostSeparator = !ShaderCountText.IsNullOrEmpty(); ShowStatusSeparator = true; }); diff --git a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs index 8321bf894..ddb6ab01c 100644 --- a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs @@ -4,6 +4,7 @@ using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Platform.Storage; using Avalonia.Threading; using DynamicData; +using Gommon; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Models; @@ -313,11 +314,7 @@ namespace Ryujinx.Ava.UI.ViewModels public void DeleteAll() { - foreach (var mod in Mods) - { - Delete(mod); - } - + Mods.ForEach(Delete); Mods.Clear(); OnPropertyChanged(nameof(ModCount)); Sort(); diff --git a/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml b/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml index b1db08b2a..77b9f7b6e 100644 --- a/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml @@ -261,6 +261,19 @@ IsVisible="{Binding !ShowLoadProgress}" Text="{Binding GpuNameText}" TextAlignment="Start" /> + +