From 58e447d8d01d5eb915ba58a8735e4dfffb942b77 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Mon, 13 Nov 2023 18:12:05 +0000 Subject: [PATCH] Change FPS counter behaviour. Calculate a rolling average of FPS over the last second. This allows the FPS counter to be updated every frame - and in particular means it can display a rough figure immediately rather than needing to wait one second to collect information at the start of a game. --- .../Widgets/Logic/PerfDebugLogic.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/OpenRA.Mods.Common/Widgets/Logic/PerfDebugLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/PerfDebugLogic.cs index ab6f44c012..f6e76719fb 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/PerfDebugLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/PerfDebugLogic.cs @@ -9,6 +9,8 @@ */ #endregion +using System; +using System.Collections.Generic; using System.Diagnostics; using OpenRA.Graphics; using OpenRA.Support; @@ -28,22 +30,22 @@ namespace OpenRA.Mods.Common.Widgets.Logic perfText.IsVisible = () => Game.Settings.Debug.PerfText; var fpsTimer = Stopwatch.StartNew(); - var fpsReferenceFrame = Game.RenderFrame; - var fps = 0; + var frameTimings = new List<(int Frame, TimeSpan Time)>(32) { (Game.RenderFrame, TimeSpan.Zero) }; perfText.GetText = () => { - var elapsed = fpsTimer.ElapsedMilliseconds; - if (elapsed > 1000) - { - // Round to closest integer - fps = (int)(1000.0f * (Game.RenderFrame - fpsReferenceFrame) / fpsTimer.ElapsedMilliseconds + 0.5f); - fpsTimer.Restart(); - fpsReferenceFrame = Game.RenderFrame; - } + // Calculate FPS as a rolling average over the last ~1 second of frames. + frameTimings.Add((Game.RenderFrame, fpsTimer.Elapsed)); + var cutoffTime = frameTimings[^1].Time - TimeSpan.FromSeconds(1); + var firstIndexPastCutoff = frameTimings.FindIndex(ft => ft.Time >= cutoffTime); + if (frameTimings.Count - firstIndexPastCutoff >= 2) // Keep at least 2 items for comparing. + frameTimings.RemoveRange(0, firstIndexPastCutoff); + var (oldestFrame, oldestTime) = frameTimings[0]; + var (newestFrame, newestTime) = frameTimings[^1]; + var fps = (newestFrame - oldestFrame) / (newestTime - oldestTime).TotalSeconds; var wfbSize = Game.Renderer.WorldFrameBufferSize; var viewportSize = worldRenderer.Viewport.Rectangle.Size; - return $"FPS: {fps}\nTick {Game.LocalTick} @ {PerfHistory.Items["tick_time"].Average(Game.Settings.Debug.Samples):F1} ms\n" + + return $"FPS: {fps:0}\nTick {Game.LocalTick} @ {PerfHistory.Items["tick_time"].Average(Game.Settings.Debug.Samples):F1} ms\n" + $"Render {Game.RenderFrame} @ {PerfHistory.Items["render"].Average(Game.Settings.Debug.Samples):F1} ms\n" + $"Batches: {PerfHistory.Items["batches"].LastValue}\n" + $"Viewport Size: {viewportSize.Width} x {viewportSize.Height} / {Game.Renderer.WorldDownscaleFactor}\n" +