No Description
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.

AdaptivePerformanceDetailsViewController.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Text;
  4. using Unity.Profiling.Editor;
  5. using UnityEditor;
  6. using UnityEngine.UIElements;
  7. using UnityEngine.AdaptivePerformance;
  8. using System.Reflection;
  9. using UnityEngine;
  10. using UnityEditor.AdaptivePerformance.UI.Editor;
  11. internal class AdaptivePerformanceDetailsViewController : ProfilerModuleViewController
  12. {
  13. const string k_UxmlResourceName = "Packages/com.unity.adaptiveperformance/Editor/Profiler/AdaptivePerformanceDetailsView.uxml";
  14. const string k_UxmlResourceNameScaler = "Packages/com.unity.adaptiveperformance/Editor/Profiler/AdaptivePerformanceScalerElement.uxml";
  15. VisualElement m_view;
  16. Label m_DetailsViewLabel;
  17. VisualElement m_Scalers;
  18. UsageDial m_UsageDial;
  19. Label m_BottleneckLabel;
  20. VisualElement m_BottleneckIcon;
  21. Label m_UsageDialLabel;
  22. StyleColor m_appliedScalerColor = new StyleColor(new Color(0.09f, 0.69f, 0.3f, 1f));
  23. StyleColor m_unappliedScalerColor = new StyleColor(new Color(0.09f, 0.3f, 0.69f, 1f));
  24. StyleColor m_inactiveColor = new StyleColor(new Color(0.29f, 0.69f, 0.3f, 0.3f));
  25. Length m_scalerOffset = new Length(-200, LengthUnit.Pixel);
  26. Length m_midDistance = new Length(100, LengthUnit.Pixel);
  27. StyleRotate m_scalerRotate = new StyleRotate(new Rotate(180));
  28. static readonly StyleColor k_Green = new StyleColor(new Color32(136, 176, 49, byte.MaxValue));
  29. static readonly StyleColor k_Yellow = new StyleColor(new Color32(221, 124, 69, byte.MaxValue));
  30. static readonly StyleColor k_Red = new StyleColor(new Color32(219, 89, 81, byte.MaxValue));
  31. public AdaptivePerformanceDetailsViewController(ProfilerWindow profilerWindow) : base(profilerWindow) {}
  32. protected override VisualElement CreateView()
  33. {
  34. var apDetailsView = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_UxmlResourceName);
  35. m_view = apDetailsView.Instantiate();
  36. m_DetailsViewLabel = m_view.Q<Label>("ap-details-view-label");
  37. m_Scalers = m_view.Q<VisualElement>("ap-scalers");
  38. m_BottleneckLabel = m_view.Q<Label>("ap-details-view-bottleneck-icon-label");
  39. m_BottleneckIcon = m_view.Q<VisualElement>("ap-details-view-bottleneck-icon");
  40. m_UsageDial = m_view.Q<UsageDial>();
  41. m_UsageDialLabel = m_view.Q<Label>("ap-details-view-thermal-label");
  42. if (m_UsageDial != null)
  43. {
  44. m_UsageDial.ShowLabel = false;
  45. m_UsageDial?.SetThresholds(40, 75);
  46. }
  47. // Create settings for each one of the scalers
  48. Type ti = typeof(AdaptivePerformanceScaler);
  49. var scalerTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_UxmlResourceNameScaler);
  50. foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
  51. {
  52. foreach (Type t in asm.GetTypes())
  53. {
  54. if (ti.IsAssignableFrom(t) && !t.IsAbstract)
  55. {
  56. var container = scalerTree.CloneTree();
  57. var viewName = container.Q<Label>("ap-scaler-element-label");
  58. var barFill = container.Q<VisualElement>("ap-scaler-element-bar-fill");
  59. var maxLabel = container.Q<Label>("ap-scaler-element-max-label");
  60. var currentLabel = container.Q<Label>("ap-scaler-element-level-label");
  61. viewName.text = $"{t.Name.Replace("Adaptive", "")}";
  62. viewName.name = $"{t.Name}-element-label";
  63. barFill.name = $"{t.Name}-element-bar-fill";
  64. maxLabel.name = $"{t.Name}-element-max-label";
  65. currentLabel.name = $"{t.Name}-element-current-label";
  66. currentLabel.style.bottom = m_midDistance;
  67. m_Scalers.Add(container);
  68. }
  69. }
  70. }
  71. ReloadData(ProfilerWindow.selectedFrameIndex);
  72. ProfilerWindow.SelectedFrameIndexChanged += OnSelectedFrameIndexChanged;
  73. return m_view;
  74. }
  75. protected override void Dispose(bool disposing)
  76. {
  77. if (!disposing)
  78. return;
  79. ProfilerWindow.SelectedFrameIndexChanged -= OnSelectedFrameIndexChanged;
  80. base.Dispose(disposing);
  81. }
  82. void OnSelectedFrameIndexChanged(long selectedFrameIndex)
  83. {
  84. ReloadData(selectedFrameIndex);
  85. }
  86. void ReloadData(long selectedFrameIndex)
  87. {
  88. var selectedFrameIndexInt32 = Convert.ToInt32(selectedFrameIndex);
  89. using (var frameData = UnityEditorInternal.ProfilerDriver.GetRawFrameDataView(selectedFrameIndexInt32, 0))
  90. {
  91. if (frameData == null || !frameData.valid)
  92. {
  93. m_DetailsViewLabel.text = "No Adaptive Performance Frame Data.";
  94. return;
  95. }
  96. var thermalWarningLevel = (WarningLevel)ExtractAdaptivePerformanceCounterValueInt(frameData, "Thermal Warning Level");
  97. var bottleneck = (PerformanceBottleneck)ExtractAdaptivePerformanceCounterValueInt(frameData, "Bottleneck");
  98. m_DetailsViewLabel.text = $"CPU frametime: {ExtractAdaptivePerformanceCounterValueFloat(frameData, "CPU frametime") / 1000000.0f} ms \t\t" +
  99. $"Average CPU frametime: {ExtractAdaptivePerformanceCounterValueFloat(frameData, "CPU avg frametime") / 1000000.0f} ms \n" +
  100. $"GPU frametime: {ExtractAdaptivePerformanceCounterValueFloat(frameData, "GPU frametime") / 1000000.0f} ms \t\t" +
  101. $"Average GPU frametime: {ExtractAdaptivePerformanceCounterValueFloat(frameData, "GPU avg frametime") / 1000000.0f} ms \n" +
  102. $"Frametime: {ExtractAdaptivePerformanceCounterValueFloat(frameData, "Frametime") / 1000000.0f} ms \t\t\t" +
  103. $"Average frametime: {ExtractAdaptivePerformanceCounterValueFloat(frameData, "Avg frametime") / 1000000.0f} ms \n" +
  104. $"\n" +
  105. $"CPU performance level: {ExtractAdaptivePerformanceCounterValueInt(frameData, "CPU performance level")} \n" +
  106. $"GPU performance level: {ExtractAdaptivePerformanceCounterValueInt(frameData, "GPU performance level")} \n" +
  107. $"\n" +
  108. $"Temperature Level: {ExtractAdaptivePerformanceCounterValueFloat(frameData, "Temperature Level")} \n" +
  109. $"Temperature Trend: {ExtractAdaptivePerformanceCounterValueFloat(frameData, "Temperature Trend")} \n" +
  110. $"\n" +
  111. $"Thermal Warning Level: {thermalWarningLevel} \n" +
  112. $"Bottleneck: {bottleneck} \n";
  113. if (m_BottleneckLabel != null && m_BottleneckIcon != null)
  114. {
  115. if (bottleneck == PerformanceBottleneck.CPU)
  116. {
  117. m_BottleneckIcon.style.backgroundColor = k_Red;
  118. m_BottleneckLabel.text = "CPU";
  119. }
  120. else if (bottleneck == PerformanceBottleneck.GPU)
  121. {
  122. m_BottleneckIcon.style.backgroundColor = k_Red;
  123. m_BottleneckLabel.text = "GPU";
  124. }
  125. else if (bottleneck == PerformanceBottleneck.TargetFrameRate)
  126. {
  127. m_BottleneckIcon.style.backgroundColor = k_Yellow;
  128. m_BottleneckLabel.text = "Target Framerate";
  129. }
  130. else
  131. {
  132. m_BottleneckIcon.style.backgroundColor = k_Yellow;
  133. m_BottleneckLabel.text = "Unknown";
  134. }
  135. }
  136. if (m_UsageDial != null)
  137. {
  138. if (thermalWarningLevel == WarningLevel.NoWarning)
  139. {
  140. m_UsageDial.Value = 25;
  141. m_UsageDialLabel.text = "No Warning";
  142. }
  143. else if (thermalWarningLevel == WarningLevel.ThrottlingImminent)
  144. {
  145. m_UsageDial.Value = 60;
  146. m_UsageDialLabel.text = "Throttling Imminent";
  147. }
  148. else if (thermalWarningLevel >= WarningLevel.Throttling)
  149. {
  150. m_UsageDial.Value = 90;
  151. m_UsageDialLabel.text = "Throttling";
  152. }
  153. }
  154. var returnVal = new AdaptivePerformanceProfilerStats.ScalerInfo[] {};
  155. var scalerInfos = GetScalerFromProfilerStream(selectedFrameIndexInt32);
  156. unsafe
  157. {
  158. foreach (var scalerInfo in scalerInfos)
  159. {
  160. const int arraySize = 320;
  161. var arr = new byte[arraySize];
  162. Marshal.Copy((IntPtr)scalerInfo.scalerName, arr, 0, arraySize);
  163. var scalerName = Encoding.ASCII.GetString(arr).Replace(" ", "");
  164. scalerName = scalerName.Replace("\0", "");
  165. var viewName = m_Scalers.Q<Label>($"{scalerName}-element-label");
  166. var barFill = m_Scalers.Q<VisualElement>($"{scalerName}-element-bar-fill");
  167. var maxLabel = m_Scalers.Q<Label>($"{scalerName}-element-max-label");
  168. var currentLabel = m_Scalers.Q<Label>($"{scalerName}-element-current-label");
  169. if (currentLabel == null || maxLabel == null || barFill == null || viewName == null)
  170. continue;
  171. currentLabel.text = $"{scalerInfo.currentLevel}";
  172. if (scalerInfo.enabled == 0)
  173. {
  174. barFill.style.backgroundColor = m_inactiveColor;
  175. }
  176. else
  177. {
  178. if (scalerInfo.applied == 1)
  179. barFill.style.backgroundColor = m_appliedScalerColor;
  180. else
  181. barFill.style.backgroundColor = m_unappliedScalerColor;
  182. }
  183. var height = new Length((((float)scalerInfo.currentLevel / (float)scalerInfo.maxLevel)) * 100.0f, LengthUnit.Percent);
  184. barFill.style.height = height;
  185. barFill.style.bottom = m_scalerOffset;
  186. barFill.style.rotate = m_scalerRotate;
  187. maxLabel.text = $"{scalerInfo.maxLevel}";
  188. }
  189. }
  190. }
  191. }
  192. static int ExtractAdaptivePerformanceCounterValueInt(UnityEditor.Profiling.FrameDataView frameData, string counterName)
  193. {
  194. if (frameData == null || counterName.Length == 0)
  195. return 0;
  196. var counterMarkerId = frameData.GetMarkerId(counterName);
  197. return frameData.GetCounterValueAsInt(counterMarkerId);
  198. }
  199. static float ExtractAdaptivePerformanceCounterValueFloat(UnityEditor.Profiling.FrameDataView frameData, string counterName)
  200. {
  201. if (frameData == null || counterName.Length == 0)
  202. return 0;
  203. var counterMarkerId = frameData.GetMarkerId(counterName);
  204. return frameData.GetCounterValueAsFloat(counterMarkerId);
  205. }
  206. public static AdaptivePerformanceProfilerStats.ScalerInfo[] GetScalerFromProfilerStream(int frame)
  207. {
  208. using (var frameData = UnityEditorInternal.ProfilerDriver.GetRawFrameDataView(frame, 0))
  209. {
  210. var returnVal = new AdaptivePerformanceProfilerStats.ScalerInfo[] {};
  211. if (frameData != null)
  212. {
  213. var clientInfos =
  214. frameData.GetFrameMetaData<AdaptivePerformanceProfilerStats.ScalerInfo>(AdaptivePerformanceProfilerStats.kAdaptivePerformanceProfilerModuleGuid, AdaptivePerformanceProfilerStats.kScalerDataTag);
  215. if (clientInfos.Length != 0)
  216. {
  217. returnVal = clientInfos.ToArray();
  218. }
  219. }
  220. return returnVal;
  221. }
  222. }
  223. }