using Ryujinx.Profiler; using System.Diagnostics; using System.Timers; namespace Ryujinx.HLE { public class PerformanceStatistics { private const double FrameRateWeight = 0.5; private const int FrameTypeSystem = 0; private const int FrameTypeGame = 1; private double[] _averageFrameRate; private double[] _accumulatedFrameTime; private double[] _previousFrameTime; private long[] _framesRendered; private object[] _frameLock; private double _ticksToSeconds; private Stopwatch _executionTime; private Timer _resetTimer; public PerformanceStatistics() { _averageFrameRate = new double[2]; _accumulatedFrameTime = new double[2]; _previousFrameTime = new double[2]; _framesRendered = new long[2]; _frameLock = new object[] { new object(), new object() }; _executionTime = new Stopwatch(); _executionTime.Start(); _resetTimer = new Timer(1000); _resetTimer.Elapsed += ResetTimerElapsed; _resetTimer.AutoReset = true; _resetTimer.Start(); _ticksToSeconds = 1.0 / Stopwatch.Frequency; } private void ResetTimerElapsed(object sender, ElapsedEventArgs e) { CalculateAverageFrameRate(FrameTypeSystem); CalculateAverageFrameRate(FrameTypeGame); } private void CalculateAverageFrameRate(int frameType) { double frameRate = 0; if (_accumulatedFrameTime[frameType] > 0) { frameRate = _framesRendered[frameType] / _accumulatedFrameTime[frameType]; } lock (_frameLock[frameType]) { _averageFrameRate[frameType] = LinearInterpolate(_averageFrameRate[frameType], frameRate); _framesRendered[frameType] = 0; _accumulatedFrameTime[frameType] = 0; } } private double LinearInterpolate(double old, double New) { return old * (1.0 - FrameRateWeight) + New * FrameRateWeight; } public void RecordSystemFrameTime() { RecordFrameTime(FrameTypeSystem); Profile.FlagTime(TimingFlagType.SystemFrame); } public void RecordGameFrameTime() { RecordFrameTime(FrameTypeGame); Profile.FlagTime(TimingFlagType.FrameSwap); } private void RecordFrameTime(int frameType) { double currentFrameTime = _executionTime.ElapsedTicks * _ticksToSeconds; double elapsedFrameTime = currentFrameTime - _previousFrameTime[frameType]; _previousFrameTime[frameType] = currentFrameTime; lock (_frameLock[frameType]) { _accumulatedFrameTime[frameType] += elapsedFrameTime; _framesRendered[frameType]++; } } public double GetSystemFrameRate() { return _averageFrameRate[FrameTypeSystem]; } public double GetGameFrameRate() { return _averageFrameRate[FrameTypeGame]; } } }