EventViewerWindow.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEditor.AddressableAssets.Diagnostics.Data;
  4. using UnityEditor.AddressableAssets.Diagnostics.GUI.Graph;
  5. using UnityEditor.AddressableAssets.Settings;
  6. using UnityEditor.IMGUI.Controls;
  7. using UnityEngine;
  8. using UnityEngine.ResourceManagement.Diagnostics;
  9. using UnityEngine.Serialization;
  10. using UnityEditor.Networking.PlayerConnection;
  11. using UnityEngine.Networking.PlayerConnection;
  12. namespace UnityEditor.AddressableAssets.Diagnostics.GUI
  13. {
  14. class EventViewerWindow : EditorWindow, IComparer<EventDataSet>
  15. {
  16. EventDataPlayerSessionCollection m_EventData;
  17. GUIContent m_PrevFrameIcon;
  18. GUIContent m_NextFrameIcon;
  19. int m_PlayerSessionIndex;
  20. int m_InspectFrame;
  21. int m_EventListFrame = -1;
  22. VerticalSplitter m_VerticalSplitter = new VerticalSplitter();
  23. HorizontalSplitter m_HorizontalSplitter = new HorizontalSplitter();
  24. float m_LastEventListUpdate;
  25. bool m_DraggingInspectLine;
  26. int m_LatestFrame;
  27. TreeViewState m_EventListTreeViewState;
  28. MultiColumnHeaderState m_EventListMchs;
  29. EventListView m_EventList;
  30. TreeViewState m_GraphListTreeViewState;
  31. MultiColumnHeaderState m_GraphListMchs;
  32. EventGraphListView m_GraphList;
  33. EventDataPlayerSession activeSession
  34. {
  35. get { return m_EventData == null ? null : m_EventData.GetSessionByIndex(m_PlayerSessionIndex); }
  36. }
  37. protected virtual bool ShowEventDetailPanel { get { return false; } }
  38. protected virtual bool ShowEventPanel { get { return false; } }
  39. void OnEnable()
  40. {
  41. EditorConnection.instance.Initialize();
  42. EditorConnection.instance.Register(DiagnosticEventCollectorSingleton.PlayerConnectionGuid, OnPlayerConnectionMessage);
  43. EditorConnection.instance.RegisterConnection(OnPlayerConnection);
  44. EditorConnection.instance.RegisterDisconnection(OnPlayerDisconnection);
  45. m_LastEventListUpdate = 0;
  46. m_PrevFrameIcon = EditorGUIUtility.IconContent("Profiler.PrevFrame", "|Go one frame backwards");
  47. m_NextFrameIcon = EditorGUIUtility.IconContent("Profiler.NextFrame", "|Go one frame forwards");
  48. EditorApplication.playModeStateChanged += OnEditorPlayModeChanged;
  49. if (m_EventData == null)
  50. {
  51. RegisterEventHandler(true);
  52. m_EventData = new EventDataPlayerSessionCollection(OnRecordEvent);
  53. m_EventData.GetPlayerSession(0, true).IsActive = true;
  54. }
  55. }
  56. void OnDisable()
  57. {
  58. EditorConnection.instance.Unregister(DiagnosticEventCollectorSingleton.PlayerConnectionGuid, OnPlayerConnectionMessage);
  59. RegisterEventHandler(false);
  60. EditorApplication.playModeStateChanged -= OnEditorPlayModeChanged;
  61. }
  62. void OnPlayerConnection(int id)
  63. {
  64. if (m_EventData == null)
  65. m_EventData = new EventDataPlayerSessionCollection(OnRecordEvent);
  66. m_EventData.GetPlayerSession(id, true).IsActive = true;
  67. int connectedSessionIndex = m_EventData.GetSessionIndexById(id);
  68. m_PlayerSessionIndex = connectedSessionIndex != -1 ? connectedSessionIndex : 0;
  69. }
  70. void OnPlayerDisconnection(int id)
  71. {
  72. if (m_EventData == null)
  73. return;
  74. m_EventData.RemoveSession(id);
  75. m_PlayerSessionIndex = 0;
  76. }
  77. void OnPlayerConnectionMessage(MessageEventArgs args)
  78. {
  79. var evt = DiagnosticEvent.Deserialize(args.data);
  80. OnEvent(evt, args.playerId);
  81. }
  82. void RegisterEventHandler(bool reg)
  83. {
  84. if (ProjectConfigData.PostProfilerEvents)
  85. DiagnosticEventCollectorSingleton.RegisterEventHandler(OnEditorPlayModeEvent, reg, true);
  86. }
  87. void OnEditorPlayModeEvent(DiagnosticEvent evt)
  88. {
  89. if (m_EventData == null)
  90. m_EventData = new EventDataPlayerSessionCollection(OnRecordEvent);
  91. if (m_EventData.GetPlayerSession(0, false) == null)
  92. m_EventData.AddSession("Editor", m_PlayerSessionIndex = 0);
  93. OnEvent(evt, 0);
  94. }
  95. public void OnEvent(DiagnosticEvent diagnosticEvent, int session)
  96. {
  97. if (m_EventData == null)
  98. m_EventData = new EventDataPlayerSessionCollection(OnRecordEvent);
  99. var entryCreated = m_EventData.ProcessEvent(diagnosticEvent, session);
  100. OnEventProcessed(diagnosticEvent, entryCreated);
  101. }
  102. public int Compare(EventDataSet x, EventDataSet y)
  103. {
  104. return x.CompareTo(y);
  105. }
  106. protected virtual bool CanHandleEvent(string graph)
  107. {
  108. if (graph.Contains("Count"))
  109. return true;
  110. return OnCanHandleEvent(graph);
  111. }
  112. protected virtual bool OnCanHandleEvent(string graph) { return true; }
  113. void OnEditorPlayModeChanged(PlayModeStateChange state)
  114. {
  115. if (state == PlayModeStateChange.EnteredPlayMode)
  116. {
  117. m_EventData = new EventDataPlayerSessionCollection(OnRecordEvent);
  118. m_EventData.GetPlayerSession(0, true).IsActive = true;
  119. m_LastEventListUpdate = 0;
  120. m_InspectFrame = -1;
  121. m_LatestFrame = -1;
  122. m_PlayerSessionIndex = 0;
  123. RegisterEventHandler(true);
  124. }
  125. if (state == PlayModeStateChange.EnteredEditMode)
  126. {
  127. RegisterEventHandler(false);
  128. }
  129. }
  130. protected virtual bool OnDisplayEvent(DiagnosticEvent diagnosticEvent)
  131. {
  132. var sel = m_GraphList.GetSelection();
  133. if (sel == null || sel.Count == 0)
  134. return true;
  135. foreach (var s in sel)
  136. {
  137. // m_GraphList.Fi
  138. }
  139. return true;
  140. }
  141. protected virtual bool OnRecordEvent(DiagnosticEvent diagnosticEvent)
  142. {
  143. return false;
  144. }
  145. int m_LastRepaintedFrame = -1;
  146. void OnEventProcessed(DiagnosticEvent diagnosticEvent, bool entryCreated)
  147. {
  148. if (!CanHandleEvent(diagnosticEvent.Graph))
  149. return;
  150. bool moveInspectFrame = m_LatestFrame < 0 || m_InspectFrame == m_LatestFrame;
  151. m_LatestFrame = diagnosticEvent.Frame;
  152. if (entryCreated)
  153. {
  154. if (m_GraphList != null)
  155. m_GraphList.Reload();
  156. }
  157. if (moveInspectFrame)
  158. SetInspectFrame(m_LatestFrame);
  159. if (diagnosticEvent.Frame != m_LastRepaintedFrame)
  160. {
  161. Repaint();
  162. m_LastRepaintedFrame = diagnosticEvent.Frame;
  163. }
  164. }
  165. void SetInspectFrame(int frame)
  166. {
  167. m_InspectFrame = frame;
  168. if (m_InspectFrame > m_LatestFrame)
  169. m_InspectFrame = m_LatestFrame;
  170. if (m_InspectFrame < 0)
  171. m_InspectFrame = 0;
  172. if (m_EventList != null)
  173. m_EventList.SetEvents(activeSession == null ? null : activeSession.GetFrameEvents(m_InspectFrame));
  174. m_LastEventListUpdate = Time.unscaledTime;
  175. m_EventListFrame = m_InspectFrame;
  176. }
  177. void OnGUI()
  178. {
  179. if (activeSession == null)
  180. return;
  181. InitializeGui();
  182. //this prevent arrow key events from reaching the treeview, so navigation via keys is disabled
  183. if (Event.current.type == EventType.KeyDown)
  184. {
  185. if (Event.current.keyCode == KeyCode.RightArrow)
  186. {
  187. SetInspectFrame(m_InspectFrame + 1);
  188. return;
  189. }
  190. if (Event.current.keyCode == KeyCode.LeftArrow)
  191. {
  192. SetInspectFrame(m_InspectFrame - 1);
  193. return;
  194. }
  195. }
  196. DrawToolBar(activeSession);
  197. var r = EditorGUILayout.GetControlRect();
  198. Rect contentRect = new Rect(r.x, r.y, r.width, position.height - r.y);
  199. var graphRect = m_GraphList.GraphRect;
  200. if (ShowEventPanel)
  201. {
  202. Rect top, bot;
  203. bool resizingVer = m_VerticalSplitter.OnGUI(contentRect, out top, out bot);
  204. ProcessInspectFrame(graphRect);
  205. m_GraphList.DrawGraphs(top, activeSession, m_InspectFrame);
  206. DrawInspectFrame(graphRect);
  207. bool resizingHor = false;
  208. if (ShowEventDetailPanel)
  209. {
  210. Rect left, right;
  211. resizingHor = m_HorizontalSplitter.OnGUI(bot, out left, out right);
  212. m_EventList.OnGUI(left);
  213. OnDrawEventDetail(right, m_EventList.selectedEvent);
  214. }
  215. else
  216. {
  217. m_EventList.OnGUI(bot);
  218. }
  219. if (resizingVer || resizingHor)
  220. Repaint();
  221. }
  222. else
  223. {
  224. ProcessInspectFrame(graphRect);
  225. m_GraphList.DrawGraphs(contentRect, activeSession, m_InspectFrame);
  226. DrawInspectFrame(graphRect);
  227. }
  228. }
  229. protected virtual void OnDrawEventDetail(Rect right, DiagnosticEvent selectedEvent)
  230. {
  231. }
  232. void OnInspectorUpdate()
  233. {
  234. if (m_EventData == null) return;
  235. m_EventData.Update();
  236. if (activeSession != null && activeSession.NeedsReload)
  237. {
  238. activeSession.NeedsReload = false;
  239. m_EventList?.Reload();
  240. }
  241. Repaint();
  242. }
  243. void ProcessInspectFrame(Rect graphRect)
  244. {
  245. if (Event.current.type == EventType.MouseDown && graphRect.Contains(Event.current.mousePosition))
  246. {
  247. if (EditorApplication.isPlaying)
  248. EditorApplication.isPaused = true;
  249. m_DraggingInspectLine = true;
  250. SetInspectFrame(m_InspectFrame);
  251. }
  252. if (m_DraggingInspectLine && (Event.current.type == EventType.MouseDrag || Event.current.type == EventType.Repaint))
  253. SetInspectFrame(m_GraphList.visibleStartTime + (int)GraphUtility.PixelToValue(Event.current.mousePosition.x, graphRect.xMin, graphRect.xMax, m_GraphList.visibleDuration));
  254. if (Event.current.type == EventType.MouseUp)
  255. {
  256. m_DraggingInspectLine = false;
  257. SetInspectFrame(m_InspectFrame);
  258. }
  259. }
  260. void DrawInspectFrame(Rect graphPanelRect)
  261. {
  262. if (m_InspectFrame != m_LatestFrame)
  263. {
  264. var ix = graphPanelRect.xMin + GraphUtility.ValueToPixel(m_InspectFrame, m_GraphList.visibleStartTime, m_GraphList.visibleStartTime + m_GraphList.visibleDuration, graphPanelRect.width);
  265. EditorGUI.DrawRect(new Rect(ix - 1, graphPanelRect.yMin, 3, graphPanelRect.height), Color.white * .8f);
  266. }
  267. }
  268. void DrawToolBar(EventDataPlayerSession session)
  269. {
  270. EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
  271. if (GUILayout.Button("Clear Events", EditorStyles.toolbarButton))
  272. {
  273. RegisterEventHandler(false);
  274. session.Clear();
  275. m_GraphList?.Reload();
  276. RegisterEventHandler(true);
  277. }
  278. if (m_GraphList != null && m_GraphList.HasHiddenEvents && GUILayout.Button("Unhide All Hidden Events", EditorStyles.toolbarButton))
  279. m_GraphList.UnhideAllHiddenEvents();
  280. GUILayout.FlexibleSpace();
  281. GUILayout.Label(m_InspectFrame == m_LatestFrame ? "Frame: " : "Frame: " + m_InspectFrame + "/" + m_LatestFrame, EditorStyles.miniLabel);
  282. using (new EditorGUI.DisabledScope(m_InspectFrame <= 0))
  283. if (GUILayout.Button(m_PrevFrameIcon, EditorStyles.toolbarButton))
  284. SetInspectFrame(m_InspectFrame - 1);
  285. using (new EditorGUI.DisabledScope(m_InspectFrame >= m_LatestFrame))
  286. if (GUILayout.Button(m_NextFrameIcon, EditorStyles.toolbarButton))
  287. SetInspectFrame(m_InspectFrame + 1);
  288. if (GUILayout.Button("Current", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
  289. SetInspectFrame(m_LatestFrame);
  290. GUILayout.EndHorizontal();
  291. }
  292. protected virtual void OnGetColumns(List<string> columnNames, List<float> columnSizes)
  293. {
  294. if (columnNames == null || columnSizes == null)
  295. return;
  296. columnNames.Add("Event"); columnSizes.Add(50);
  297. columnNames.Add("Id"); columnSizes.Add(200);
  298. // columnNames.Add("Data"); columnSizes.Add(400);
  299. }
  300. protected virtual bool OnDrawColumnCell(Rect cellRect, DiagnosticEvent diagnosticEvent, int column)
  301. {
  302. return false;
  303. }
  304. protected virtual void DrawColumnCell(Rect cellRect, DiagnosticEvent diagnosticEvent, int column)
  305. {
  306. if (!OnDrawColumnCell(cellRect, diagnosticEvent, column))
  307. {
  308. switch (column)
  309. {
  310. case 0: EditorGUI.LabelField(cellRect, diagnosticEvent.Stream.ToString()); break;
  311. case 1: EditorGUI.LabelField(cellRect, diagnosticEvent.DisplayName); break;
  312. // case 2: EditorGUI.LabelField(cellRect, diagnosticEvent. == null ? "null" : diagnosticEvent.Data.ToString()); break;
  313. }
  314. }
  315. }
  316. void InitializeGui()
  317. {
  318. if (m_GraphList == null)
  319. {
  320. if (m_GraphListTreeViewState == null)
  321. m_GraphListTreeViewState = new TreeViewState();
  322. var headerState = EventGraphListView.CreateDefaultHeaderState();
  323. if (MultiColumnHeaderState.CanOverwriteSerializedFields(m_GraphListMchs, headerState))
  324. MultiColumnHeaderState.OverwriteSerializedFields(m_GraphListMchs, headerState);
  325. m_GraphListMchs = headerState;
  326. m_GraphList = new EventGraphListView(() => { return activeSession == null ? null : activeSession.RootStreamEntry; }, m_GraphListTreeViewState, m_GraphListMchs, CanHandleEvent, this);
  327. InitializeGraphView(m_GraphList);
  328. m_GraphList.Reload();
  329. }
  330. if (m_EventList == null)
  331. {
  332. if (m_EventListTreeViewState == null)
  333. m_EventListTreeViewState = new TreeViewState();
  334. var columns = new List<string>();
  335. var sizes = new List<float>();
  336. OnGetColumns(columns, sizes);
  337. var headerState = EventListView.CreateDefaultMultiColumnHeaderState(columns, sizes);
  338. if (MultiColumnHeaderState.CanOverwriteSerializedFields(m_EventListMchs, headerState))
  339. MultiColumnHeaderState.OverwriteSerializedFields(m_EventListMchs, headerState);
  340. m_EventListMchs = headerState;
  341. m_EventList = new EventListView(m_EventListTreeViewState, m_EventListMchs, DrawColumnCell, OnDisplayEvent);
  342. m_EventList.Reload();
  343. }
  344. if (m_EventListFrame != m_InspectFrame && m_InspectFrame != m_LatestFrame && !m_DraggingInspectLine && Time.unscaledTime - m_LastEventListUpdate > .25f)
  345. {
  346. if (activeSession != null)
  347. m_EventList.SetEvents(activeSession.GetFrameEvents(m_InspectFrame));
  348. m_LastEventListUpdate = Time.unscaledTime;
  349. m_EventListFrame = m_InspectFrame;
  350. }
  351. if (m_GraphListMchs != null && m_GraphListMchs.columns.Length > 2)
  352. {
  353. string warningText = string.Empty;
  354. if (!ProjectConfigData.PostProfilerEvents)
  355. warningText = "Warning: 'Send Profiler events' must be enabled in your Addressable Asset settings to view profile data. Changes to 'Send Profiler Events' will be applied on the following build.";
  356. m_GraphListMchs.columns[2].headerContent.text = warningText;
  357. }
  358. }
  359. void InitializeGraphView(EventGraphListView graphView)
  360. {
  361. graphView.DefineGraph("FrameCount", 1, new GraphLayerBarChartMesh(1, "FPS", "Current Frame Rate", Color.blue),
  362. new GraphLayerLabel(1, "FPS", "Current Frame Rate", Color.white, GraphColors.LabelGraphLabelBackground, v => string.Format("{0} FPS", v)));
  363. graphView.DefineGraph("MemoryCount", 2, new GraphLayerBarChartMesh(2, "MonoHeap", "Current Mono Heap Size", Color.green * .75f),
  364. new GraphLayerLabel(2, "MonoHeap", "Current Mono Heap Size", Color.white, GraphColors.LabelGraphLabelBackground, v => string.Format("{0:0.0}MB", (v / 1024f))));
  365. OnInitializeGraphView(graphView);
  366. }
  367. protected virtual void OnInitializeGraphView(EventGraphListView graphView) {}
  368. }
  369. [Serializable]
  370. class VerticalSplitter
  371. {
  372. [NonSerialized]
  373. Rect m_Rect = new Rect(0, 0, 0, 3);
  374. public Rect SplitterRect { get { return m_Rect; } }
  375. [FormerlySerializedAs("m_currentPercent")]
  376. [SerializeField]
  377. float m_CurrentPercent;
  378. bool m_Resizing;
  379. float m_MinPercent;
  380. float m_MaxPercent;
  381. public VerticalSplitter(float percent = .8f, float minPer = .2f, float maxPer = .9f)
  382. {
  383. m_CurrentPercent = percent;
  384. m_MinPercent = minPer;
  385. m_MaxPercent = maxPer;
  386. }
  387. public bool OnGUI(Rect content, out Rect top, out Rect bot)
  388. {
  389. m_Rect.x = content.x;
  390. m_Rect.y = (int)(content.y + content.height * m_CurrentPercent);
  391. m_Rect.width = content.width;
  392. EditorGUIUtility.AddCursorRect(m_Rect, MouseCursor.ResizeVertical);
  393. if (Event.current.type == EventType.MouseDown && m_Rect.Contains(Event.current.mousePosition))
  394. m_Resizing = true;
  395. if (m_Resizing)
  396. {
  397. EditorGUIUtility.AddCursorRect(content, MouseCursor.ResizeVertical);
  398. var mousePosInRect = Event.current.mousePosition.y - content.y;
  399. m_CurrentPercent = Mathf.Clamp(mousePosInRect / content.height, m_MinPercent, m_MaxPercent);
  400. m_Rect.y = Mathf.Min((int)(content.y + content.height * m_CurrentPercent), content.yMax - m_Rect.height);
  401. if (Event.current.type == EventType.MouseUp)
  402. m_Resizing = false;
  403. }
  404. top = new Rect(content.x, content.y, content.width, m_Rect.yMin - content.yMin);
  405. bot = new Rect(content.x, m_Rect.yMax, content.width, content.yMax - m_Rect.yMax);
  406. return m_Resizing;
  407. }
  408. }
  409. [Serializable]
  410. class HorizontalSplitter
  411. {
  412. [NonSerialized]
  413. Rect m_Rect = new Rect(0, 0, 3, 0);
  414. public Rect SplitterRect { get { return m_Rect; } }
  415. [FormerlySerializedAs("m_currentPercent")]
  416. [SerializeField]
  417. float m_CurrentPercent;
  418. bool m_Resizing;
  419. float m_MinPercent;
  420. float m_MaxPercent;
  421. public HorizontalSplitter(float percent = .8f, float minPer = .2f, float maxPer = .9f)
  422. {
  423. m_CurrentPercent = percent;
  424. m_MinPercent = minPer;
  425. m_MaxPercent = maxPer;
  426. }
  427. public bool OnGUI(Rect content, out Rect left, out Rect right)
  428. {
  429. m_Rect.y = content.y;
  430. m_Rect.x = (int)(content.x + content.width * m_CurrentPercent);
  431. m_Rect.height = content.height;
  432. EditorGUIUtility.AddCursorRect(m_Rect, MouseCursor.ResizeHorizontal);
  433. if (Event.current.type == EventType.MouseDown && m_Rect.Contains(Event.current.mousePosition))
  434. m_Resizing = true;
  435. if (m_Resizing)
  436. {
  437. EditorGUIUtility.AddCursorRect(content, MouseCursor.ResizeHorizontal);
  438. var mousePosInRect = Event.current.mousePosition.x - content.x;
  439. m_CurrentPercent = Mathf.Clamp(mousePosInRect / content.width, m_MinPercent, m_MaxPercent);
  440. m_Rect.x = Mathf.Min((int)(content.x + content.width * m_CurrentPercent), content.xMax - m_Rect.width);
  441. if (Event.current.type == EventType.MouseUp)
  442. m_Resizing = false;
  443. }
  444. left = new Rect(content.x, content.y, m_Rect.xMin, content.height);
  445. right = new Rect(m_Rect.xMax, content.y, content.width - m_Rect.xMax, content.height);
  446. return m_Resizing;
  447. }
  448. }
  449. }