Nav apraksta
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

BurstInspectorGUI.cs 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Runtime.CompilerServices;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using Unity.Burst.LowLevel;
  8. using UnityEditor;
  9. using UnityEditor.Compilation;
  10. using UnityEditor.IMGUI.Controls;
  11. using UnityEngine;
  12. [assembly: InternalsVisibleTo("Unity.Burst.Editor.Tests")]
  13. namespace Unity.Burst.Editor
  14. {
  15. internal enum AssemblyKind
  16. {
  17. RawNoDebugInformation,
  18. RawWithDebugInformation,
  19. EnhancedMinimalDebugInformation,
  20. EnhancedFullDebugInformation,
  21. ColouredMinimalDebugInformation,
  22. ColouredFullDebugInformation,
  23. }
  24. internal class BurstInspectorGUI : EditorWindow
  25. {
  26. private static bool Initialized;
  27. private static void EnsureInitialized()
  28. {
  29. if (Initialized)
  30. {
  31. return;
  32. }
  33. Initialized = true;
  34. #if UNITY_2020_2_OR_NEWER
  35. BurstLoader.OnBurstShutdown += () =>
  36. {
  37. if (EditorWindow.HasOpenInstances<BurstInspectorGUI>())
  38. {
  39. var window = EditorWindow.GetWindow<BurstInspectorGUI>("Burst Inspector");
  40. window.Close();
  41. }
  42. };
  43. #endif
  44. }
  45. private const string FontSizeIndexPref = "BurstInspectorFontSizeIndex";
  46. private static readonly string[] DisassemblyKindNames =
  47. {
  48. "Assembly",
  49. ".NET IL",
  50. "LLVM IR (Unoptimized)",
  51. "LLVM IR (Optimized)",
  52. "LLVM IR Optimisation Diagnostics"
  53. };
  54. private static readonly string[] AssemblyOptions =
  55. {
  56. "Plain (No debug information)",
  57. "Plain (With debug information)",
  58. "Enhanced (Minimal debug information)",
  59. "Enhanced (Full debug information)",
  60. "Coloured (Minimal debug information)",
  61. "Coloured (Full debug information)"
  62. };
  63. private static string[] DisasmOptions;
  64. private static string[] GetDisasmOptions()
  65. {
  66. if (DisasmOptions == null)
  67. {
  68. // We can't initialize this in BurstInspectorGUI.cctor because BurstCompilerOptions may not yet
  69. // have been initialized by BurstLoader. So we initialize on-demand here. This method doesn't need to
  70. // be thread-safe because it's only called from the UI thread.
  71. DisasmOptions = new[]
  72. {
  73. "\n" + BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDump, NativeDumpFlags.Asm),
  74. "\n" + BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDump, NativeDumpFlags.IL),
  75. "\n" + BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDump, NativeDumpFlags.IR),
  76. "\n" + BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDump, NativeDumpFlags.IROptimized),
  77. "\n" + BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDump, NativeDumpFlags.IRPassAnalysis)
  78. };
  79. }
  80. return DisasmOptions;
  81. }
  82. private static readonly SplitterState TreeViewSplitterState = new SplitterState(new float[] { 30, 70 }, new int[] { 128, 128 }, null);
  83. private static readonly string[] TargetCpuNames = Enum.GetNames(typeof(BurstTargetCpu));
  84. private static readonly int[] FontSizes =
  85. {
  86. 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20
  87. };
  88. private static string[] _fontSizesText;
  89. [NonSerialized]
  90. private readonly BurstDisassembler _burstDisassembler;
  91. [SerializeField] private BurstTargetCpu _targetCpu = BurstTargetCpu.Auto;
  92. [SerializeField] private DisassemblyKind _disasmKind = DisassemblyKind.Asm;
  93. [NonSerialized]
  94. private GUIStyle _fixedFontStyle;
  95. [NonSerialized]
  96. private int _fontSizeIndex = -1;
  97. [SerializeField] private int _previousTargetIndex = -1;
  98. [SerializeField] private bool _safetyChecks = false;
  99. [SerializeField] private bool _enhancedDisassembly = true;
  100. [SerializeField] private int _assemblyKind = -1;
  101. [SerializeField] private string _searchFilter;
  102. private int _assemblyKindPrior = -1;
  103. private bool _sameTargetButDifferentAssemblyKind = false;
  104. [SerializeField] private Vector2 _scrollPos;
  105. private SearchField _searchField;
  106. [SerializeField] private string _selectedItem;
  107. [NonSerialized]
  108. private List<BurstCompileTarget> _targets;
  109. [NonSerialized]
  110. private LongTextArea _textArea;
  111. [NonSerialized]
  112. private Font _font;
  113. [NonSerialized]
  114. private BurstMethodTreeView _treeView;
  115. [NonSerialized]
  116. private bool _initialized;
  117. [NonSerialized]
  118. private bool _requiresRepaint;
  119. private int FontSize => FontSizes[_fontSizeIndex];
  120. public BurstInspectorGUI()
  121. {
  122. _burstDisassembler = new BurstDisassembler();
  123. _assemblyKindPrior = _assemblyKind;
  124. }
  125. public void OnEnable()
  126. {
  127. EnsureInitialized();
  128. if (_treeView == null) _treeView = new BurstMethodTreeView(new TreeViewState(), () => _searchFilter);
  129. var assemblyList = BurstReflection.EditorAssembliesThatCanPossiblyContainJobs;
  130. Task.Run(
  131. () =>
  132. {
  133. // Do this stuff asynchronously.
  134. var result = BurstReflection.FindExecuteMethods(assemblyList, BurstReflectionAssemblyOptions.None);
  135. _targets = result.CompileTargets;
  136. _targets.Sort((left, right) => string.Compare(left.GetDisplayName(), right.GetDisplayName(), StringComparison.Ordinal));
  137. return result;
  138. })
  139. .ContinueWith(t =>
  140. {
  141. // Do this stuff on the main (UI) thread.
  142. if (t.Status == TaskStatus.RanToCompletion)
  143. {
  144. foreach (var logMessage in t.Result.LogMessages)
  145. {
  146. switch (logMessage.LogType)
  147. {
  148. case BurstReflection.LogType.Warning:
  149. Debug.LogWarning(logMessage.Message);
  150. break;
  151. case BurstReflection.LogType.Exception:
  152. Debug.LogException(logMessage.Exception);
  153. break;
  154. default:
  155. throw new InvalidOperationException();
  156. }
  157. }
  158. _treeView.Targets = _targets;
  159. _treeView.Reload();
  160. if (_selectedItem == null || !_treeView.TrySelectByDisplayName(_selectedItem))
  161. {
  162. _previousTargetIndex = -1;
  163. _scrollPos = Vector2.zero;
  164. }
  165. _requiresRepaint = true;
  166. _initialized = true;
  167. }
  168. else if (t.Exception != null)
  169. {
  170. Debug.LogError($"Could not load Inspector: {t.Exception}");
  171. }
  172. });
  173. }
  174. private void CleanupFont()
  175. {
  176. if (_font != null)
  177. {
  178. DestroyImmediate(_font, true);
  179. _font = null;
  180. }
  181. }
  182. public void OnDisable()
  183. {
  184. CleanupFont();
  185. }
  186. public void Update()
  187. {
  188. // Need to do this because if we call Repaint from anywhere else,
  189. // it doesn't do anything if this window is not currently focused.
  190. if (_requiresRepaint)
  191. {
  192. Repaint();
  193. _requiresRepaint = false;
  194. }
  195. }
  196. private void FlowToNewLine(ref float remainingWidth, float resetWidth, GUIStyle style, GUIContent content)
  197. {
  198. float spaceRemainingBeforeNewLine = EditorStyles.toggle.CalcSize(new GUIContent("WWWW")).x;
  199. remainingWidth -= style.CalcSize(content).x;
  200. if (remainingWidth <= spaceRemainingBeforeNewLine)
  201. {
  202. remainingWidth = resetWidth;
  203. GUILayout.EndHorizontal();
  204. GUILayout.BeginHorizontal();
  205. }
  206. }
  207. private bool IsRaw(AssemblyKind kind)
  208. {
  209. return kind == AssemblyKind.RawNoDebugInformation || kind == AssemblyKind.RawWithDebugInformation;
  210. }
  211. private bool IsEnhanced(AssemblyKind kind)
  212. {
  213. return !IsRaw(kind);
  214. }
  215. private bool IsColoured(AssemblyKind kind)
  216. {
  217. return kind == AssemblyKind.ColouredMinimalDebugInformation || kind == AssemblyKind.ColouredFullDebugInformation;
  218. }
  219. private void RenderButtonBars(float width, BurstCompileTarget target, out bool doCopy, out int fontIndex)
  220. {
  221. float remainingWidth = width;
  222. var contentDisasm = new GUIContent("Enhanced Disassembly");
  223. var contentSafety = new GUIContent("Safety Checks");
  224. var contentCodeGenOptions = new GUIContent("Auto");
  225. var contentLabelFontSize = new GUIContent("Font Size");
  226. var contentFontSize = new GUIContent("99");
  227. var contentCopyToClip = new GUIContent("Copy to Clipboard");
  228. GUILayout.BeginHorizontal();
  229. _assemblyKind = EditorGUILayout.Popup(_assemblyKind, AssemblyOptions, EditorStyles.popup);
  230. FlowToNewLine(ref remainingWidth, width, EditorStyles.popup, contentDisasm);
  231. _safetyChecks = GUILayout.Toggle(_safetyChecks, contentSafety, EditorStyles.toggle);
  232. FlowToNewLine(ref remainingWidth, width, EditorStyles.toggle, contentSafety);
  233. EditorGUI.BeginDisabledGroup(!target.HasRequiredBurstCompileAttributes);
  234. _targetCpu = (BurstTargetCpu)EditorGUILayout.Popup((int)_targetCpu, TargetCpuNames, EditorStyles.popup);
  235. FlowToNewLine(ref remainingWidth, width, EditorStyles.popup, contentCodeGenOptions);
  236. GUILayout.Label("Font Size", EditorStyles.label);
  237. fontIndex = EditorGUILayout.Popup(_fontSizeIndex, _fontSizesText, EditorStyles.popup);
  238. FlowToNewLine(ref remainingWidth, width, EditorStyles.label,contentLabelFontSize);
  239. FlowToNewLine(ref remainingWidth, width, EditorStyles.popup,contentFontSize);
  240. doCopy = GUILayout.Button(contentCopyToClip, EditorStyles.miniButton);
  241. FlowToNewLine(ref remainingWidth, width, EditorStyles.miniButton,contentCopyToClip);
  242. EditorGUI.EndDisabledGroup();
  243. GUILayout.EndHorizontal();
  244. _disasmKind = (DisassemblyKind) GUILayout.Toolbar((int) _disasmKind, DisassemblyKindNames, GUILayout.ExpandWidth(true), GUILayout.MinWidth(5*10));
  245. }
  246. public void OnGUI()
  247. {
  248. if (!_initialized)
  249. {
  250. GUILayout.BeginHorizontal();
  251. GUILayout.FlexibleSpace();
  252. GUILayout.BeginVertical();
  253. GUILayout.FlexibleSpace();
  254. GUILayout.Label("Loading...");
  255. GUILayout.FlexibleSpace();
  256. GUILayout.EndVertical();
  257. GUILayout.FlexibleSpace();
  258. GUILayout.EndHorizontal();
  259. return;
  260. }
  261. // Make sure that editor options are synchronized
  262. BurstEditorOptions.EnsureSynchronized();
  263. if (_fontSizesText == null)
  264. {
  265. _fontSizesText = new string[FontSizes.Length];
  266. for (var i = 0; i < FontSizes.Length; ++i) _fontSizesText[i] = FontSizes[i].ToString();
  267. }
  268. if (_fontSizeIndex == -1)
  269. {
  270. _fontSizeIndex = EditorPrefs.GetInt(FontSizeIndexPref, 5);
  271. _fontSizeIndex = Math.Max(0, _fontSizeIndex);
  272. _fontSizeIndex = Math.Min(_fontSizeIndex, FontSizes.Length - 1);
  273. }
  274. if (_fixedFontStyle == null)
  275. {
  276. _fixedFontStyle = new GUIStyle(GUI.skin.label);
  277. string fontName;
  278. if (Application.platform == RuntimePlatform.WindowsEditor)
  279. fontName = "Consolas";
  280. else
  281. fontName = "Courier";
  282. CleanupFont();
  283. _font = Font.CreateDynamicFontFromOSFont(fontName, FontSize);
  284. _fixedFontStyle.font = _font;
  285. _fixedFontStyle.fontSize = FontSize;
  286. }
  287. if (_searchField == null) _searchField = new SearchField();
  288. if (_textArea == null) _textArea = new LongTextArea();
  289. GUILayout.BeginHorizontal();
  290. // SplitterGUILayout.BeginHorizontalSplit is internal in Unity but we don't have much choice
  291. SplitterGUILayout.BeginHorizontalSplit(TreeViewSplitterState);
  292. GUILayout.BeginVertical(GUILayout.Width(position.width / 3));
  293. GUILayout.Label("Compile Targets", EditorStyles.boldLabel);
  294. var newFilter = _searchField.OnGUI(_searchFilter);
  295. if (newFilter != _searchFilter)
  296. {
  297. _searchFilter = newFilter;
  298. _treeView.Reload();
  299. }
  300. _treeView.OnGUI(GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, GUILayout.ExpandHeight(true), GUILayout.ExpandWidth(true)));
  301. var lastRectSize = GUILayoutUtility.GetLastRect();
  302. GUILayout.EndVertical();
  303. GUILayout.BeginVertical();
  304. var selection = _treeView.GetSelection();
  305. if (selection.Count == 1)
  306. {
  307. var targetIndex = selection[0];
  308. var target = _targets[targetIndex - 1];
  309. var targetOptions = target.Options;
  310. // Stash selected item name to handle domain reloads more gracefully
  311. _selectedItem = target.GetDisplayName();
  312. if (_assemblyKind == -1)
  313. {
  314. if (_enhancedDisassembly)
  315. {
  316. _assemblyKind = (int)AssemblyKind.ColouredMinimalDebugInformation;
  317. }
  318. else
  319. {
  320. _assemblyKind = (int)AssemblyKind.RawNoDebugInformation;
  321. }
  322. }
  323. // Refresh if any options are changed
  324. bool doCopy;
  325. int fontSize;
  326. // -14 to add a little bit of space for the vertical scrollbar to display correctly
  327. RenderButtonBars((position.width*2)/3 - 14, target, out doCopy, out fontSize);
  328. var supportsEnhancedRendering = _disasmKind == DisassemblyKind.Asm || _disasmKind == DisassemblyKind.OptimizedIR || _disasmKind == DisassemblyKind.UnoptimizedIR;
  329. // We are currently formatting only Asm output
  330. var isTextFormatted = IsEnhanced((AssemblyKind)_assemblyKind) && supportsEnhancedRendering;
  331. // Depending if we are formatted or not, we don't render the same text
  332. var textToRender = isTextFormatted ? target.FormattedDisassembly : target.RawDisassembly;
  333. // Only refresh if we are switching to a new selection that hasn't been disassembled yet
  334. // Or we are changing disassembly settings (safety checks / enhanced disassembly)
  335. var targetRefresh = textToRender == null
  336. || target.DisassemblyKind != _disasmKind
  337. || targetOptions.EnableBurstSafetyChecks != _safetyChecks
  338. || target.TargetCpu != _targetCpu
  339. || target.IsDarkMode != EditorGUIUtility.isProSkin;
  340. bool targetChanged = _previousTargetIndex != targetIndex;
  341. _previousTargetIndex = targetIndex;
  342. if (_assemblyKindPrior != _assemblyKind)
  343. {
  344. targetRefresh = true;
  345. _assemblyKindPrior = _assemblyKind; // Needs to be refreshed, as we need to change disassembly options
  346. // If the target did not changed but our assembly kind did, we need to remember this.
  347. if (!targetChanged)
  348. {
  349. _sameTargetButDifferentAssemblyKind = true;
  350. }
  351. }
  352. // If the previous target changed the assembly kind and we have a target change, we need to
  353. // refresh the assembly because we'll have cached the previous assembly kinds output rather
  354. // than the one requested.
  355. if (_sameTargetButDifferentAssemblyKind && targetChanged)
  356. {
  357. targetRefresh = true;
  358. _sameTargetButDifferentAssemblyKind = false;
  359. }
  360. if (targetRefresh)
  361. {
  362. // TODO: refactor this code with a proper AppendOption to avoid these "\n"
  363. var options = new StringBuilder();
  364. target.TargetCpu = _targetCpu;
  365. target.DisassemblyKind = _disasmKind;
  366. targetOptions.EnableBurstSafetyChecks = _safetyChecks;
  367. target.IsDarkMode = EditorGUIUtility.isProSkin;
  368. targetOptions.EnableBurstCompileSynchronously = true;
  369. string defaultOptions;
  370. if (targetOptions.TryGetOptions(target.IsStaticMethod ? (MemberInfo)target.Method : target.JobType, true, out defaultOptions))
  371. {
  372. options.Append(defaultOptions);
  373. // Disables the 2 current warnings generated from code (since they clutter up the inspector display)
  374. // BC1370 - throw inside code not guarded with ConditionalSafetyCheck attribute
  375. // BC1322 - loop intrinsic on loop that has been optimised away
  376. options.Append($"\n{BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDisableWarnings, "BC1370;BC1322")}");
  377. options.AppendFormat("\n" + BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionTarget, TargetCpuNames[(int)_targetCpu]));
  378. switch ((AssemblyKind)_assemblyKind)
  379. {
  380. case AssemblyKind.EnhancedMinimalDebugInformation:
  381. case AssemblyKind.ColouredMinimalDebugInformation:
  382. options.AppendFormat("\n" + BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDebug, "2"));
  383. break;
  384. case AssemblyKind.ColouredFullDebugInformation:
  385. case AssemblyKind.EnhancedFullDebugInformation:
  386. case AssemblyKind.RawWithDebugInformation:
  387. options.AppendFormat("\n" + BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDebug, "1"));
  388. break;
  389. default:
  390. case AssemblyKind.RawNoDebugInformation:
  391. break;
  392. }
  393. options.AppendFormat("\n" + BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionJitSkipBurstInitialize));
  394. var baseOptions = options.ToString().Trim('\n', ' ');
  395. target.RawDisassembly = GetDisassembly(target.Method, baseOptions + GetDisasmOptions()[(int)_disasmKind]);
  396. if (isTextFormatted)
  397. {
  398. target.FormattedDisassembly = _burstDisassembler.Process(target.RawDisassembly, FetchAsmKind(_targetCpu, _disasmKind), target.IsDarkMode, IsColoured((AssemblyKind)_assemblyKind));
  399. textToRender = target.FormattedDisassembly;
  400. }
  401. else
  402. {
  403. target.FormattedDisassembly = null;
  404. textToRender = target.RawDisassembly;
  405. }
  406. }
  407. }
  408. if (textToRender != null)
  409. {
  410. _textArea.Text = textToRender;
  411. if (targetChanged) _scrollPos = Vector2.zero;
  412. _scrollPos = GUILayout.BeginScrollView(_scrollPos, true, true);
  413. _textArea.Render(_fixedFontStyle, _scrollPos, lastRectSize);
  414. GUILayout.EndScrollView();
  415. }
  416. if (doCopy)
  417. {
  418. // When copying to the clipboard, we copy the version the user sees
  419. EditorGUIUtility.systemCopyBuffer = textToRender ?? string.Empty;
  420. }
  421. if (fontSize != _fontSizeIndex)
  422. {
  423. _textArea.Invalidate();
  424. _fontSizeIndex = fontSize;
  425. EditorPrefs.SetInt(FontSizeIndexPref, fontSize);
  426. _fixedFontStyle = null;
  427. }
  428. }
  429. GUILayout.EndVertical();
  430. SplitterGUILayout.EndHorizontalSplit();
  431. GUILayout.EndHorizontal();
  432. }
  433. private static string GetDisassembly(MethodInfo method, string options)
  434. {
  435. try
  436. {
  437. var result = BurstCompilerService.GetDisassembly(method, options);
  438. if (result.IndexOf('\t') >= 0)
  439. {
  440. result = result.Replace("\t", " ");
  441. }
  442. // Workaround to remove timings
  443. if (result.Contains("Burst timings"))
  444. {
  445. var index = result.IndexOf("While compiling", StringComparison.Ordinal);
  446. if (index > 0)
  447. {
  448. result = result.Substring(index);
  449. }
  450. }
  451. return result;
  452. }
  453. catch (Exception e)
  454. {
  455. return "Failed to compile:\n" + e.Message;
  456. }
  457. }
  458. private static BurstDisassembler.AsmKind FetchAsmKind(BurstTargetCpu cpu, DisassemblyKind kind)
  459. {
  460. if (kind == DisassemblyKind.Asm)
  461. {
  462. switch (cpu)
  463. {
  464. case BurstTargetCpu.ARMV7A_NEON32:
  465. case BurstTargetCpu.ARMV8A_AARCH64:
  466. case BurstTargetCpu.ARMV8A_AARCH64_HALFFP:
  467. case BurstTargetCpu.THUMB2_NEON32:
  468. return BurstDisassembler.AsmKind.ARM;
  469. case BurstTargetCpu.WASM32:
  470. return BurstDisassembler.AsmKind.Wasm;
  471. }
  472. return BurstDisassembler.AsmKind.Intel;
  473. }
  474. else
  475. {
  476. return BurstDisassembler.AsmKind.LLVMIR;
  477. }
  478. }
  479. }
  480. internal class BurstMethodTreeView : TreeView
  481. {
  482. private readonly Func<string> _getFilter;
  483. public BurstMethodTreeView(TreeViewState state, Func<string> getFilter) : base(state)
  484. {
  485. _getFilter = getFilter;
  486. showBorder = true;
  487. }
  488. public List<BurstCompileTarget> Targets { get; set; }
  489. protected override TreeViewItem BuildRoot()
  490. {
  491. var root = new TreeViewItem {id = 0, depth = -1, displayName = "Root"};
  492. var allItems = new List<TreeViewItem>();
  493. if (Targets != null)
  494. {
  495. allItems.Capacity = Targets.Count;
  496. var id = 1;
  497. var filter = _getFilter();
  498. foreach (var t in Targets)
  499. {
  500. var displayName = t.GetDisplayName();
  501. if (string.IsNullOrEmpty(filter) || displayName.IndexOf(filter, 0, displayName.Length, StringComparison.InvariantCultureIgnoreCase) >= 0)
  502. allItems.Add(new TreeViewItem {id = id, depth = 0, displayName = displayName});
  503. ++id;
  504. }
  505. }
  506. SetupParentsAndChildrenFromDepths(root, allItems);
  507. return root;
  508. }
  509. internal bool TrySelectByDisplayName(string name)
  510. {
  511. var id = 1;
  512. foreach (var t in Targets)
  513. {
  514. if (t.GetDisplayName() == name)
  515. {
  516. SetSelection(new[] { id });
  517. FrameItem(id);
  518. return true;
  519. }
  520. else
  521. {
  522. ++id;
  523. }
  524. }
  525. return false;
  526. }
  527. protected override void RowGUI(RowGUIArgs args)
  528. {
  529. var target = Targets[args.item.id - 1];
  530. var wasEnabled = GUI.enabled;
  531. GUI.enabled = target.HasRequiredBurstCompileAttributes;
  532. base.RowGUI(args);
  533. GUI.enabled = wasEnabled;
  534. }
  535. protected override bool CanMultiSelect(TreeViewItem item)
  536. {
  537. return false;
  538. }
  539. }
  540. }