Fix : Uncapped FPS ; Removed : Estimated Input lag

This commit is contained in:
Jahnisse
2026-06-03 16:38:20 +02:00
parent 1385d6a954
commit 08755ce2cd
@@ -4,21 +4,13 @@ using System.Collections.Generic;
namespace OctoCore.UI namespace OctoCore.UI
{ {
/// <summary>
/// Displays FPS, frame time, and estimated input lag.
/// Singleton that persists across scene loads. Safe to place in every scene — duplicates are destroyed automatically.
/// Requires a Canvas Text component assigned in the Inspector.
/// </summary>
public class PerformanceOverlay : MonoBehaviour public class PerformanceOverlay : MonoBehaviour
{ {
#region Constants and Static Fields #region Constants and Static Fields
public static PerformanceOverlay Instance { get; private set; } public static PerformanceOverlay Instance { get; private set; }
private const string GREEN = "<color=#00ff88>"; private const string GREEN = "<color=#00ff88>", YELLOW = "<color=#ffcc00>", RED = "<color=#ff4444>", END = "</color>";
private const string YELLOW = "<color=#ffcc00>";
private const string RED = "<color=#ff4444>";
private const string END = "</color>";
#endregion #endregion
@@ -31,13 +23,9 @@ namespace OctoCore.UI
[Tooltip("Number of frames to average for a smooth reading.")] [Tooltip("Number of frames to average for a smooth reading.")]
[SerializeField] private int _sampleSize = 60; [SerializeField] private int _sampleSize = 60;
[Tooltip("How often (seconds) the display refreshes.")] [Tooltip("How often, in seconds, the display refreshes.")]
[SerializeField] private float _updateInterval = 0.1f; [SerializeField] private float _updateInterval = 0.1f;
[Header("Input Lag Settings")]
[Tooltip("Render pipeline latency in frames. 1 for Built-in/URP, 2 for HDRP.")]
[SerializeField] private int _pipelineLatencyFrames = 1;
[Header("Thresholds")] [Header("Thresholds")]
[SerializeField] private int _goodFps = 60; [SerializeField] private int _goodFps = 60;
[SerializeField] private int _warningFps = 30; [SerializeField] private int _warningFps = 30;
@@ -64,18 +52,31 @@ namespace OctoCore.UI
Instance = this; Instance = this;
DontDestroyOnLoad(gameObject); DontDestroyOnLoad(gameObject);
if (_displayText == null)
_displayText = GetComponent<Text>();
ConfigureText();
}
private void OnValidate()
{
_sampleSize = Mathf.Max(1, _sampleSize);
_updateInterval = Mathf.Max(0.02f, _updateInterval);
} }
private void Update() private void Update()
{ {
float dt = Time.unscaledDeltaTime; float deltaTime = Time.unscaledDeltaTime;
_frameTimes.Enqueue(deltaTime);
_accumulatedTime += deltaTime;
_frameTimes.Enqueue(dt);
_accumulatedTime += dt;
if (_frameTimes.Count > _sampleSize) if (_frameTimes.Count > _sampleSize)
_accumulatedTime -= _frameTimes.Dequeue(); _accumulatedTime -= _frameTimes.Dequeue();
_timeSinceLastUpdate += dt; _timeSinceLastUpdate += deltaTime;
if (_timeSinceLastUpdate >= _updateInterval) if (_timeSinceLastUpdate >= _updateInterval)
{ {
_timeSinceLastUpdate = 0f; _timeSinceLastUpdate = 0f;
@@ -85,36 +86,37 @@ namespace OctoCore.UI
#endregion #endregion
#region Public Methods
/// <summary>Toggles the overlay on / off.</summary>
public void Toggle() => _displayText.gameObject.SetActive(!_displayText.gameObject.activeSelf);
#endregion
#region Private Methods #region Private Methods
private void ConfigureText()
{
if (_displayText == null) return;
_displayText.supportRichText = true;
_displayText.horizontalOverflow = HorizontalWrapMode.Overflow;
_displayText.verticalOverflow = VerticalWrapMode.Overflow;
_displayText.alignment = TextAnchor.UpperLeft;
}
private void RefreshDisplay() private void RefreshDisplay()
{ {
if (_displayText == null) return; if (_displayText == null) return;
if (_frameTimes.Count == 0) return;
float avgFrameTime = _accumulatedTime / _frameTimes.Count; float avgFrameTime = _accumulatedTime / _frameTimes.Count;
if (avgFrameTime <= 0f) return;
float fps = 1f / avgFrameTime; float fps = 1f / avgFrameTime;
float frameTimeMs = avgFrameTime * 1000f; float frameTimeMs = avgFrameTime * 1000f;
// HID polling floor (~8 ms for 125 Hz USB; ~1 ms for 1000 Hz)
float inputLagMs = frameTimeMs * (1 + _pipelineLatencyFrames) + 8f;
string fpsColour = fps >= _goodFps ? GREEN string fpsColour = fps >= _goodFps ? GREEN
: fps >= _warningFps ? YELLOW : fps >= _warningFps ? YELLOW
: RED; : RED;
_displayText.text = _displayText.text =
$"{fpsColour}{fps,5:F0} FPS{END}\n" + $"{fpsColour}{fps:F0} FPS{END}\n" +
$"Frame {frameTimeMs,6:F2} ms\n" + $"Frame {frameTimeMs:F2} ms";
$"Lag ≈ {inputLagMs,6:F2} ms";
} }
#endregion #endregion
} }
} }