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 |