137 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C#
		
	
	
	
		
		
			
		
	
	
			137 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C#
		
	
	
	
|  | #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 |