#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 { public float AverageFrameTime { get; private set; } public float LastFrameTime { get; private set; } public CircularBuffer FrameBuffer { get { return _frameBuffer; } } private const int FrameBufferSize = 400; private readonly CircularBuffer _frameBuffer = new CircularBuffer(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(); _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