Fix : Uncapped FPS ; Removed : Estimated Input lag
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user