暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DebugFrameTiming.cs 10KB

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