From aec8177850885c58d77901139a9d41bdcef13334 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Tue, 13 Oct 2020 21:54:42 +0100 Subject: [PATCH] Replace Host FPS with GPU command queue load ("Fifo %") (#1585) * Replace Host FPS with FIFO% * Change measurement order. Improve calculation. Now at 100% when FIFO is blocking game exectution, rather than "0". * Address feedback (1) * Remove Host FPS * FIFO rather than Fifo * Address Ac_k feedback * Rebase --- Ryujinx.HLE/PerformanceStatistics.cs | 122 ++++++++++++++++++++------- Ryujinx/Ui/GLRenderer.cs | 6 +- Ryujinx/Ui/MainWindow.cs | 4 +- Ryujinx/Ui/MainWindow.glade | 4 +- Ryujinx/Ui/StatusUpdatedEventArgs.cs | 6 +- 5 files changed, 102 insertions(+), 40 deletions(-) diff --git a/Ryujinx.HLE/PerformanceStatistics.cs b/Ryujinx.HLE/PerformanceStatistics.cs index 408e5d72a..be86584aa 100644 --- a/Ryujinx.HLE/PerformanceStatistics.cs +++ b/Ryujinx.HLE/PerformanceStatistics.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using Ryujinx.Common; +using System.Diagnostics; using System.Timers; namespace Ryujinx.HLE @@ -7,36 +8,44 @@ namespace Ryujinx.HLE { private const double FrameRateWeight = 0.5; - private const int FrameTypeSystem = 0; - private const int FrameTypeGame = 1; + private const int FrameTypeGame = 0; + private const int PercentTypeFifo = 0; private double[] _averageFrameRate; private double[] _accumulatedFrameTime; private double[] _previousFrameTime; + private double[] _averagePercent; + private double[] _accumulatedPercent; + private double[] _percentLastEndTime; + private double[] _percentStartTime; + private long[] _framesRendered; + private long[] _percentCount; private object[] _frameLock; + private object[] _percentLock; private double _ticksToSeconds; - private Stopwatch _executionTime; - private Timer _resetTimer; public PerformanceStatistics() { - _averageFrameRate = new double[2]; - _accumulatedFrameTime = new double[2]; - _previousFrameTime = new double[2]; + _averageFrameRate = new double[1]; + _accumulatedFrameTime = new double[1]; + _previousFrameTime = new double[1]; - _framesRendered = new long[2]; + _averagePercent = new double[1]; + _accumulatedPercent = new double[1]; + _percentLastEndTime = new double[1]; + _percentStartTime = new double[1]; - _frameLock = new object[] { new object(), new object() }; + _framesRendered = new long[1]; + _percentCount = new long[1]; - _executionTime = new Stopwatch(); - - _executionTime.Start(); + _frameLock = new object[] { new object() }; + _percentLock = new object[] { new object() }; _resetTimer = new Timer(1000); @@ -46,26 +55,26 @@ namespace Ryujinx.HLE _resetTimer.Start(); - _ticksToSeconds = 1.0 / Stopwatch.Frequency; + _ticksToSeconds = 1.0 / PerformanceCounter.TicksPerSecond; } private void ResetTimerElapsed(object sender, ElapsedEventArgs e) { - CalculateAverageFrameRate(FrameTypeSystem); CalculateAverageFrameRate(FrameTypeGame); + CalculateAveragePercent(PercentTypeFifo); } private void CalculateAverageFrameRate(int frameType) { double frameRate = 0; - if (_accumulatedFrameTime[frameType] > 0) - { - frameRate = _framesRendered[frameType] / _accumulatedFrameTime[frameType]; - } - lock (_frameLock[frameType]) { + if (_accumulatedFrameTime[frameType] > 0) + { + frameRate = _framesRendered[frameType] / _accumulatedFrameTime[frameType]; + } + _averageFrameRate[frameType] = LinearInterpolate(_averageFrameRate[frameType], frameRate); _framesRendered[frameType] = 0; @@ -74,14 +83,30 @@ namespace Ryujinx.HLE } } - private double LinearInterpolate(double old, double New) + private void CalculateAveragePercent(int percentType) { - return old * (1.0 - FrameRateWeight) + New * FrameRateWeight; + // If start time is non-zero, a percent reading is still being measured. + // If there aren't any readings, the default should be 100% if still being measured, or 0% if not. + double percent = (_percentStartTime[percentType] == 0) ? 0 : 100; + + lock (_percentLock[percentType]) + { + if (_percentCount[percentType] > 0) + { + percent = _accumulatedPercent[percentType] / _percentCount[percentType]; + } + + _averagePercent[percentType] = percent; + + _percentCount[percentType] = 0; + + _accumulatedPercent[percentType] = 0; + } } - public void RecordSystemFrameTime() + private double LinearInterpolate(double lhs, double rhs) { - RecordFrameTime(FrameTypeSystem); + return lhs * (1.0 - FrameRateWeight) + rhs * FrameRateWeight; } public void RecordGameFrameTime() @@ -89,9 +114,46 @@ namespace Ryujinx.HLE RecordFrameTime(FrameTypeGame); } + public void RecordFifoStart() + { + StartPercentTime(PercentTypeFifo); + } + + public void RecordFifoEnd() + { + EndPercentTime(PercentTypeFifo); + } + + private void StartPercentTime(int percentType) + { + double currentTime = PerformanceCounter.ElapsedTicks * _ticksToSeconds; + + _percentStartTime[percentType] = currentTime; + } + + private void EndPercentTime(int percentType) + { + double currentTime = PerformanceCounter.ElapsedTicks * _ticksToSeconds; + + double elapsedTime = currentTime - _percentLastEndTime[percentType]; + double elapsedActiveTime = currentTime - _percentStartTime[percentType]; + + double percentActive = (elapsedActiveTime / elapsedTime) * 100; + + lock (_percentLock[percentType]) + { + _accumulatedPercent[percentType] += percentActive; + + _percentCount[percentType]++; + } + + _percentLastEndTime[percentType] = currentTime; + _percentStartTime[percentType] = 0; + } + private void RecordFrameTime(int frameType) { - double currentFrameTime = _executionTime.ElapsedTicks * _ticksToSeconds; + double currentFrameTime = PerformanceCounter.ElapsedTicks * _ticksToSeconds; double elapsedFrameTime = currentFrameTime - _previousFrameTime[frameType]; @@ -105,14 +167,14 @@ namespace Ryujinx.HLE } } - public double GetSystemFrameRate() - { - return _averageFrameRate[FrameTypeSystem]; - } - public double GetGameFrameRate() { return _averageFrameRate[FrameTypeGame]; } + + public double GetFifoPercent() + { + return _averagePercent[PercentTypeFifo]; + } } } diff --git a/Ryujinx/Ui/GLRenderer.cs b/Ryujinx/Ui/GLRenderer.cs index d8fc3e152..edf37bb9b 100644 --- a/Ryujinx/Ui/GLRenderer.cs +++ b/Ryujinx/Ui/GLRenderer.cs @@ -339,7 +339,9 @@ namespace Ryujinx.Ui if (_device.WaitFifo()) { + _device.Statistics.RecordFifoStart(); _device.ProcessFrame(); + _device.Statistics.RecordFifoEnd(); } string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? "Docked" : "Handheld"; @@ -353,13 +355,11 @@ namespace Ryujinx.Ui { _device.PresentFrame(SwapBuffers); - _device.Statistics.RecordSystemFrameTime(); - StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs( _device.EnableDeviceVsync, dockedMode, - $"Host: {_device.Statistics.GetSystemFrameRate():00.00} FPS", $"Game: {_device.Statistics.GetGameFrameRate():00.00} FPS", + $"FIFO: {_device.Statistics.GetFifoPercent():0.00} %", $"GPU: {_renderer.GpuVendor}")); _ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame); diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index f6c88a798..10042143c 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -59,7 +59,7 @@ namespace Ryujinx.Ui [GUI] CheckMenuItem _favToggle; [GUI] MenuItem _firmwareInstallDirectory; [GUI] MenuItem _firmwareInstallFile; - [GUI] Label _hostStatus; + [GUI] Label _fifoStatus; [GUI] CheckMenuItem _iconToggle; [GUI] CheckMenuItem _developerToggle; [GUI] CheckMenuItem _appToggle; @@ -792,8 +792,8 @@ namespace Ryujinx.Ui { Application.Invoke(delegate { - _hostStatus.Text = args.HostStatus; _gameStatus.Text = args.GameStatus; + _fifoStatus.Text = args.FifoStatus; _gpuName.Text = args.GpuName; _dockedMode.Text = args.DockedMode; diff --git a/Ryujinx/Ui/MainWindow.glade b/Ryujinx/Ui/MainWindow.glade index 26a7d75ad..87946e20b 100644 --- a/Ryujinx/Ui/MainWindow.glade +++ b/Ryujinx/Ui/MainWindow.glade @@ -521,7 +521,7 @@ - + True False start @@ -546,7 +546,7 @@ - + True False start diff --git a/Ryujinx/Ui/StatusUpdatedEventArgs.cs b/Ryujinx/Ui/StatusUpdatedEventArgs.cs index 8c59f086d..4b1941575 100644 --- a/Ryujinx/Ui/StatusUpdatedEventArgs.cs +++ b/Ryujinx/Ui/StatusUpdatedEventArgs.cs @@ -6,16 +6,16 @@ namespace Ryujinx.Ui { public bool VSyncEnabled; public string DockedMode; - public string HostStatus; public string GameStatus; + public string FifoStatus; public string GpuName; - public StatusUpdatedEventArgs(bool vSyncEnabled, string dockedMode, string hostStatus, string gameStatus, string gpuName) + public StatusUpdatedEventArgs(bool vSyncEnabled, string dockedMode, string gameStatus, string fifoStatus, string gpuName) { VSyncEnabled = vSyncEnabled; DockedMode = dockedMode; - HostStatus = hostStatus; GameStatus = gameStatus; + FifoStatus = fifoStatus; GpuName = gpuName; } }