A game about forced loneliness, made by TACStudios
at master 215 lines 10 kB view raw
1//#define RTPROFILER_DEBUG 2 3using System; 4using System.Collections.Generic; 5using System.Linq; 6using UnityEngine; 7 8namespace UnityEngine.Rendering 9{ 10 /// <summary> 11 /// Debug frame timings class 12 /// </summary> 13 public class DebugFrameTiming 14 { 15 const string k_FpsFormatString = "{0:F1}"; 16 const string k_MsFormatString = "{0:F2}ms"; 17 const float k_RefreshRate = 1f / 5f; 18 19 internal FrameTimeSampleHistory m_FrameHistory; 20 internal BottleneckHistory m_BottleneckHistory; 21 22 /// <summary> 23 /// Size of the Bottleneck History Window in number of samples. 24 /// </summary> 25 public int bottleneckHistorySize { get; set; } = 60; 26 27 /// <summary> 28 /// Size of the Sample History Window in number of samples. 29 /// </summary> 30 public int sampleHistorySize { get; set; } = 30; 31 32 FrameTiming[] m_Timing = new FrameTiming[1]; 33 FrameTimeSample m_Sample = new FrameTimeSample(); 34 35 /// <summary> 36 /// Constructs the debug frame timing 37 /// </summary> 38 public DebugFrameTiming() 39 { 40 m_FrameHistory = new FrameTimeSampleHistory(sampleHistorySize); 41 m_BottleneckHistory = new BottleneckHistory(bottleneckHistorySize); 42 } 43 44 /// <summary> 45 /// Update timing data from profiling counters. 46 /// </summary> 47 public void UpdateFrameTiming() 48 { 49 m_Timing[0] = default; 50 m_Sample = default; 51 FrameTimingManager.CaptureFrameTimings(); 52 FrameTimingManager.GetLatestTimings(1, m_Timing); 53 54 if (m_Timing.Length > 0) 55 { 56 m_Sample.FullFrameTime = (float)m_Timing.First().cpuFrameTime; 57 m_Sample.FramesPerSecond = m_Sample.FullFrameTime > 0f ? 1000f / m_Sample.FullFrameTime : 0f; 58 m_Sample.MainThreadCPUFrameTime = (float)m_Timing.First().cpuMainThreadFrameTime; 59 m_Sample.MainThreadCPUPresentWaitTime = (float)m_Timing.First().cpuMainThreadPresentWaitTime; 60 m_Sample.RenderThreadCPUFrameTime = (float)m_Timing.First().cpuRenderThreadFrameTime; 61 m_Sample.GPUFrameTime = (float)m_Timing.First().gpuFrameTime; 62 } 63 64 m_FrameHistory.DiscardOldSamples(sampleHistorySize); 65 m_FrameHistory.Add(m_Sample); 66 m_FrameHistory.ComputeAggregateValues(); 67 68 m_BottleneckHistory.DiscardOldSamples(bottleneckHistorySize); 69 m_BottleneckHistory.AddBottleneckFromAveragedSample(m_FrameHistory.SampleAverage); 70 m_BottleneckHistory.ComputeHistogram(); 71 } 72 73 /// <summary> 74 /// Add frame timing data widgets to debug UI. 75 /// </summary> 76 /// <param name="list">List of widgets to add the stats.</param> 77 public void RegisterDebugUI(List<DebugUI.Widget> list) 78 { 79 list.Add(new DebugUI.Foldout() 80 { 81 displayName = "Frame Stats", 82 isHeader = true, 83 opened = true, 84 columnLabels = new string[] { "Avg", "Min", "Max" }, 85 children = 86 { 87 new DebugUI.ValueTuple 88 { 89 displayName = "Frame Rate (FPS)", 90 values = new[] 91 { 92 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FpsFormatString, getter = () => m_FrameHistory.SampleAverage.FramesPerSecond }, 93 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FpsFormatString, getter = () => m_FrameHistory.SampleMin.FramesPerSecond }, 94 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FpsFormatString, getter = () => m_FrameHistory.SampleMax.FramesPerSecond }, 95 } 96 }, 97 new DebugUI.ValueTuple 98 { 99 displayName = "Frame Time", 100 values = new[] 101 { 102 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleAverage.FullFrameTime }, 103 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMin.FullFrameTime }, 104 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMax.FullFrameTime }, 105 } 106 }, 107 new DebugUI.ValueTuple 108 { 109 displayName = "CPU Main Thread Frame", 110 values = new[] 111 { 112 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleAverage.MainThreadCPUFrameTime }, 113 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMin.MainThreadCPUFrameTime }, 114 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMax.MainThreadCPUFrameTime }, 115 } 116 }, 117 new DebugUI.ValueTuple 118 { 119 displayName = "CPU Render Thread Frame", 120 values = new[] 121 { 122 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleAverage.RenderThreadCPUFrameTime }, 123 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMin.RenderThreadCPUFrameTime }, 124 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMax.RenderThreadCPUFrameTime }, 125 } 126 }, 127 new DebugUI.ValueTuple 128 { 129 displayName = "CPU Present Wait", 130 values = new[] 131 { 132 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleAverage.MainThreadCPUPresentWaitTime }, 133 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMin.MainThreadCPUPresentWaitTime }, 134 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMax.MainThreadCPUPresentWaitTime }, 135 } 136 }, 137 new DebugUI.ValueTuple 138 { 139 displayName = "GPU Frame", 140 values = new[] 141 { 142 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleAverage.GPUFrameTime }, 143 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMin.GPUFrameTime }, 144 new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMax.GPUFrameTime }, 145 } 146 } 147 } 148 }); 149 150 list.Add(new DebugUI.Foldout 151 { 152 displayName = "Bottlenecks", 153 isHeader = true, 154 children = 155 { 156#if UNITY_EDITOR 157 new DebugUI.Container { displayName = "Not supported in Editor" } 158#else 159 new DebugUI.ProgressBarValue { displayName = "CPU", getter = () => m_BottleneckHistory.Histogram.CPU }, 160 new DebugUI.ProgressBarValue { displayName = "GPU", getter = () => m_BottleneckHistory.Histogram.GPU }, 161 new DebugUI.ProgressBarValue { displayName = "Present limited", getter = () => m_BottleneckHistory.Histogram.PresentLimited }, 162 new DebugUI.ProgressBarValue { displayName = "Balanced", getter = () => m_BottleneckHistory.Histogram.Balanced }, 163#endif 164 } 165 }); 166#if RTPROFILER_DEBUG 167 list.Add(new DebugUI.Foldout 168 { 169 displayName = "Realtime Profiler Debug", 170 children = 171 { 172 new DebugUI.IntField 173 { 174 displayName = "Frame Time Sample History Size", 175 getter = () => sampleHistorySize, 176 setter = (value) => { sampleHistorySize = value; }, 177 min = () => 1, 178 max = () => 100 179 }, 180 new DebugUI.IntField 181 { 182 displayName = "Bottleneck History Size", 183 getter = () => bottleneckHistorySize, 184 setter = (value) => { bottleneckHistorySize = value; }, 185 min = () => 1, 186 max = () => 100 187 }, 188 new DebugUI.IntField 189 { 190 displayName = "Force VSyncCount", 191 min = () => - 1, 192 max = () => 4, 193 getter = () => QualitySettings.vSyncCount, 194 setter = (value) => { QualitySettings.vSyncCount = value; } 195 }, 196 new DebugUI.IntField 197 { 198 displayName = "Force TargetFrameRate", 199 min = () => - 1, 200 max = () => 1000, 201 getter = () => Application.targetFrameRate, 202 setter = (value) => { Application.targetFrameRate = value; } 203 }, 204 } 205 }); 206#endif 207 } 208 209 internal void Reset() 210 { 211 m_BottleneckHistory.Clear(); 212 m_FrameHistory.Clear(); 213 } 214 } 215}