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.

BurstPlatformAotSettings.cs 35KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. #if UNITY_EDITOR
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.IO;
  5. using System;
  6. using System.Text;
  7. using UnityEditor;
  8. using UnityEditor.Build;
  9. using UnityEditor.Build.Reporting;
  10. using UnityEngine;
  11. using UnityEngine.UIElements;
  12. namespace Unity.Burst.Editor
  13. {
  14. internal enum DebugDataKind
  15. {
  16. LineOnly,
  17. Full
  18. }
  19. internal enum AvailX86Targets
  20. {
  21. SSE2 = (int)BurstTargetCpu.X86_SSE2,
  22. SSE4 = (int)BurstTargetCpu.X86_SSE4,
  23. }
  24. [Flags]
  25. internal enum BitsetX86Targets
  26. {
  27. SSE2 = 1 << AvailX86Targets.SSE2,
  28. SSE4 = 1 << AvailX86Targets.SSE4,
  29. }
  30. internal enum AvailX64Targets
  31. {
  32. SSE2 = (int)BurstTargetCpu.X64_SSE2,
  33. SSE4 = (int)BurstTargetCpu.X64_SSE4,
  34. AVX = (int)BurstTargetCpu.AVX,
  35. AVX2 = (int)BurstTargetCpu.AVX2,
  36. }
  37. [Flags]
  38. internal enum BitsetX64Targets
  39. {
  40. SSE2 = 1 << AvailX64Targets.SSE2,
  41. SSE4 = 1 << AvailX64Targets.SSE4,
  42. AVX = 1 << AvailX64Targets.AVX,
  43. AVX2 = 1 << AvailX64Targets.AVX2,
  44. }
  45. internal enum AvailArm64Targets
  46. {
  47. ARMV8A = BurstTargetCpu.ARMV8A_AARCH64,
  48. ARMV8A_HALFFP = BurstTargetCpu.ARMV8A_AARCH64_HALFFP,
  49. ARMV9A = BurstTargetCpu.ARMV9A,
  50. }
  51. [Flags]
  52. internal enum BitsetArm64Targets
  53. {
  54. ARMV8A = 1 << AvailArm64Targets.ARMV8A,
  55. ARMV8A_HALFFP = 1 << AvailArm64Targets.ARMV8A_HALFFP,
  56. ARMV9A = 1 << AvailArm64Targets.ARMV9A,
  57. }
  58. [AttributeUsage(AttributeTargets.Field)]
  59. internal class BurstMetadataSettingAttribute : Attribute { }
  60. [AttributeUsage(AttributeTargets.Field)]
  61. internal class BurstCommonSettingAttribute : Attribute {}
  62. class BurstPlatformLegacySettings : ScriptableObject
  63. {
  64. [SerializeField]
  65. internal bool DisableOptimisations;
  66. [SerializeField]
  67. internal bool DisableSafetyChecks;
  68. [SerializeField]
  69. internal bool DisableBurstCompilation;
  70. BurstPlatformLegacySettings(BuildTarget target)
  71. {
  72. DisableSafetyChecks = true;
  73. DisableBurstCompilation = false;
  74. DisableOptimisations = false;
  75. }
  76. }
  77. // To add a setting,
  78. // Add a
  79. // [SerializeField] internal type settingname;
  80. // Add a
  81. // internal static readonly string settingname_DisplayName = "Name of option to be displayed in the editor (and searched for)";
  82. // Add a
  83. // internal static readonly string settingname_ToolTip = "tool tip information to display when hovering mouse
  84. // If the setting should be restricted to e.g. Standalone platform :
  85. //
  86. // Add a
  87. // internal static bool settingname_Display(BuildTarget selectedTarget, string architecture) {}
  88. //
  89. // Add a
  90. // internal static bool settingname_Serialise(BuildTarget selectedTarget) {}
  91. class BurstPlatformAotSettings : ScriptableObject
  92. {
  93. [SerializeField]
  94. [BurstMetadataSetting] // We always need version to be in our saved settings!
  95. internal int Version;
  96. [SerializeField]
  97. internal bool EnableBurstCompilation;
  98. [SerializeField]
  99. internal bool EnableOptimisations;
  100. [SerializeField]
  101. internal bool EnableSafetyChecks;
  102. [SerializeField]
  103. internal bool EnableDebugInAllBuilds;
  104. [SerializeField]
  105. internal DebugDataKind DebugDataKind;
  106. [SerializeField]
  107. internal bool UsePlatformSDKLinker;
  108. [SerializeField]
  109. internal bool EnableArmv9SecurityFeatures;
  110. [SerializeField]
  111. internal AvailX86Targets CpuMinTargetX32;
  112. [SerializeField]
  113. internal AvailX86Targets CpuMaxTargetX32;
  114. [SerializeField]
  115. internal AvailX64Targets CpuMinTargetX64;
  116. [SerializeField]
  117. internal AvailX64Targets CpuMaxTargetX64;
  118. [SerializeField]
  119. internal BitsetX86Targets CpuTargetsX32;
  120. [SerializeField]
  121. internal BitsetX64Targets CpuTargetsX64;
  122. [SerializeField]
  123. internal BitsetArm64Targets CpuTargetsArm64;
  124. [SerializeField]
  125. internal OptimizeFor OptimizeFor;
  126. [SerializeField]
  127. [BurstCommonSetting]
  128. internal string DisabledWarnings;
  129. internal static readonly string EnableDebugInAllBuilds_DisplayName = "Force Debug Information";
  130. internal static readonly string EnableDebugInAllBuilds_ToolTip = "Generates debug information for the Burst-compiled code, irrespective of if Development Mode is ticked. This can be used to generate symbols for release builds for platforms that need it.";
  131. internal static readonly string DebugDataKind_DisplayName = "Debug Information Kind";
  132. internal static readonly string DebugDataKind_ToolTip = "Choose which kind of debug information you want present in builds with debug information enabled.";
  133. internal static readonly string EnableOptimisations_DisplayName = "Enable Optimizations";
  134. internal static readonly string EnableOptimisations_ToolTip = "Enables all optimizations for the currently selected platform.";
  135. internal static readonly string EnableBurstCompilation_DisplayName = "Enable Burst Compilation";
  136. internal static readonly string EnableBurstCompilation_ToolTip = "Enables burst compilation for the selected platform.";
  137. internal static readonly string OptimizeFor_DisplayName = "Optimize For";
  138. internal static readonly string OptimizeFor_ToolTip = "Choose what optimization setting to compile Burst code for.";
  139. internal static readonly string DisabledWarnings_DisplayName = "Disabled Warnings*";
  140. internal static readonly string DisabledWarnings_ToolTip = "Burst warnings to disable (separated by ;).";
  141. internal static readonly string UsePlatformSDKLinker_DisplayName = "Use Platform SDK Linker";
  142. internal static readonly string UsePlatformSDKLinker_ToolTip = "Enabling this option will disable cross compilation support for desktops, and will require platform specific tools for Windows/Linux/Mac - use only if you encounter problems with the burst builtin solution.";
  143. // We do not support this option anymore, so the easiest thing is to just not display it.
  144. internal static bool UsePlatformSDKLinker_Display(BuildTarget selectedTarget, string architecture) => false;
  145. internal static bool UsePlatformSDKLinker_Serialise(BuildTarget selectedTarget) => false;
  146. internal static readonly string CpuTargetsX32_DisplayName = "Target 32Bit CPU Architectures";
  147. internal static readonly string CpuTargetsX32_ToolTip = "Use this to specify the set of target architectures to support for the currently selected platform.";
  148. internal static bool CpuTargetsX32_Display(BuildTarget selectedTarget, string architecture)
  149. {
  150. return (IsStandalone(selectedTarget) || selectedTarget == BuildTarget.WSAPlayer) && Has32BitSupport(selectedTarget);
  151. }
  152. internal static bool CpuTargetsX32_Serialise(BuildTarget selectedTarget)
  153. {
  154. return (IsStandalone(selectedTarget) || selectedTarget == BuildTarget.WSAPlayer) && Has32BitSupportForSerialise(selectedTarget);
  155. }
  156. internal static readonly string CpuTargetsX64_DisplayName = "Target 64Bit CPU Architectures";
  157. internal static readonly string CpuTargetsX64_ToolTip = "Use this to specify the target architectures to support for the currently selected platform.";
  158. internal static bool CpuTargetsX64_Display(BuildTarget selectedTarget, string architecture)
  159. {
  160. return (IsStandalone(selectedTarget) || selectedTarget == BuildTarget.WSAPlayer)
  161. && Has64BitSupport(selectedTarget)
  162. && (selectedTarget != BuildTarget.StandaloneOSX || architecture != "arm64");
  163. }
  164. internal static bool CpuTargetsX64_Serialise(BuildTarget selectedTarget)
  165. {
  166. return IsStandalone(selectedTarget) || selectedTarget == BuildTarget.WSAPlayer;
  167. }
  168. internal static readonly string CpuTargetsArm64_DisplayName = "Target Arm 64Bit CPU Architectures";
  169. internal static readonly string CpuTargetsArm64_ToolTip = "Use this to specify the target architectures to support for the currently selected platform.";
  170. internal static bool CpuTargetsArm64_Display(BuildTarget selectedTarget, string architecture)
  171. {
  172. return selectedTarget == BuildTarget.Android;
  173. }
  174. internal static bool CpuTargetsArm64_Serialise(BuildTarget selectedTarget)
  175. {
  176. return selectedTarget == BuildTarget.Android;
  177. }
  178. internal static bool IsStandalone(BuildTarget target)
  179. {
  180. switch (target)
  181. {
  182. case BuildTarget.StandaloneLinux64:
  183. case BuildTarget.StandaloneWindows:
  184. case BuildTarget.StandaloneWindows64:
  185. case BuildTarget.StandaloneOSX:
  186. return true;
  187. default:
  188. return false;
  189. }
  190. }
  191. BurstPlatformAotSettings(BuildTarget target)
  192. {
  193. InitialiseDefaults();
  194. }
  195. private const int DefaultVersion = 4;
  196. internal void InitialiseDefaults()
  197. {
  198. Version = DefaultVersion;
  199. EnableSafetyChecks = false;
  200. EnableBurstCompilation = true;
  201. EnableOptimisations = true;
  202. EnableDebugInAllBuilds = false;
  203. DebugDataKind = DebugDataKind.Full;
  204. UsePlatformSDKLinker = false; // Only applicable for desktop targets (Windows/Mac/Linux)
  205. CpuMinTargetX32 = 0;
  206. CpuMaxTargetX32 = 0;
  207. CpuMinTargetX64 = 0;
  208. CpuMaxTargetX64 = 0;
  209. CpuTargetsX32 = BitsetX86Targets.SSE2 | BitsetX86Targets.SSE4;
  210. CpuTargetsX64 = BitsetX64Targets.SSE2 | BitsetX64Targets.AVX2;
  211. CpuTargetsArm64 = BitsetArm64Targets.ARMV8A;
  212. DisabledWarnings = "";
  213. OptimizeFor = OptimizeFor.Default;
  214. }
  215. internal static string GetPath(BuildTarget? target)
  216. {
  217. if (target.HasValue)
  218. {
  219. return "ProjectSettings/BurstAotSettings_" + target.ToString() + ".json";
  220. }
  221. else
  222. {
  223. return "ProjectSettings/CommonBurstAotSettings.json";
  224. }
  225. }
  226. internal static BuildTarget? ResolveTarget(BuildTarget? target)
  227. {
  228. if (!target.HasValue)
  229. {
  230. return target;
  231. }
  232. // Treat the 32/64 platforms the same from the point of view of burst settings
  233. // since there is no real way to distinguish from the platforms selector
  234. if (target == BuildTarget.StandaloneWindows64 || target == BuildTarget.StandaloneWindows)
  235. return BuildTarget.StandaloneWindows;
  236. // 32 bit linux support was deprecated
  237. if (target == BuildTarget.StandaloneLinux64)
  238. return BuildTarget.StandaloneLinux64;
  239. return target;
  240. }
  241. private static bool IsOutputPathToBuildFolder(BuildSummary summary) =>
  242. Directory.Exists(summary.outputPath) // Path to either an executable or the specified build folder.
  243. && summary.platform != BuildTarget.StandaloneOSX; // For MacOSX the folder pointed to is the .app folder
  244. // that is contained within the build folder.
  245. private static string FetchBuildFolder(BuildSummary summary)
  246. {
  247. // Trouble is that it differs based on the build target whether summary refers to:
  248. // - A specific executable.
  249. // - The folder being build to.
  250. // No matter what, we want to place the debug information directory inside of this build
  251. // folder.
  252. var outputPath = summary.outputPath;
  253. return IsOutputPathToBuildFolder(summary)
  254. ? outputPath // outputPath = <path-to-build-directory>
  255. : Path.GetDirectoryName(outputPath); // outputPath = <path-to-executable>
  256. }
  257. internal static readonly string BurstMiscPathPostFix = "_BurstDebugInformation_DoNotShip";
  258. internal static string FetchOutputPath(BuildSummary summary, string productName)
  259. {
  260. var burstMiscFolderName = $"{productName}{BurstMiscPathPostFix}";
  261. var finalOutputPath = FetchBuildFolder(summary);
  262. return Path.Combine(finalOutputPath, burstMiscFolderName);
  263. }
  264. internal static BurstPlatformAotSettings GetOrCreateSettings(BuildTarget? target)
  265. {
  266. target = ResolveTarget(target);
  267. var settings = CreateInstance<BurstPlatformAotSettings>();
  268. settings.InitialiseDefaults();
  269. string path = GetPath(target);
  270. var fileExists = File.Exists(path);
  271. var upgraded = false;
  272. if (fileExists)
  273. {
  274. var json = File.ReadAllText(path);
  275. settings = SerialiseIn(target, json, out upgraded);
  276. }
  277. if (!fileExists || upgraded)
  278. {
  279. // If the settings file didn't previously exist,
  280. // or it did exist but we've just upgraded it to a new version,
  281. // save it to disk now.
  282. settings.Save(target);
  283. }
  284. // Overwrite the settings with any that are common and shared between all settings.
  285. if (target.HasValue)
  286. {
  287. var commonSettings = GetOrCreateSettings(null);
  288. var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
  289. foreach (var field in platformFields)
  290. {
  291. if (null != field.GetCustomAttribute<BurstCommonSettingAttribute>())
  292. {
  293. field.SetValue(settings, field.GetValue(commonSettings));
  294. }
  295. }
  296. }
  297. return settings;
  298. }
  299. delegate bool SerialiseItem(BuildTarget selectedPlatform);
  300. private static BurstPlatformAotSettings SerialiseIn(BuildTarget? target, string json, out bool upgraded)
  301. {
  302. var versioned = ScriptableObject.CreateInstance<BurstPlatformAotSettings>();
  303. EditorJsonUtility.FromJsonOverwrite(json, versioned);
  304. upgraded = false;
  305. if (versioned.Version == 0)
  306. {
  307. // Deal with pre versioned format
  308. var legacy = ScriptableObject.CreateInstance<BurstPlatformLegacySettings>();
  309. EditorJsonUtility.FromJsonOverwrite(json, legacy);
  310. // Legacy file, upgrade it
  311. versioned.InitialiseDefaults();
  312. versioned.EnableOptimisations = !legacy.DisableOptimisations;
  313. versioned.EnableBurstCompilation = !legacy.DisableBurstCompilation;
  314. versioned.EnableSafetyChecks = !legacy.DisableSafetyChecks;
  315. // Destroy the legacy object so Unity doesn't try to backup / restore it later during domain reload.
  316. ScriptableObject.DestroyImmediate(legacy);
  317. upgraded = true;
  318. }
  319. if (versioned.Version < 3)
  320. {
  321. // Upgrade the version first
  322. versioned.Version = 3;
  323. // Upgrade from min..max targets to bitset
  324. versioned.CpuTargetsX32 |= (BitsetX86Targets)(1 << (int)versioned.CpuMinTargetX32);
  325. versioned.CpuTargetsX32 |= (BitsetX86Targets)(1 << (int)versioned.CpuMaxTargetX32);
  326. versioned.CpuTargetsX64 |= (BitsetX64Targets)(1 << (int)versioned.CpuMinTargetX64);
  327. versioned.CpuTargetsX64 |= (BitsetX64Targets)(1 << (int)versioned.CpuMaxTargetX64);
  328. // Extra checks to add targets in the min..max range for 64-bit targets.
  329. switch (versioned.CpuMinTargetX64)
  330. {
  331. default:
  332. break;
  333. case AvailX64Targets.SSE2:
  334. switch (versioned.CpuMaxTargetX64)
  335. {
  336. default:
  337. break;
  338. case AvailX64Targets.AVX2:
  339. versioned.CpuTargetsX64 |= (BitsetX64Targets)(1 << (int)AvailX64Targets.AVX);
  340. goto case AvailX64Targets.AVX;
  341. case AvailX64Targets.AVX:
  342. versioned.CpuTargetsX64 |= (BitsetX64Targets)(1 << (int)AvailX64Targets.SSE4);
  343. break;
  344. }
  345. break;
  346. case AvailX64Targets.SSE4:
  347. switch (versioned.CpuMaxTargetX64)
  348. {
  349. default:
  350. break;
  351. case AvailX64Targets.AVX2:
  352. versioned.CpuTargetsX64 |= (BitsetX64Targets)(1 << (int)AvailX64Targets.AVX);
  353. break;
  354. }
  355. break;
  356. }
  357. // Wipe the old min/max targets
  358. versioned.CpuMinTargetX32 = 0;
  359. versioned.CpuMaxTargetX32 = 0;
  360. versioned.CpuMinTargetX64 = 0;
  361. versioned.CpuMaxTargetX64 = 0;
  362. upgraded = true;
  363. }
  364. if (versioned.Version < 4)
  365. {
  366. // Upgrade the version first.
  367. versioned.Version = 4;
  368. // When we upgrade we'll set the optimization level to default (which is, as expected, the default).
  369. versioned.OptimizeFor = OptimizeFor.Default;
  370. // This option has been removed as user-setting options, so switch them to false here.
  371. versioned.EnableSafetyChecks = false;
  372. upgraded = true;
  373. }
  374. // Otherwise should be a modern file with a valid version (we can use that to upgrade when the time comes)
  375. return versioned;
  376. }
  377. private static bool ShouldSerialiseOut(BuildTarget? target, FieldInfo field)
  378. {
  379. var method = typeof(BurstPlatformAotSettings).GetMethod(field.Name + "_Serialise", BindingFlags.Static | BindingFlags.NonPublic);
  380. if (method != null)
  381. {
  382. var shouldSerialise = (SerialiseItem)Delegate.CreateDelegate(typeof(SerialiseItem), method);
  383. if (!target.HasValue || !shouldSerialise(target.Value))
  384. {
  385. return false;
  386. }
  387. }
  388. // If we always need to write out the attribute, return now.
  389. if (null != field.GetCustomAttribute<BurstMetadataSettingAttribute>())
  390. {
  391. return true;
  392. }
  393. var isCommon = !target.HasValue;
  394. var hasCommonAttribute = null != field.GetCustomAttribute<BurstCommonSettingAttribute>();
  395. if ((isCommon && hasCommonAttribute) || (!isCommon && !hasCommonAttribute))
  396. {
  397. return true;
  398. }
  399. return false;
  400. }
  401. internal string SerialiseOut(BuildTarget? target)
  402. {
  403. // Version 2 and onwards serialise a custom object in order to avoid serialising all the settings.
  404. StringBuilder s = new StringBuilder();
  405. s.Append("{\n");
  406. s.Append(" \"MonoBehaviour\": {\n");
  407. var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
  408. int total = 0;
  409. for (int i = 0; i < platformFields.Length; i++)
  410. {
  411. if (ShouldSerialiseOut(target, platformFields[i]))
  412. {
  413. total++;
  414. }
  415. }
  416. for (int i = 0; i < platformFields.Length; i++)
  417. {
  418. if (ShouldSerialiseOut(target, platformFields[i]))
  419. {
  420. s.Append($" \"{platformFields[i].Name}\": ");
  421. if (platformFields[i].FieldType.IsEnum)
  422. s.Append((int)platformFields[i].GetValue(this));
  423. else if (platformFields[i].FieldType == typeof(string))
  424. s.Append($"\"{platformFields[i].GetValue(this)}\"");
  425. else if (platformFields[i].FieldType == typeof(bool))
  426. s.Append(((bool)platformFields[i].GetValue(this)) ? "true" : "false");
  427. else
  428. s.Append((int)platformFields[i].GetValue(this));
  429. total--;
  430. if (total != 0)
  431. s.Append(",");
  432. s.Append("\n");
  433. }
  434. }
  435. s.Append(" }\n");
  436. s.Append("}\n");
  437. return s.ToString();
  438. }
  439. internal void Save(BuildTarget? target)
  440. {
  441. if (target.HasValue)
  442. {
  443. target = ResolveTarget(target);
  444. }
  445. var path = GetPath(target);
  446. if (!AssetDatabase.IsOpenForEdit(path))
  447. {
  448. if (!AssetDatabase.MakeEditable(path))
  449. {
  450. Debug.LogWarning($"Burst could not save AOT settings file {path}");
  451. return;
  452. }
  453. }
  454. File.WriteAllText(path, SerialiseOut(target));
  455. }
  456. internal static SerializedObject GetCommonSerializedSettings()
  457. {
  458. return new SerializedObject(GetOrCreateSettings(null));
  459. }
  460. internal static SerializedObject GetSerializedSettings(BuildTarget target)
  461. {
  462. return new SerializedObject(GetOrCreateSettings(target));
  463. }
  464. internal static bool Has32BitSupport(BuildTarget target)
  465. {
  466. switch (target)
  467. {
  468. case BuildTarget.StandaloneWindows:
  469. case BuildTarget.WSAPlayer:
  470. return true;
  471. default:
  472. return false;
  473. }
  474. }
  475. internal static bool Has32BitSupportForSerialise(BuildTarget target)
  476. {
  477. switch (target)
  478. {
  479. case BuildTarget.StandaloneWindows:
  480. case BuildTarget.StandaloneWindows64:
  481. case BuildTarget.WSAPlayer:
  482. return true;
  483. default:
  484. return false;
  485. }
  486. }
  487. internal static bool Has64BitSupport(BuildTarget target)
  488. {
  489. switch (target)
  490. {
  491. case BuildTarget.StandaloneWindows64:
  492. case BuildTarget.WSAPlayer:
  493. case BuildTarget.StandaloneOSX:
  494. return true;
  495. default:
  496. return false;
  497. }
  498. }
  499. private static BurstTargetCpu GetCpu(int v)
  500. {
  501. // https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
  502. var r = ((v > 0xFFFF) ? 1 : 0) << 4; v >>= r;
  503. var shift = ((v > 0xFF) ? 1 : 0) << 3; v >>= shift; r |= shift;
  504. shift = ((v > 0xF) ? 1 : 0) << 2; v >>= shift; r |= shift;
  505. shift = ((v > 0x3) ? 1 : 0) << 1; v >>= shift; r |= shift;
  506. r |= (v >> 1);
  507. return (BurstTargetCpu)r;
  508. }
  509. private static IEnumerable<Enum> GetFlags(Enum input)
  510. {
  511. foreach (Enum value in Enum.GetValues(input.GetType()))
  512. {
  513. if (input.HasFlag(value))
  514. {
  515. yield return value;
  516. }
  517. }
  518. }
  519. internal TargetCpus GetDesktopCpu32Bit()
  520. {
  521. var cpus = new TargetCpus();
  522. foreach (var target in GetFlags(CpuTargetsX32))
  523. {
  524. cpus.Cpus.Add(GetCpu((int)(BitsetX86Targets)target));
  525. }
  526. // If no targets were specified just default to the oldest CPU supported.
  527. if (cpus.Cpus.Count == 0)
  528. {
  529. cpus.Cpus.Add(BurstTargetCpu.X86_SSE2);
  530. }
  531. return cpus;
  532. }
  533. internal TargetCpus GetDesktopCpu64Bit()
  534. {
  535. var cpus = new TargetCpus();
  536. foreach (var target in GetFlags(CpuTargetsX64))
  537. {
  538. cpus.Cpus.Add(GetCpu((int)(BitsetX64Targets)target));
  539. }
  540. // If no targets were specified just default to the oldest CPU supported.
  541. if (cpus.Cpus.Count == 0)
  542. {
  543. cpus.Cpus.Add(BurstTargetCpu.X64_SSE2);
  544. }
  545. return cpus;
  546. }
  547. internal TargetCpus GetAndroidCpuArm64()
  548. {
  549. var cpus = new TargetCpus();
  550. foreach (var target in GetFlags(CpuTargetsArm64))
  551. {
  552. cpus.Cpus.Add(GetCpu((int)(BitsetArm64Targets)target));
  553. }
  554. // If no targets were specified just default to the oldest CPU supported.
  555. if (cpus.Cpus.Count == 0)
  556. {
  557. cpus.Cpus.Add(BurstTargetCpu.ARMV8A_AARCH64);
  558. }
  559. return cpus;
  560. }
  561. }
  562. static class BurstAotSettingsIMGUIRegister
  563. {
  564. class BurstAotSettingsProvider : SettingsProvider
  565. {
  566. SerializedObject[] m_PlatformSettings;
  567. SerializedProperty[][] m_PlatformProperties;
  568. DisplayItem[][] m_PlatformVisibility;
  569. GUIContent[][] m_PlatformToolTips;
  570. BuildPlatform[] m_ValidPlatforms;
  571. SerializedObject m_CommonPlatformSettings;
  572. delegate bool DisplayItem(BuildTarget selectedTarget, string architecture);
  573. static bool DefaultShow(BuildTarget selectedTarget, string architecture)
  574. {
  575. return true;
  576. }
  577. static bool DefaultHide(BuildTarget selectedTarget, string architecture)
  578. {
  579. return false;
  580. }
  581. public BurstAotSettingsProvider()
  582. : base("Project/Burst AOT Settings", SettingsScope.Project, null)
  583. {
  584. int a;
  585. m_ValidPlatforms = BuildPlatforms.instance.GetValidPlatforms(true).ToArray();
  586. var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
  587. int numPlatformFields = platformFields.Length;
  588. int numKeywords = numPlatformFields;
  589. var tempKeywords = new string[numKeywords];
  590. for (a = 0; a < numPlatformFields; a++)
  591. {
  592. tempKeywords[a] = typeof(BurstPlatformAotSettings).GetField(platformFields[a].Name + "_ToolTip", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as string;
  593. }
  594. keywords = new HashSet<string>(tempKeywords);
  595. m_PlatformSettings = new SerializedObject[m_ValidPlatforms.Length];
  596. m_PlatformProperties = new SerializedProperty[m_ValidPlatforms.Length][];
  597. m_PlatformVisibility = new DisplayItem[m_ValidPlatforms.Length][];
  598. m_PlatformToolTips = new GUIContent[m_ValidPlatforms.Length][];
  599. m_CommonPlatformSettings = null;
  600. }
  601. public override void OnActivate(string searchContext, VisualElement rootElement)
  602. {
  603. var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
  604. for (int p = 0; p < m_ValidPlatforms.Length; p++)
  605. {
  606. InitialiseSettingsForCommon(platformFields);
  607. InitialiseSettingsForPlatform(p, platformFields);
  608. }
  609. }
  610. private void InitialiseSettingsForCommon(FieldInfo[] commonFields)
  611. {
  612. m_CommonPlatformSettings = BurstPlatformAotSettings.GetCommonSerializedSettings();
  613. }
  614. private void InitialiseSettingsForPlatform(int platform, FieldInfo[] platformFields)
  615. {
  616. if (m_ValidPlatforms[platform].targetGroup == BuildTargetGroup.Standalone)
  617. m_PlatformSettings[platform] = BurstPlatformAotSettings.GetSerializedSettings(EditorUserBuildSettings.selectedStandaloneTarget);
  618. else
  619. m_PlatformSettings[platform] = BurstPlatformAotSettings.GetSerializedSettings(m_ValidPlatforms[platform].defaultTarget);
  620. m_PlatformProperties[platform] = new SerializedProperty[platformFields.Length];
  621. m_PlatformToolTips[platform] = new GUIContent[platformFields.Length];
  622. m_PlatformVisibility[platform] = new DisplayItem[platformFields.Length];
  623. for (int i = 0; i < platformFields.Length; i++)
  624. {
  625. m_PlatformProperties[platform][i] = m_PlatformSettings[platform].FindProperty(platformFields[i].Name);
  626. var displayName = typeof(BurstPlatformAotSettings).GetField(platformFields[i].Name + "_DisplayName", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as string;
  627. var toolTip = typeof(BurstPlatformAotSettings).GetField(platformFields[i].Name + "_ToolTip", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as string;
  628. m_PlatformToolTips[platform][i] = EditorGUIUtility.TrTextContent(displayName, toolTip);
  629. var method = typeof(BurstPlatformAotSettings).GetMethod(platformFields[i].Name + "_Display", BindingFlags.Static | BindingFlags.NonPublic);
  630. if (method == null)
  631. {
  632. if (displayName == null)
  633. {
  634. m_PlatformVisibility[platform][i] = DefaultHide;
  635. }
  636. else
  637. {
  638. m_PlatformVisibility[platform][i] = DefaultShow;
  639. }
  640. }
  641. else
  642. {
  643. m_PlatformVisibility[platform][i] = (DisplayItem)Delegate.CreateDelegate(typeof(DisplayItem), method);
  644. }
  645. }
  646. }
  647. private string FetchStandaloneTargetName()
  648. {
  649. switch (EditorUserBuildSettings.selectedStandaloneTarget)
  650. {
  651. case BuildTarget.StandaloneOSX:
  652. return "Mac OS X"; // Matches the Build Settings Dialog names
  653. case BuildTarget.StandaloneWindows:
  654. case BuildTarget.StandaloneWindows64:
  655. return "Windows";
  656. default:
  657. return "Linux";
  658. }
  659. }
  660. public override void OnGUI(string searchContext)
  661. {
  662. var rect = EditorGUILayout.BeginVertical();
  663. EditorGUIUtility.labelWidth = rect.width / 2;
  664. int selectedPlatform = EditorGUILayout.BeginPlatformGrouping(m_ValidPlatforms, null);
  665. // During a build and other cases, the settings object can become invalid, if it does, we re-build it for the current platform
  666. // this fixes the settings failing to save if modified after a build has finished, and the settings were still open
  667. if (!m_PlatformSettings[selectedPlatform].isValid)
  668. {
  669. var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
  670. InitialiseSettingsForCommon(platformFields);
  671. // If the selected platform is invalid, it means all of them will be. So we do a pass to reinitialize all now.
  672. for (var platform = 0; platform < m_PlatformSettings.Length; platform++)
  673. {
  674. InitialiseSettingsForPlatform(platform, platformFields);
  675. }
  676. }
  677. var selectedTarget = m_ValidPlatforms[selectedPlatform].defaultTarget;
  678. if (m_ValidPlatforms[selectedPlatform].targetGroup == BuildTargetGroup.Standalone)
  679. selectedTarget = EditorUserBuildSettings.selectedStandaloneTarget;
  680. var buildTargetName = BuildPipeline.GetBuildTargetName(selectedTarget);
  681. var architecture = EditorUserBuildSettings.GetPlatformSettings(buildTargetName, "Architecture").ToLowerInvariant();
  682. if (m_ValidPlatforms[selectedPlatform].targetGroup == BuildTargetGroup.Standalone)
  683. {
  684. // Note burst treats Windows and Windows32 as the same target from a settings point of view (same for linux)
  685. // So we only display the standalone platform
  686. EditorGUILayout.LabelField(EditorGUIUtility.TrTextContent("Target Platform", "Shows the currently selected standalone build target, can be switched in the Build Settings dialog"), EditorGUIUtility.TrTextContent(FetchStandaloneTargetName()));
  687. }
  688. for (int i = 0; i < m_PlatformProperties[selectedPlatform].Length; i++)
  689. {
  690. if (m_PlatformVisibility[selectedPlatform][i](selectedTarget, architecture))
  691. {
  692. EditorGUILayout.PropertyField(m_PlatformProperties[selectedPlatform][i], m_PlatformToolTips[selectedPlatform][i]);
  693. }
  694. }
  695. if (m_ValidPlatforms[selectedPlatform].targetGroup == BuildTargetGroup.Android)
  696. EditorGUILayout.HelpBox("Armv9A (SVE2) target CPU architecture is experimental", MessageType.Warning);
  697. EditorGUILayout.EndPlatformGrouping();
  698. EditorGUILayout.EndVertical();
  699. EditorGUILayout.LabelField("* Shared setting common across all platforms");
  700. if (m_PlatformSettings[selectedPlatform].hasModifiedProperties)
  701. {
  702. m_PlatformSettings[selectedPlatform].ApplyModifiedPropertiesWithoutUndo();
  703. var commonAotSettings = ((BurstPlatformAotSettings)m_CommonPlatformSettings.targetObject);
  704. var platformAotSettings = ((BurstPlatformAotSettings)m_PlatformSettings[selectedPlatform].targetObject);
  705. var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
  706. foreach (var field in platformFields)
  707. {
  708. if (null != field.GetCustomAttribute<BurstCommonSettingAttribute>())
  709. {
  710. field.SetValue(commonAotSettings, field.GetValue(platformAotSettings));
  711. foreach (var platformSetting in m_PlatformSettings)
  712. {
  713. field.SetValue(platformSetting.targetObject, field.GetValue(commonAotSettings));
  714. }
  715. }
  716. }
  717. commonAotSettings.Save(null);
  718. platformAotSettings.Save(selectedTarget);
  719. }
  720. }
  721. }
  722. [SettingsProvider]
  723. public static SettingsProvider CreateBurstAotSettingsProvider()
  724. {
  725. return new BurstAotSettingsProvider();
  726. }
  727. }
  728. }
  729. #endif