|
|
|
|
#if UNITY_2018_1_OR_NEWER
|
|
|
|
|
|
|
|
|
|
namespace SRDebugger.Profiler
|
|
|
|
|
{
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using SRDebugger.Services;
|
|
|
|
|
using SRF;
|
|
|
|
|
using SRF.Service;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
#if UNITY_2019_3_OR_NEWER
|
|
|
|
|
using UnityEngine.Rendering;
|
|
|
|
|
#else
|
|
|
|
|
using UnityEngine.Experimental.Rendering;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
public class SRPProfilerService : SRServiceBase<IProfilerService>, IProfilerService
|
|
|
|
|
{
|
|
|
|
|
public float AverageFrameTime { get; private set; }
|
|
|
|
|
public float LastFrameTime { get; private set; }
|
|
|
|
|
|
|
|
|
|
public CircularBuffer<ProfilerFrame> FrameBuffer
|
|
|
|
|
{
|
|
|
|
|
get { return _frameBuffer; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private const int FrameBufferSize = 400;
|
|
|
|
|
private readonly CircularBuffer<ProfilerFrame> _frameBuffer = new CircularBuffer<ProfilerFrame>(FrameBufferSize);
|
|
|
|
|
|
|
|
|
|
private ProfilerLateUpdateListener _lateUpdateListener;
|
|
|
|
|
|
|
|
|
|
// Time between first Update() and last LateUpdate()
|
|
|
|
|
private double _updateDuration;
|
|
|
|
|
|
|
|
|
|
// Time that render pipeline starts
|
|
|
|
|
private double _renderStartTime;
|
|
|
|
|
|
|
|
|
|
// Time between scripted render pipeline starts + EndOfFrame
|
|
|
|
|
private double _renderDuration;
|
|
|
|
|
|
|
|
|
|
private readonly Stopwatch _stopwatch = new Stopwatch();
|
|
|
|
|
|
|
|
|
|
protected override void Awake()
|
|
|
|
|
{
|
|
|
|
|
base.Awake();
|
|
|
|
|
_lateUpdateListener = gameObject.AddComponent<ProfilerLateUpdateListener>();
|
|
|
|
|
_lateUpdateListener.OnLateUpdate = OnLateUpdate;
|
|
|
|
|
|
|
|
|
|
CachedGameObject.hideFlags = HideFlags.NotEditable;
|
|
|
|
|
CachedTransform.SetParent(Hierarchy.Get("SRDebugger"), true);
|
|
|
|
|
|
|
|
|
|
#if UNITY_2019_3_OR_NEWER
|
|
|
|
|
RenderPipelineManager.beginFrameRendering += RenderPipelineOnBeginFrameRendering;
|
|
|
|
|
#else
|
|
|
|
|
RenderPipeline.beginFrameRendering += RenderPipelineOnBeginFrameRendering;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
StartCoroutine(EndOfFrameCoroutine());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void Update()
|
|
|
|
|
{
|
|
|
|
|
base.Update();
|
|
|
|
|
|
|
|
|
|
EndFrame();
|
|
|
|
|
|
|
|
|
|
// Set the frame time for the last frame
|
|
|
|
|
if (FrameBuffer.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
var frame = FrameBuffer.Back();
|
|
|
|
|
frame.FrameTime = Time.unscaledDeltaTime;
|
|
|
|
|
FrameBuffer[FrameBuffer.Count - 1] = frame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LastFrameTime = Time.unscaledDeltaTime;
|
|
|
|
|
|
|
|
|
|
var frameCount = Mathf.Min(20, FrameBuffer.Count);
|
|
|
|
|
|
|
|
|
|
var f = 0d;
|
|
|
|
|
for (var i = 0; i < frameCount; i++)
|
|
|
|
|
{
|
|
|
|
|
f += FrameBuffer[FrameBuffer.Count - 1 - i].FrameTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AverageFrameTime = (float)f / frameCount;
|
|
|
|
|
|
|
|
|
|
_stopwatch.Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IEnumerator EndOfFrameCoroutine()
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
yield return new WaitForEndOfFrame();
|
|
|
|
|
_renderDuration = _stopwatch.Elapsed.TotalSeconds - _renderStartTime;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void PushFrame(double totalTime, double updateTime, double renderTime)
|
|
|
|
|
{
|
|
|
|
|
_frameBuffer.PushBack(new ProfilerFrame
|
|
|
|
|
{
|
|
|
|
|
OtherTime = totalTime - updateTime - renderTime,
|
|
|
|
|
UpdateTime = updateTime,
|
|
|
|
|
RenderTime = renderTime
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnLateUpdate()
|
|
|
|
|
{
|
|
|
|
|
_updateDuration = _stopwatch.Elapsed.TotalSeconds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if UNITY_2019_3_OR_NEWER
|
|
|
|
|
private void RenderPipelineOnBeginFrameRendering(ScriptableRenderContext context, Camera[] cameras)
|
|
|
|
|
#else
|
|
|
|
|
private void RenderPipelineOnBeginFrameRendering(Camera[] obj)
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
_renderStartTime = _stopwatch.Elapsed.TotalSeconds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EndFrame()
|
|
|
|
|
{
|
|
|
|
|
if (_stopwatch.IsRunning)
|
|
|
|
|
{
|
|
|
|
|
PushFrame(_stopwatch.Elapsed.TotalSeconds, _updateDuration, _renderDuration);
|
|
|
|
|
|
|
|
|
|
_stopwatch.Reset();
|
|
|
|
|
_stopwatch.Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_updateDuration = _renderDuration = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|