initial commit

This commit is contained in:
Jo 2025-01-07 02:06:59 +01:00
parent 6715289efe
commit 788c3389af
37645 changed files with 2526849 additions and 80 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cf87faa2d38c376e8e9adb8eb79abd10
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,840 @@
#if UNITY_EDITOR
using System.Collections.Generic;
using System.Reflection;
using System.IO;
using System;
using System.Text;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Burst.Editor
{
internal enum DebugDataKind
{
LineOnly,
Full
}
internal enum AvailX86Targets
{
SSE2 = (int)BurstTargetCpu.X86_SSE2,
SSE4 = (int)BurstTargetCpu.X86_SSE4,
}
[Flags]
internal enum BitsetX86Targets
{
SSE2 = 1 << AvailX86Targets.SSE2,
SSE4 = 1 << AvailX86Targets.SSE4,
}
internal enum AvailX64Targets
{
SSE2 = (int)BurstTargetCpu.X64_SSE2,
SSE4 = (int)BurstTargetCpu.X64_SSE4,
AVX = (int)BurstTargetCpu.AVX,
AVX2 = (int)BurstTargetCpu.AVX2,
}
[Flags]
internal enum BitsetX64Targets
{
SSE2 = 1 << AvailX64Targets.SSE2,
SSE4 = 1 << AvailX64Targets.SSE4,
AVX = 1 << AvailX64Targets.AVX,
AVX2 = 1 << AvailX64Targets.AVX2,
}
internal enum AvailArm64Targets
{
ARMV8A = BurstTargetCpu.ARMV8A_AARCH64,
ARMV8A_HALFFP = BurstTargetCpu.ARMV8A_AARCH64_HALFFP,
ARMV9A = BurstTargetCpu.ARMV9A,
}
[Flags]
internal enum BitsetArm64Targets
{
ARMV8A = 1 << AvailArm64Targets.ARMV8A,
ARMV8A_HALFFP = 1 << AvailArm64Targets.ARMV8A_HALFFP,
ARMV9A = 1 << AvailArm64Targets.ARMV9A,
}
[AttributeUsage(AttributeTargets.Field)]
internal class BurstMetadataSettingAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Field)]
internal class BurstCommonSettingAttribute : Attribute {}
class BurstPlatformLegacySettings : ScriptableObject
{
[SerializeField]
internal bool DisableOptimisations;
[SerializeField]
internal bool DisableSafetyChecks;
[SerializeField]
internal bool DisableBurstCompilation;
BurstPlatformLegacySettings(BuildTarget target)
{
DisableSafetyChecks = true;
DisableBurstCompilation = false;
DisableOptimisations = false;
}
}
// To add a setting,
// Add a
// [SerializeField] internal type settingname;
// Add a
// internal static readonly string settingname_DisplayName = "Name of option to be displayed in the editor (and searched for)";
// Add a
// internal static readonly string settingname_ToolTip = "tool tip information to display when hovering mouse
// If the setting should be restricted to e.g. Standalone platform :
//
// Add a
// internal static bool settingname_Display(BuildTarget selectedTarget, string architecture) {}
//
// Add a
// internal static bool settingname_Serialise(BuildTarget selectedTarget) {}
class BurstPlatformAotSettings : ScriptableObject
{
[SerializeField]
[BurstMetadataSetting] // We always need version to be in our saved settings!
internal int Version;
[SerializeField]
internal bool EnableBurstCompilation;
[SerializeField]
internal bool EnableOptimisations;
[SerializeField]
internal bool EnableSafetyChecks;
[SerializeField]
internal bool EnableDebugInAllBuilds;
[SerializeField]
internal DebugDataKind DebugDataKind;
[SerializeField]
internal bool UsePlatformSDKLinker;
[SerializeField]
internal bool EnableArmv9SecurityFeatures;
[SerializeField]
internal AvailX86Targets CpuMinTargetX32;
[SerializeField]
internal AvailX86Targets CpuMaxTargetX32;
[SerializeField]
internal AvailX64Targets CpuMinTargetX64;
[SerializeField]
internal AvailX64Targets CpuMaxTargetX64;
[SerializeField]
internal BitsetX86Targets CpuTargetsX32;
[SerializeField]
internal BitsetX64Targets CpuTargetsX64;
[SerializeField]
internal BitsetArm64Targets CpuTargetsArm64;
[SerializeField]
internal OptimizeFor OptimizeFor;
[SerializeField]
[BurstCommonSetting]
internal string DisabledWarnings;
internal static readonly string EnableDebugInAllBuilds_DisplayName = "Force Debug Information";
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.";
internal static readonly string DebugDataKind_DisplayName = "Debug Information Kind";
internal static readonly string DebugDataKind_ToolTip = "Choose which kind of debug information you want present in builds with debug information enabled.";
internal static readonly string EnableOptimisations_DisplayName = "Enable Optimizations";
internal static readonly string EnableOptimisations_ToolTip = "Enables all optimizations for the currently selected platform.";
internal static readonly string EnableBurstCompilation_DisplayName = "Enable Burst Compilation";
internal static readonly string EnableBurstCompilation_ToolTip = "Enables burst compilation for the selected platform.";
internal static readonly string OptimizeFor_DisplayName = "Optimize For";
internal static readonly string OptimizeFor_ToolTip = "Choose what optimization setting to compile Burst code for.";
internal static readonly string DisabledWarnings_DisplayName = "Disabled Warnings*";
internal static readonly string DisabledWarnings_ToolTip = "Burst warnings to disable (separated by ;).";
internal static readonly string UsePlatformSDKLinker_DisplayName = "Use Platform SDK Linker";
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.";
// We do not support this option anymore, so the easiest thing is to just not display it.
internal static bool UsePlatformSDKLinker_Display(BuildTarget selectedTarget, string architecture) => false;
internal static bool UsePlatformSDKLinker_Serialise(BuildTarget selectedTarget) => false;
internal static readonly string CpuTargetsX32_DisplayName = "Target 32Bit CPU Architectures";
internal static readonly string CpuTargetsX32_ToolTip = "Use this to specify the set of target architectures to support for the currently selected platform.";
internal static bool CpuTargetsX32_Display(BuildTarget selectedTarget, string architecture)
{
return (IsStandalone(selectedTarget) || selectedTarget == BuildTarget.WSAPlayer) && Has32BitSupport(selectedTarget);
}
internal static bool CpuTargetsX32_Serialise(BuildTarget selectedTarget)
{
return (IsStandalone(selectedTarget) || selectedTarget == BuildTarget.WSAPlayer) && Has32BitSupportForSerialise(selectedTarget);
}
internal static readonly string CpuTargetsX64_DisplayName = "Target 64Bit CPU Architectures";
internal static readonly string CpuTargetsX64_ToolTip = "Use this to specify the target architectures to support for the currently selected platform.";
internal static bool CpuTargetsX64_Display(BuildTarget selectedTarget, string architecture)
{
return (IsStandalone(selectedTarget) || selectedTarget == BuildTarget.WSAPlayer)
&& Has64BitSupport(selectedTarget)
&& (selectedTarget != BuildTarget.StandaloneOSX || architecture != "arm64");
}
internal static bool CpuTargetsX64_Serialise(BuildTarget selectedTarget)
{
return IsStandalone(selectedTarget) || selectedTarget == BuildTarget.WSAPlayer;
}
internal static readonly string CpuTargetsArm64_DisplayName = "Target Arm 64Bit CPU Architectures";
internal static readonly string CpuTargetsArm64_ToolTip = "Use this to specify the target architectures to support for the currently selected platform.";
internal static bool CpuTargetsArm64_Display(BuildTarget selectedTarget, string architecture)
{
return selectedTarget == BuildTarget.Android;
}
internal static bool CpuTargetsArm64_Serialise(BuildTarget selectedTarget)
{
return selectedTarget == BuildTarget.Android;
}
internal static bool IsStandalone(BuildTarget target)
{
switch (target)
{
case BuildTarget.StandaloneLinux64:
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
case BuildTarget.StandaloneOSX:
return true;
default:
return false;
}
}
BurstPlatformAotSettings(BuildTarget target)
{
InitialiseDefaults();
}
private const int DefaultVersion = 4;
internal void InitialiseDefaults()
{
Version = DefaultVersion;
EnableSafetyChecks = false;
EnableBurstCompilation = true;
EnableOptimisations = true;
EnableDebugInAllBuilds = false;
DebugDataKind = DebugDataKind.Full;
UsePlatformSDKLinker = false; // Only applicable for desktop targets (Windows/Mac/Linux)
CpuMinTargetX32 = 0;
CpuMaxTargetX32 = 0;
CpuMinTargetX64 = 0;
CpuMaxTargetX64 = 0;
CpuTargetsX32 = BitsetX86Targets.SSE2 | BitsetX86Targets.SSE4;
CpuTargetsX64 = BitsetX64Targets.SSE2 | BitsetX64Targets.AVX2;
CpuTargetsArm64 = BitsetArm64Targets.ARMV8A;
DisabledWarnings = "";
OptimizeFor = OptimizeFor.Default;
}
internal static string GetPath(BuildTarget? target)
{
if (target.HasValue)
{
return "ProjectSettings/BurstAotSettings_" + target.ToString() + ".json";
}
else
{
return "ProjectSettings/CommonBurstAotSettings.json";
}
}
internal static BuildTarget? ResolveTarget(BuildTarget? target)
{
if (!target.HasValue)
{
return target;
}
// Treat the 32/64 platforms the same from the point of view of burst settings
// since there is no real way to distinguish from the platforms selector
if (target == BuildTarget.StandaloneWindows64 || target == BuildTarget.StandaloneWindows)
return BuildTarget.StandaloneWindows;
// 32 bit linux support was deprecated
if (target == BuildTarget.StandaloneLinux64)
return BuildTarget.StandaloneLinux64;
return target;
}
internal static readonly string BurstMiscPathPostFix = "_BurstDebugInformation_DoNotShip";
internal static string FetchOutputPath(BuildSummary summary)
{
var finalOutputPath = summary.outputPath;
var directoryName = Path.GetDirectoryName(finalOutputPath);
var appName = Path.GetFileNameWithoutExtension(finalOutputPath);
return $"{Path.Combine(directoryName, appName)}{BurstMiscPathPostFix}";
}
internal static BurstPlatformAotSettings GetOrCreateSettings(BuildTarget? target)
{
target = ResolveTarget(target);
var settings = CreateInstance<BurstPlatformAotSettings>();
settings.InitialiseDefaults();
string path = GetPath(target);
var fileExists = File.Exists(path);
var upgraded = false;
if (fileExists)
{
var json = File.ReadAllText(path);
settings = SerialiseIn(target, json, out upgraded);
}
if (!fileExists || upgraded)
{
// If the settings file didn't previously exist,
// or it did exist but we've just upgraded it to a new version,
// save it to disk now.
settings.Save(target);
}
// Overwrite the settings with any that are common and shared between all settings.
if (target.HasValue)
{
var commonSettings = GetOrCreateSettings(null);
var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var field in platformFields)
{
if (null != field.GetCustomAttribute<BurstCommonSettingAttribute>())
{
field.SetValue(settings, field.GetValue(commonSettings));
}
}
}
return settings;
}
delegate bool SerialiseItem(BuildTarget selectedPlatform);
private static BurstPlatformAotSettings SerialiseIn(BuildTarget? target, string json, out bool upgraded)
{
var versioned = ScriptableObject.CreateInstance<BurstPlatformAotSettings>();
EditorJsonUtility.FromJsonOverwrite(json, versioned);
upgraded = false;
if (versioned.Version == 0)
{
// Deal with pre versioned format
var legacy = ScriptableObject.CreateInstance<BurstPlatformLegacySettings>();
EditorJsonUtility.FromJsonOverwrite(json, legacy);
// Legacy file, upgrade it
versioned.InitialiseDefaults();
versioned.EnableOptimisations = !legacy.DisableOptimisations;
versioned.EnableBurstCompilation = !legacy.DisableBurstCompilation;
versioned.EnableSafetyChecks = !legacy.DisableSafetyChecks;
// Destroy the legacy object so Unity doesn't try to backup / restore it later during domain reload.
ScriptableObject.DestroyImmediate(legacy);
upgraded = true;
}
if (versioned.Version < 3)
{
// Upgrade the version first
versioned.Version = 3;
// Upgrade from min..max targets to bitset
versioned.CpuTargetsX32 |= (BitsetX86Targets)(1 << (int)versioned.CpuMinTargetX32);
versioned.CpuTargetsX32 |= (BitsetX86Targets)(1 << (int)versioned.CpuMaxTargetX32);
versioned.CpuTargetsX64 |= (BitsetX64Targets)(1 << (int)versioned.CpuMinTargetX64);
versioned.CpuTargetsX64 |= (BitsetX64Targets)(1 << (int)versioned.CpuMaxTargetX64);
// Extra checks to add targets in the min..max range for 64-bit targets.
switch (versioned.CpuMinTargetX64)
{
default:
break;
case AvailX64Targets.SSE2:
switch (versioned.CpuMaxTargetX64)
{
default:
break;
case AvailX64Targets.AVX2:
versioned.CpuTargetsX64 |= (BitsetX64Targets)(1 << (int)AvailX64Targets.AVX);
goto case AvailX64Targets.AVX;
case AvailX64Targets.AVX:
versioned.CpuTargetsX64 |= (BitsetX64Targets)(1 << (int)AvailX64Targets.SSE4);
break;
}
break;
case AvailX64Targets.SSE4:
switch (versioned.CpuMaxTargetX64)
{
default:
break;
case AvailX64Targets.AVX2:
versioned.CpuTargetsX64 |= (BitsetX64Targets)(1 << (int)AvailX64Targets.AVX);
break;
}
break;
}
// Wipe the old min/max targets
versioned.CpuMinTargetX32 = 0;
versioned.CpuMaxTargetX32 = 0;
versioned.CpuMinTargetX64 = 0;
versioned.CpuMaxTargetX64 = 0;
upgraded = true;
}
if (versioned.Version < 4)
{
// Upgrade the version first.
versioned.Version = 4;
// When we upgrade we'll set the optimization level to default (which is, as expected, the default).
versioned.OptimizeFor = OptimizeFor.Default;
// This option has been removed as user-setting options, so switch them to false here.
versioned.EnableSafetyChecks = false;
upgraded = true;
}
// Otherwise should be a modern file with a valid version (we can use that to upgrade when the time comes)
return versioned;
}
private static bool ShouldSerialiseOut(BuildTarget? target, FieldInfo field)
{
var method = typeof(BurstPlatformAotSettings).GetMethod(field.Name + "_Serialise", BindingFlags.Static | BindingFlags.NonPublic);
if (method != null)
{
var shouldSerialise = (SerialiseItem)Delegate.CreateDelegate(typeof(SerialiseItem), method);
if (!target.HasValue || !shouldSerialise(target.Value))
{
return false;
}
}
// If we always need to write out the attribute, return now.
if (null != field.GetCustomAttribute<BurstMetadataSettingAttribute>())
{
return true;
}
var isCommon = !target.HasValue;
var hasCommonAttribute = null != field.GetCustomAttribute<BurstCommonSettingAttribute>();
if ((isCommon && hasCommonAttribute) || (!isCommon && !hasCommonAttribute))
{
return true;
}
return false;
}
internal string SerialiseOut(BuildTarget? target)
{
// Version 2 and onwards serialise a custom object in order to avoid serialising all the settings.
StringBuilder s = new StringBuilder();
s.Append("{\n");
s.Append(" \"MonoBehaviour\": {\n");
var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
int total = 0;
for (int i = 0; i < platformFields.Length; i++)
{
if (ShouldSerialiseOut(target, platformFields[i]))
{
total++;
}
}
for (int i = 0; i < platformFields.Length; i++)
{
if (ShouldSerialiseOut(target, platformFields[i]))
{
s.Append($" \"{platformFields[i].Name}\": ");
if (platformFields[i].FieldType.IsEnum)
s.Append((int)platformFields[i].GetValue(this));
else if (platformFields[i].FieldType == typeof(string))
s.Append($"\"{platformFields[i].GetValue(this)}\"");
else if (platformFields[i].FieldType == typeof(bool))
s.Append(((bool)platformFields[i].GetValue(this)) ? "true" : "false");
else
s.Append((int)platformFields[i].GetValue(this));
total--;
if (total != 0)
s.Append(",");
s.Append("\n");
}
}
s.Append(" }\n");
s.Append("}\n");
return s.ToString();
}
internal void Save(BuildTarget? target)
{
if (target.HasValue)
{
target = ResolveTarget(target);
}
var path = GetPath(target);
if (!AssetDatabase.IsOpenForEdit(path))
{
if (!AssetDatabase.MakeEditable(path))
{
Debug.LogWarning($"Burst could not save AOT settings file {path}");
return;
}
}
File.WriteAllText(path, SerialiseOut(target));
}
internal static SerializedObject GetCommonSerializedSettings()
{
return new SerializedObject(GetOrCreateSettings(null));
}
internal static SerializedObject GetSerializedSettings(BuildTarget target)
{
return new SerializedObject(GetOrCreateSettings(target));
}
internal static bool Has32BitSupport(BuildTarget target)
{
switch (target)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.WSAPlayer:
return true;
default:
return false;
}
}
internal static bool Has32BitSupportForSerialise(BuildTarget target)
{
switch (target)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
case BuildTarget.WSAPlayer:
return true;
default:
return false;
}
}
internal static bool Has64BitSupport(BuildTarget target)
{
switch (target)
{
case BuildTarget.StandaloneWindows64:
case BuildTarget.WSAPlayer:
case BuildTarget.StandaloneOSX:
return true;
default:
return false;
}
}
private static BurstTargetCpu GetCpu(int v)
{
// https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
var r = ((v > 0xFFFF) ? 1 : 0) << 4; v >>= r;
var shift = ((v > 0xFF) ? 1 : 0) << 3; v >>= shift; r |= shift;
shift = ((v > 0xF) ? 1 : 0) << 2; v >>= shift; r |= shift;
shift = ((v > 0x3) ? 1 : 0) << 1; v >>= shift; r |= shift;
r |= (v >> 1);
return (BurstTargetCpu)r;
}
private static IEnumerable<Enum> GetFlags(Enum input)
{
foreach (Enum value in Enum.GetValues(input.GetType()))
{
if (input.HasFlag(value))
{
yield return value;
}
}
}
internal TargetCpus GetDesktopCpu32Bit()
{
var cpus = new TargetCpus();
foreach (var target in GetFlags(CpuTargetsX32))
{
cpus.Cpus.Add(GetCpu((int)(BitsetX86Targets)target));
}
// If no targets were specified just default to the oldest CPU supported.
if (cpus.Cpus.Count == 0)
{
cpus.Cpus.Add(BurstTargetCpu.X86_SSE2);
}
return cpus;
}
internal TargetCpus GetDesktopCpu64Bit()
{
var cpus = new TargetCpus();
foreach (var target in GetFlags(CpuTargetsX64))
{
cpus.Cpus.Add(GetCpu((int)(BitsetX64Targets)target));
}
// If no targets were specified just default to the oldest CPU supported.
if (cpus.Cpus.Count == 0)
{
cpus.Cpus.Add(BurstTargetCpu.X64_SSE2);
}
return cpus;
}
internal TargetCpus GetAndroidCpuArm64()
{
var cpus = new TargetCpus();
foreach (var target in GetFlags(CpuTargetsArm64))
{
cpus.Cpus.Add(GetCpu((int)(BitsetArm64Targets)target));
}
// If no targets were specified just default to the oldest CPU supported.
if (cpus.Cpus.Count == 0)
{
cpus.Cpus.Add(BurstTargetCpu.ARMV8A_AARCH64);
}
return cpus;
}
}
static class BurstAotSettingsIMGUIRegister
{
class BurstAotSettingsProvider : SettingsProvider
{
SerializedObject[] m_PlatformSettings;
SerializedProperty[][] m_PlatformProperties;
DisplayItem[][] m_PlatformVisibility;
GUIContent[][] m_PlatformToolTips;
BuildPlatform[] m_ValidPlatforms;
SerializedObject m_CommonPlatformSettings;
delegate bool DisplayItem(BuildTarget selectedTarget, string architecture);
static bool DefaultShow(BuildTarget selectedTarget, string architecture)
{
return true;
}
static bool DefaultHide(BuildTarget selectedTarget, string architecture)
{
return false;
}
public BurstAotSettingsProvider()
: base("Project/Burst AOT Settings", SettingsScope.Project, null)
{
int a;
m_ValidPlatforms = BuildPlatforms.instance.GetValidPlatforms(true).ToArray();
var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
int numPlatformFields = platformFields.Length;
int numKeywords = numPlatformFields;
var tempKeywords = new string[numKeywords];
for (a = 0; a < numPlatformFields; a++)
{
tempKeywords[a] = typeof(BurstPlatformAotSettings).GetField(platformFields[a].Name + "_ToolTip", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as string;
}
keywords = new HashSet<string>(tempKeywords);
m_PlatformSettings = new SerializedObject[m_ValidPlatforms.Length];
m_PlatformProperties = new SerializedProperty[m_ValidPlatforms.Length][];
m_PlatformVisibility = new DisplayItem[m_ValidPlatforms.Length][];
m_PlatformToolTips = new GUIContent[m_ValidPlatforms.Length][];
m_CommonPlatformSettings = null;
}
public override void OnActivate(string searchContext, VisualElement rootElement)
{
var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
for (int p = 0; p < m_ValidPlatforms.Length; p++)
{
InitialiseSettingsForCommon(platformFields);
InitialiseSettingsForPlatform(p, platformFields);
}
}
private void InitialiseSettingsForCommon(FieldInfo[] commonFields)
{
m_CommonPlatformSettings = BurstPlatformAotSettings.GetCommonSerializedSettings();
}
private void InitialiseSettingsForPlatform(int platform, FieldInfo[] platformFields)
{
if (m_ValidPlatforms[platform].targetGroup == BuildTargetGroup.Standalone)
m_PlatformSettings[platform] = BurstPlatformAotSettings.GetSerializedSettings(EditorUserBuildSettings.selectedStandaloneTarget);
else
m_PlatformSettings[platform] = BurstPlatformAotSettings.GetSerializedSettings(m_ValidPlatforms[platform].defaultTarget);
m_PlatformProperties[platform] = new SerializedProperty[platformFields.Length];
m_PlatformToolTips[platform] = new GUIContent[platformFields.Length];
m_PlatformVisibility[platform] = new DisplayItem[platformFields.Length];
for (int i = 0; i < platformFields.Length; i++)
{
m_PlatformProperties[platform][i] = m_PlatformSettings[platform].FindProperty(platformFields[i].Name);
var displayName = typeof(BurstPlatformAotSettings).GetField(platformFields[i].Name + "_DisplayName", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as string;
var toolTip = typeof(BurstPlatformAotSettings).GetField(platformFields[i].Name + "_ToolTip", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as string;
m_PlatformToolTips[platform][i] = EditorGUIUtility.TrTextContent(displayName, toolTip);
var method = typeof(BurstPlatformAotSettings).GetMethod(platformFields[i].Name + "_Display", BindingFlags.Static | BindingFlags.NonPublic);
if (method == null)
{
if (displayName == null)
{
m_PlatformVisibility[platform][i] = DefaultHide;
}
else
{
m_PlatformVisibility[platform][i] = DefaultShow;
}
}
else
{
m_PlatformVisibility[platform][i] = (DisplayItem)Delegate.CreateDelegate(typeof(DisplayItem), method);
}
}
}
private string FetchStandaloneTargetName()
{
switch (EditorUserBuildSettings.selectedStandaloneTarget)
{
case BuildTarget.StandaloneOSX:
return "Mac OS X"; // Matches the Build Settings Dialog names
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
return "Windows";
default:
return "Linux";
}
}
public override void OnGUI(string searchContext)
{
var rect = EditorGUILayout.BeginVertical();
EditorGUIUtility.labelWidth = rect.width / 2;
int selectedPlatform = EditorGUILayout.BeginPlatformGrouping(m_ValidPlatforms, null);
// During a build and other cases, the settings object can become invalid, if it does, we re-build it for the current platform
// this fixes the settings failing to save if modified after a build has finished, and the settings were still open
if (!m_PlatformSettings[selectedPlatform].isValid)
{
var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
InitialiseSettingsForCommon(platformFields);
// If the selected platform is invalid, it means all of them will be. So we do a pass to reinitialize all now.
for (var platform = 0; platform < m_PlatformSettings.Length; platform++)
{
InitialiseSettingsForPlatform(platform, platformFields);
}
}
var selectedTarget = m_ValidPlatforms[selectedPlatform].defaultTarget;
if (m_ValidPlatforms[selectedPlatform].targetGroup == BuildTargetGroup.Standalone)
selectedTarget = EditorUserBuildSettings.selectedStandaloneTarget;
var buildTargetName = BuildPipeline.GetBuildTargetName(selectedTarget);
var architecture = EditorUserBuildSettings.GetPlatformSettings(buildTargetName, "Architecture").ToLowerInvariant();
if (m_ValidPlatforms[selectedPlatform].targetGroup == BuildTargetGroup.Standalone)
{
// Note burst treats Windows and Windows32 as the same target from a settings point of view (same for linux)
// So we only display the standalone platform
EditorGUILayout.LabelField(EditorGUIUtility.TrTextContent("Target Platform", "Shows the currently selected standalone build target, can be switched in the Build Settings dialog"), EditorGUIUtility.TrTextContent(FetchStandaloneTargetName()));
}
for (int i = 0; i < m_PlatformProperties[selectedPlatform].Length; i++)
{
if (m_PlatformVisibility[selectedPlatform][i](selectedTarget, architecture))
{
EditorGUILayout.PropertyField(m_PlatformProperties[selectedPlatform][i], m_PlatformToolTips[selectedPlatform][i]);
}
}
if (m_ValidPlatforms[selectedPlatform].targetGroup == BuildTargetGroup.Android)
EditorGUILayout.HelpBox("Armv9A (SVE2) target CPU architecture is experimental", MessageType.Warning);
EditorGUILayout.EndPlatformGrouping();
EditorGUILayout.EndVertical();
EditorGUILayout.LabelField("* Shared setting common across all platforms");
if (m_PlatformSettings[selectedPlatform].hasModifiedProperties)
{
m_PlatformSettings[selectedPlatform].ApplyModifiedPropertiesWithoutUndo();
var commonAotSettings = ((BurstPlatformAotSettings)m_CommonPlatformSettings.targetObject);
var platformAotSettings = ((BurstPlatformAotSettings)m_PlatformSettings[selectedPlatform].targetObject);
var platformFields = typeof(BurstPlatformAotSettings).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var field in platformFields)
{
if (null != field.GetCustomAttribute<BurstCommonSettingAttribute>())
{
field.SetValue(commonAotSettings, field.GetValue(platformAotSettings));
foreach (var platformSetting in m_PlatformSettings)
{
field.SetValue(platformSetting.targetObject, field.GetValue(commonAotSettings));
}
}
}
commonAotSettings.Save(null);
platformAotSettings.Save(selectedTarget);
}
}
}
[SettingsProvider]
public static SettingsProvider CreateBurstAotSettingsProvider()
{
return new BurstAotSettingsProvider();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 571b2a6719883c029655e07bdf47aea0
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86710f5f973f3eb6ac4556540734abe2
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: baf945884d1937c2a53bce1dfcac594c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,168 @@
#if UNITY_EDITOR || BURST_INTERNAL
namespace Unity.Burst.Editor
{
internal partial class BurstDisassembler
{
/// <summary>
/// <see cref="AsmTokenKind"/> provider for LLVM IR - intrinsics are not covered at this time
/// </summary>
private class LLVMIRAsmTokenKindProvider : AsmTokenKindProvider
{
private static readonly string[] Qualifiers = new[]
{
"to",
"new",
"float",
"double",
"i1",
"i32",
"i16",
"i64",
"eq",
"ne",
"ugt",
"uge",
"ult",
"ule",
"sgt",
"sge",
"slt",
"sle",
"false",
"true",
"oeq",
"ogt",
"oge",
"olt",
"ole",
"one",
"ord",
"ueq",
"une",
"uno",
};
private static readonly string[] Instructions = new[]
{
"ret",
"br",
"switch",
"indirectbr",
"invoke",
"callbr",
"resume",
"catchswitch",
"catchret",
"cleanupret",
"unreachable",
"add",
"sub",
"mul",
"udiv",
"sdiv",
"urem",
"srem",
"shl",
"lshr",
"ashr",
"and",
"or",
"xor",
"extractvalue",
"insertvalue",
"alloca",
"load",
"store",
"fence",
"cmpxchg",
"atomicrmw",
"getelementptr",
"trunc",
"zext",
"sext",
"ptrtoint",
"inttoptr",
"bitcast",
"addrspacecast",
"icmp",
"phi",
"select",
"freeze",
"call",
"va_arg",
"landingpad",
"catchpad",
"cleanuppad",
};
private static readonly string[] FpuInstructions = new[]
{
"fneg",
"fadd",
"fsub",
"fmul",
"fdiv",
"frem",
"fptrunc",
"fpext",
"fptoui",
"fptosi",
"uitofp",
"sitofp",
"fcmp",
};
private static readonly string[] SimdInstructions = new[]
{
"extractelement",
"insertelement",
"shufflevector",
};
private LLVMIRAsmTokenKindProvider() : base(Qualifiers.Length + Instructions.Length + FpuInstructions.Length + SimdInstructions.Length)
{
foreach (var instruction in Qualifiers)
{
AddTokenKind(instruction, AsmTokenKind.Qualifier);
}
foreach (var instruction in Instructions)
{
AddTokenKind(instruction, AsmTokenKind.Instruction);
}
foreach (var instruction in FpuInstructions)
{
AddTokenKind(instruction, AsmTokenKind.Instruction);
}
foreach (var instruction in SimdInstructions)
{
AddTokenKind(instruction, AsmTokenKind.InstructionSIMD);
}
}
public override SIMDkind SimdKind(StringSlice instruction)
{
throw new System.NotImplementedException("Syntax Highlighting is not implemented for LLVM IR.");
}
public static readonly LLVMIRAsmTokenKindProvider Instance = new LLVMIRAsmTokenKindProvider();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: caa879909c953e51b623b5371e13b0dc
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
namespace Unity.Burst.Editor
{
internal partial class BurstDisassembler
{
internal class LLVMIRInstructionInfo
{
internal static bool GetLLVMIRInfo(string instructionName, out string instructionInfo)
{
var returnValue = true;
switch (instructionName)
{
default:
instructionInfo = string.Empty;
break;
}
return returnValue;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3b07e41fd0073a288687109ac0c6250f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,212 @@
using System;
#if UNITY_EDITOR || BURST_INTERNAL
namespace Unity.Burst.Editor
{
internal partial class BurstDisassembler
{
internal class WasmAsmTokenKindProvider : AsmTokenKindProvider
{
private static readonly string[] Registers = new[]
{
"memory.", // add . to avoid parsing instruction portion as directive
"local.",
"global.",
"i32.",
"i64.",
"f32.",
"f64."
};
private static readonly string[] Qualifiers = new[]
{
"offset",
"align",
"eqz",
"eq",
"ne",
"lt_s",
"lt_u",
"gt_s",
"gt_u",
"le_s",
"le_u",
"ge_s",
"ge_u",
"lt",
"gt",
"le",
"ge",
};
private static readonly string[] Instructions = new[]
{
"if",
"end",
"block",
"end_block",
"end_loop",
"end_function",
"loop",
"unreachable",
"nop",
"call",
"call_indirect",
"drop",
"select",
"get",
"set",
"tee",
"load",
"load8_s",
"load8_u",
"load16_s",
"load16_u",
"load32_s",
"load32_u",
"store",
"store8",
"store16",
"store32",
"size",
"grow",
"const",
"clz",
"ctz",
"popcnt",
"add",
"sub",
"mul",
"div_s",
"div_u",
"rem_s",
"rem_u",
"and",
"or",
"xor",
"shl",
"shr_s",
"shr_u",
"rotl",
"rotr",
"abs",
"neg",
"ceil",
"floor",
"trunc",
"sqrt",
"div",
"min",
"max",
"copysign",
"wrap_i64",
"trunc_f32_s",
"trunc_f32_u",
"trunc_f64_s",
"trunc_f64_u",
"extend_i32_s",
"extend_i32_u",
"convert_i32_s",
"convert_i32_u",
"convert_i64_s",
"convert_i64_u",
"demote_f64",
"promote_f32",
"reinterpret_f32",
"reinterpret_f64",
"reinterpret_i32",
"reinterpret_i64",
};
private static readonly string[] BranchInstructions = new string[]
{
"br_if",
};
private static readonly string[] JumpInstructions = new string[]
{
"br",
"br_table"
};
private static readonly string[] ReturnInstructions = new string[]
{
"return",
};
private static readonly string[] SimdInstructions = new string[]
{
};
private WasmAsmTokenKindProvider() : base(
Registers.Length +
Qualifiers.Length +
Instructions.Length +
BranchInstructions.Length +
JumpInstructions.Length +
ReturnInstructions.Length +
SimdInstructions.Length)
{
foreach (var register in Registers)
{
AddTokenKind(register, AsmTokenKind.Register);
}
foreach (var instruction in Qualifiers)
{
AddTokenKind(instruction, AsmTokenKind.Qualifier);
}
foreach (var instruction in Instructions)
{
AddTokenKind(instruction, AsmTokenKind.Instruction);
}
foreach (var instruction in BranchInstructions)
{
AddTokenKind(instruction, AsmTokenKind.BranchInstruction);
}
foreach (var instruction in JumpInstructions)
{
AddTokenKind(instruction, AsmTokenKind.JumpInstruction);
}
foreach (var instruction in ReturnInstructions)
{
AddTokenKind(instruction, AsmTokenKind.ReturnInstruction);
}
foreach (var instruction in SimdInstructions)
{
AddTokenKind(instruction, AsmTokenKind.InstructionSIMD);
}
}
public override bool AcceptsCharAsIdentifierOrRegisterEnd(char c)
{
return c == '.';
}
public override bool IsInstructionOrRegisterOrIdentifier(char c)
{
// Wasm should not take '.' with it as this will take register.instruction combo as one.
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_' ||
c == '@';
}
public override SIMDkind SimdKind(StringSlice instruction)
{
throw new NotImplementedException("WASM does not contain any SIMD instruction.");
}
public static readonly WasmAsmTokenKindProvider Instance = new WasmAsmTokenKindProvider();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 60718cfd7019357fa8f224817c4f4e31
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,263 @@
namespace Unity.Burst.Editor
{
internal partial class BurstDisassembler
{
internal class WasmInstructionInfo
{
internal static bool GetWasmInfo(string instructionName, out string instructionInfo)
{
var returnValue = true;
switch (instructionName)
{
case "if":
instructionInfo = "Executes a statement if the last item on the stack is true.";
break;
case "end":
instructionInfo = "Can be used to end a block, loop, if or else.";
break;
case "end_function":
instructionInfo = "Ends function.";
break;
case "block":
instructionInfo = "Creates a label that can later be branched out of with a br.";
break;
case "end_block":
instructionInfo = "Ends the previous opened block.";
break;
case "loop":
instructionInfo = "Creates a label that can later be branched to with a br.";
break;
case "end_loop":
instructionInfo = "Ends the previous opened loop label.";
break;
case "unreachable":
instructionInfo = "Denotes a point in code that should not be reachable.";
break;
case "nop":
instructionInfo = "Does nothing.";
break;
case "call":
instructionInfo = "Calls a function.";
break;
case "call_indirect":
instructionInfo = "Calls a function in a table.";
break;
case "drop":
instructionInfo = "Pops a value from the stack, and discards it.";
break;
case "select":
instructionInfo = "Selects one of its first two operands based on a boolean condition.";
break;
case "get":
instructionInfo = "Load the value of a variable onto the stack.";
break;
case "set":
instructionInfo = "Set the value of a variable.";
break;
case "tee":
instructionInfo = "Set the value of a variable and keep the value on the stack.";
break;
case "load":
instructionInfo = "Load a number from memory.";
break;
case "load8_s":
instructionInfo = "Load a signed 8-bit value from memory.";
break;
case "load8_u":
instructionInfo = "Load an unsigned 8-bit value from memory.";
break;
case "load16_s":
instructionInfo = "Load a signed 16-bit value from memory.";
break;
case "load16_u":
instructionInfo = "Load an unsigned 16-bit value from memory.";
break;
case "load32_s":
instructionInfo = "Load a signed 32-bit value from memory.";
break;
case "load32_u":
instructionInfo = "Load an unsigned 32-bit value from memory.";
break;
case "store":
instructionInfo = "Store a number in memory.";
break;
case "store8":
instructionInfo = "Store a 8-bit number in memory.";
break;
case "store16":
instructionInfo = "Store a 16-bit number in memory.";
break;
case "store32":
instructionInfo = "Store a 32-bit number in memory.";
break;
case "size":
instructionInfo = "Get the size of the memory instance.";
break;
case "grow":
instructionInfo = "Increase the size of the memory instance.";
break;
case "const":
instructionInfo = "Declare a constant number.";
break;
case "clz":
instructionInfo = "Count leading zeros in a numbers binary representation.";
break;
case "ctz":
instructionInfo = "Count trailing zeros in a numbers binary representation.";
break;
case "popcnt":
instructionInfo = "Count the number of '1' in a numbers binary representation.";
break;
case "add":
instructionInfo = "Add up two numbers.";
break;
case "sub":
instructionInfo = "Subtract one number from another number.";
break;
case "mul":
instructionInfo = "Multiply one number by another number.";
break;
case "div_s":
instructionInfo = "Divide two signed numbers.";
break;
case "div_u":
instructionInfo = "Divide two unsigned numbers.";
break;
case "rem_s":
instructionInfo = "Calculate the remainder left over when two signed integers are divided.";
break;
case "rem_u":
instructionInfo = "Calculate the remainder left over when two unsigned integers are divided.";
break;
case "and":
instructionInfo = "Bitwise and operation.";
break;
case "or":
instructionInfo = "Bitwise or operation.";
break;
case "xor":
instructionInfo = "Bitwise exclusive or operation.";
break;
case "shl":
instructionInfo = "Bitwise shift left operation.";
break;
case "shr_s":
instructionInfo = "Bitwise signed shift right operation.";
break;
case "shr_u":
instructionInfo = "Bitwise unsigned shift right operation.";
break;
case "rotl":
instructionInfo = "Bitwise rotate left operation.";
break;
case "rotr":
instructionInfo = "Bitwise rotate right operation.";
break;
case "abs":
instructionInfo = "Get the absolute value of a number.";
break;
case "neg":
instructionInfo = "Negate a number.";
break;
case "ceil":
instructionInfo = "Round up a number.";
break;
case "floor":
instructionInfo = "Round down a number.";
break;
case "trunc":
instructionInfo = "Discard the fractional part of a number.";
break;
case "sqrt":
instructionInfo = "Get the square root of a number.";
break;
case "div":
instructionInfo = "Divide two numbers.";
break;
case "min":
instructionInfo = "Get the lower of two numbers.";
break;
case "max":
instructionInfo = "Get the highest of two numbers.";
break;
case "copysign":
instructionInfo = "Copy just the sign bit from one number to another.";
break;
case "wrap_i64":
instructionInfo = "Convert (wrap) i64 number to i32 number.";
break;
case "trunc_f32_s":
instructionInfo = "Truncate fractional part away from a signed 32-bit floating number, giving a " +
"signed 32-bit integer.";
break;
case "trunc_f32_u":
instructionInfo = "Truncate fractional part away from a unsigned 32-bit floating number, giving a " +
"unsigned 32-bit integer.";
break;
case "trunc_f64_s":
instructionInfo = "Truncate fractional part away from a signed 64-bit floating number, giving a " +
"signed 64-bit integer.";
break;
case "trunc_f64_u":
instructionInfo = "Truncate fractional part away from a unsigned 64-bit floating number, giving a " +
"unsigned 64-bit integer.";
break;
case "extend_i32_s":
instructionInfo = "Convert (extend) signed 32-bit integer to signed 64-bit integer number.";
break;
case "extend_i32_u":
instructionInfo = "Convert (extend) unsigned 32-bit integer to unsigned 64-bit integer number.";
break;
case "convert_i32_s":
instructionInfo = "Convert signed 32-bit integer to signed 32-bit floating number.";
break;
case "convert_i32_u":
instructionInfo = "Convert unsigned 32-bit integer to unsigned 32-bit floating number.";
break;
case "convert_i64_s":
instructionInfo = "Convert signed 64-bit integer to signed 64-bit floating number.";
break;
case "convert_i64_u":
instructionInfo = "Convert unsigned 64-bit integer to unsigned 64-bit floating number.";
break;
case "demote_f64":
instructionInfo = "Convert (demote) 64-bit floating number to 32-bit floating number.";
break;
case "promote_f32":
instructionInfo = "Convert (promote) 32-bit floating number to 64-bit floating number.";
break;
case "reinterpret_f32":
instructionInfo = "Reinterpret the bytes of 32-bit floating number as 32-bit integer number.";
break;
case "reinterpret_f64":
instructionInfo = "Reinterpret the bytes of 64-bit floating number as 64-bit integer number.";
break;
case "reinterpret_i32":
instructionInfo = "Reinterpret the bytes of 32-bit integer number as 32-bit floating number.";
break;
case "reinterpret_i64":
instructionInfo = "Reinterpret the bytes of 64-bit integer number as 64-bit floating number.";
break;
case "br_if":
instructionInfo = "Branch to a loop or block if condition is true.";
break;
case "br":
instructionInfo = "Branch to a loop or block.";
break;
case "br_table":
instructionInfo = "Branch to a loop or block if condition based on argument.";
break;
case "return":
instructionInfo = "Returns from a function.";
break;
default:
instructionInfo = string.Empty;
break;
}
return returnValue;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 59dd88516199395585b8d7d3fcb486f4
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,575 @@
#if UNITY_EDITOR || BURST_INTERNAL
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Unity.Burst.Editor
{
internal partial class BurstDisassembler
{
/// <summary>
/// Base class for providing extended information of an identifier
/// </summary>
internal abstract class AsmTokenKindProvider
{
// Internally using string slice instead of string
// to support faster lookup from AsmToken
private readonly Dictionary<StringSlice, AsmTokenKind> _tokenKinds;
private int _maximumLength;
protected AsmTokenKindProvider(int capacity)
{
_tokenKinds = new Dictionary<StringSlice, AsmTokenKind>(capacity);
}
protected void AddTokenKind(string text, AsmTokenKind kind)
{
_tokenKinds.Add(new StringSlice(text), kind);
if (text.Length > _maximumLength) _maximumLength = text.Length;
}
public virtual AsmTokenKind FindTokenKind(StringSlice slice)
{
return slice.Length <= _maximumLength && _tokenKinds.TryGetValue(slice, out var tokenKind)
? tokenKind
: AsmTokenKind.Identifier;
}
public virtual bool AcceptsCharAsIdentifierOrRegisterEnd(char c)
{
return false;
}
public virtual bool IsInstructionOrRegisterOrIdentifier(char c)
{
// we include . because we have instructions like `b.le` or `f32.const`
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_' ||
c == '@' || c == '.';
}
/// <summary>
/// Checks whether regA == regB. This function assumes the given strings are proper registers.
/// </summary>
public virtual bool RegisterEqual(string regA, string regB) => regA == regB;
public abstract SIMDkind SimdKind(StringSlice instruction);
}
/// <summary>
/// The ASM tokenizer
/// </summary>
private struct AsmTokenizer
{
private readonly string _text;
private readonly AsmKind _asmKind;
private readonly AsmTokenKindProvider _tokenKindProvider;
private int _position;
private int _nextPosition;
private int _alignedPosition;
private int _nextAlignedPosition;
private char _c;
private readonly char _commentStartChar;
private bool _doPad;
private int _padding;
public AsmTokenizer(string text, AsmKind asmKind, AsmTokenKindProvider tokenKindProvider, char commentStart)
{
_text = text;
_asmKind = asmKind;
_tokenKindProvider = tokenKindProvider;
_position = 0;
_nextPosition = 0;
_alignedPosition = 0;
_nextAlignedPosition = 0;
_commentStartChar = commentStart;
_doPad = false;
_padding = 0;
_c = (char)0;
NextChar();
}
public bool TryGetNextToken(out AsmToken token)
{
token = new AsmToken();
while (true)
{
var startPosition = _position;
var startAlignedPosition = _alignedPosition;
if (_c == 0)
{
return false;
}
if (_c == '.')
{
token = ParseDirective(startPosition, startAlignedPosition);
return true;
}
// Like everywhere else in this file, we are inlining the matching characters instead
// of using helper functions, as Mono might not be enough good at inlining by itself
if (_c >= 'a' && _c <= 'z' || _c >= 'A' && _c <= 'Z' || _c == '_' || _c == '@')
{
token = ParseInstructionOrIdentifierOrRegister(startPosition, startAlignedPosition);
PrepareAlignment(token);
return true;
}
if (_c >= '0' && _c <= '9' || _c == '-')
{
token = ParseNumber(startPosition, startAlignedPosition);
return true;
}
if (_c == '"')
{
token = ParseString(startPosition, startAlignedPosition);
return true;
}
if (_c == _commentStartChar)
{
token = ParseComment(startPosition, startAlignedPosition);
return true;
}
if (_c == '\r')
{
if (PreviewChar() == '\n')
{
NextChar(); // skip \r
}
token = ParseNewLine(startPosition, startAlignedPosition);
return true;
}
if (_c == '\n')
{
token = ParseNewLine(startPosition, startAlignedPosition);
return true;
}
if (_doPad)
{
_nextAlignedPosition += _padding;
_doPad = false;
}
token = ParseMisc(startPosition, startAlignedPosition);
return true;
}
}
private void PrepareAlignment(AsmToken token)
{
var kind = token.Kind;
_padding = InstructionAlignment - token.Length;
_doPad = _asmKind == AsmKind.Intel
&& (kind == AsmTokenKind.Instruction
|| kind == AsmTokenKind.BranchInstruction
|| kind == AsmTokenKind.CallInstruction
|| kind == AsmTokenKind.JumpInstruction
|| kind == AsmTokenKind.ReturnInstruction
|| kind == AsmTokenKind.InstructionSIMD)
&& _c != '\n' && _c != '\r' // If there is no registers behind instruction don't align.
&& _padding > 0;
}
private AsmToken ParseNewLine(int startPosition, int startAlignedPosition)
{
var endPosition = _position;
NextChar(); // Skip newline
return new AsmToken(AsmTokenKind.NewLine, startPosition, startAlignedPosition, endPosition - startPosition + 1);
}
private AsmToken ParseMisc(int startPosition, int startAlignedPosition)
{
var endPosition = _position;
// Parse anything that is not a directive, instruction, number, string or comment
while (!((_c == (char)0) || (_c == '\r') || (_c == '\n') || (_c == '.') || (_c >= 'a' && _c <= 'z' || _c >= 'A' && _c <= 'Z' || _c == '_' || _c == '@') || (_c >= '0' && _c <= '9' || _c == '-') || (_c == '"') || (_c == _commentStartChar)))
{
endPosition = _position;
NextChar();
}
return new AsmToken(AsmTokenKind.Misc, startPosition, startAlignedPosition, endPosition - startPosition + 1);
}
private static readonly string[] DataDirectiveStrings = new[]
{
AssertDataDirectiveLength(".long"),
AssertDataDirectiveLength(".byte"),
AssertDataDirectiveLength(".short"),
AssertDataDirectiveLength(".ascii"),
AssertDataDirectiveLength(".asciz"),
};
private static string AssertDataDirectiveLength(string text)
{
var length = text.Length;
Debug.Assert(length == 5 || length == 6, $"Invalid length {length} for string {text}. Expecting 5 or 6");
return text;
}
private AsmToken ParseDirective(int startPosition, int startAlignedPosition)
{
var endPosition = _position;
NextChar(); // skip .
bool isLabel = _c == 'L'; // A label starts with a capital `L` like .Lthis_is_a_jump_label
while (_c >= 'a' && _c <= 'z' || _c >= 'A' && _c <= 'Z' || _c >= '0' && _c <= '9' || _c == '.' || _c == '_' || _c == '@')
{
endPosition = _position;
NextChar();
}
// Refine the kind of directive:
//
// .Lfunc_begin => FunctionBegin
// .Lfunc_end => FunctionEnd
// .L????????? => Label
// data directive (.byte, .long, .short...) => DataDirective
// anything else => Directive
const string MatchFunc = ".Lfunc_";
const int MatchFuncLength = 7;
Debug.Assert(MatchFunc.Length == MatchFuncLength);
var kind = isLabel ? AsmTokenKind.Label : AsmTokenKind.Directive;
// Fast early check
if (isLabel && string.CompareOrdinal(_text, startPosition, MatchFunc, 0, MatchFuncLength) == 0)
{
if (string.CompareOrdinal(_text, startPosition, ".Lfunc_begin", 0, ".Lfunc_begin".Length) == 0)
{
kind = AsmTokenKind.FunctionBegin;
}
else if (string.CompareOrdinal(_text, startPosition, ".Lfunc_end", 0, ".Lfunc_end".Length) == 0)
{
kind = AsmTokenKind.FunctionEnd;
}
}
// Adjust directive to mark data directives, source location directives...etc.
int length = endPosition - startPosition + 1;
// Use length to early exit
if (!isLabel && length >= 4 && length <= 8)
{
if ((length == 5 || length == 6))
{
foreach (var dataDirectiveStr in DataDirectiveStrings)
{
if (string.CompareOrdinal(_text, startPosition, dataDirectiveStr, 0, dataDirectiveStr.Length) == 0)
{
kind = AsmTokenKind.DataDirective;
break;
}
}
// .file => SourceFile
if (kind == AsmTokenKind.Directive && string.CompareOrdinal(_text, startPosition, ".file", 0, 5) == 0)
{
kind = AsmTokenKind.SourceFile;
}
}
// .loc => SourceLocation
// .cv_loc => SourceLocation
else if ((length == 4 && string.CompareOrdinal(_text, startPosition, ".loc", 0, 4) == 0) ||
(length == 7 && string.CompareOrdinal(_text, startPosition, ".cv_loc", 0, 7) == 0))
{
kind = AsmTokenKind.SourceLocation;
}
// .file .cv_file => SourceFile
else if (length == 8 && string.CompareOrdinal(_text, startPosition, ".cv_file", 0, 8) == 0)
{
kind = AsmTokenKind.SourceFile;
}
}
return new AsmToken(kind, startPosition, startAlignedPosition, length);
}
private AsmToken ParseInstructionOrIdentifierOrRegister(int startPosition, int startAlignedPosition)
{
var endPosition = _position;
while (_tokenKindProvider.IsInstructionOrRegisterOrIdentifier(_c))
{
endPosition = _position;
NextChar();
}
if (_tokenKindProvider.AcceptsCharAsIdentifierOrRegisterEnd(_c))
{
endPosition = _position;
NextChar();
}
// Resolve token kind for identifier
int length = endPosition - startPosition + 1;
var tokenKind = _tokenKindProvider.FindTokenKind(new StringSlice(_text, startPosition, length));
if (tokenKind == AsmTokenKind.Identifier)
{
// If we have `:` right after an identifier, change from identifier to label declaration to help the semantic pass later
if (_c == ':')
{
tokenKind = AsmTokenKind.Label;
}
}
return new AsmToken(tokenKind, startPosition, startAlignedPosition, endPosition - startPosition + 1);
}
private AsmToken ParseNumber(int startPosition, int startAlignedPostion)
{
var endPosition = _position;
if (_c == '-')
{
NextChar();
}
while (_c >= '0' && _c <= '9' || _c >= 'a' && _c <= 'f' || _c >= 'A' && _c <= 'F' || _c == 'x' || _c == '.')
{
endPosition = _position;
NextChar();
}
// If we have `:` right after a number, change from number to label declaration to help the semantic pass later
var numberKind = _c == ':' ? AsmTokenKind.Label : AsmTokenKind.Number;
return new AsmToken(numberKind, startPosition, startAlignedPostion, endPosition - startPosition + 1);
}
private AsmToken ParseString(int startPosition, int startAlignedPostion)
{
var endPosition = _position;
// Skip first "
NextChar();
while (_c != (char)0 && _c != '"')
{
// Skip escape \"
if (_c == '\\' && PreviewChar() == '"')
{
NextChar();
}
endPosition = _position;
NextChar();
}
endPosition = _position;
NextChar(); // Skip trailing 0
// If we have `:` right after a string, change from string to label declaration to help the semantic pass later
var stringKind = _c == ':' ? AsmTokenKind.Label : AsmTokenKind.String;
return new AsmToken(stringKind, startPosition, startAlignedPostion, endPosition - startPosition + 1);
}
private AsmToken ParseComment(int startPosition, int startAlignedPosition)
{
var endPosition = _position;
while (_c != (char)0 && (_c != '\n' && _c != '\r'))
{
endPosition = _position;
NextChar();
}
return new AsmToken(AsmTokenKind.Comment, startPosition, startAlignedPosition, endPosition - startPosition + 1);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void NextChar()
{
if (_nextPosition < _text.Length)
{
_position = _nextPosition;
_c = _text[_position];
_nextPosition = _position + 1;
_alignedPosition = _nextAlignedPosition;
_nextAlignedPosition = _alignedPosition + 1;
}
else
{
_c = (char)0;
}
}
private char PreviewChar()
{
return _nextPosition < _text.Length ? _text[_nextPosition] : (char)0;
}
}
public enum SIMDkind
{
Packed,
Scalar,
Infrastructure,
}
/// <summary>
/// An ASM token. The token doesn't contain the string of the token, but provides method <see cref="Slice"/> and <see cref="ToString"/> to extract it.
/// </summary>
internal readonly struct AsmToken
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CAUTION: It is important to not put *any managed objects*
// into this struct for GC efficiency
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public AsmToken(AsmTokenKind kind, int position, int alignedPosition, int length)
{
Kind = kind;
Position = position;
AlignedPosition = alignedPosition;
Length = length;
}
public readonly AsmTokenKind Kind;
public readonly int Position;
public readonly int AlignedPosition;
public readonly int Length;
public StringSlice Slice(string text) => new StringSlice(text, Position, Length);
public string ToString(string text) => text.Substring(Position, Length);
public string ToFriendlyText(string text)
{
return $"{text.Substring(Position, Length)} : {Kind}";
}
}
/// <summary>
/// Kind of an ASM token.
/// </summary>
internal enum AsmTokenKind
{
Eof,
Directive,
DataDirective,
SourceFile,
SourceLocation,
Label,
FunctionBegin,
FunctionEnd,
Identifier,
Qualifier,
Instruction,
CallInstruction,
BranchInstruction,
JumpInstruction,
ReturnInstruction,
InstructionSIMD,
Register,
Number,
String,
Comment,
NewLine,
Misc
}
}
/// <summary>
/// A slice of a string from an original string.
/// </summary>
internal readonly struct StringSlice : IEquatable<StringSlice>
{
private readonly string _text;
public readonly int Position;
public readonly int Length;
public StringSlice(string text)
{
_text = text ?? throw new ArgumentNullException(nameof(text));
Position = 0;
Length = text.Length;
}
public StringSlice(string text, int position, int length)
{
_text = text ?? throw new ArgumentNullException(nameof(text));
Position = position;
Length = length;
}
public char this[int index] => _text[Position + index];
public bool Equals(StringSlice other)
{
if (Length != other.Length) return false;
for (int i = 0; i < Length; i++)
{
if (this[i] != other[i])
{
return false;
}
}
return true;
}
public override bool Equals(object obj)
{
return obj is StringSlice other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = Length;
for (int i = 0; i < Length; i++)
{
hashCode = (hashCode * 397) ^ this[i];
}
return hashCode;
}
}
public static bool operator ==(StringSlice left, StringSlice right)
{
return left.Equals(right);
}
public static bool operator !=(StringSlice left, StringSlice right)
{
return !left.Equals(right);
}
public override string ToString()
{
return _text.Substring(Position, Length);
}
public bool StartsWith(string text)
{
if (text == null) throw new ArgumentNullException(nameof(text));
if (Length < text.Length) return false;
for (var i = 0; i < text.Length; i++)
{
var c = text[i];
if (_text[Position + i] != c) return false;
}
return true;
}
public bool Contains(char c) => _text.Skip(Position).Take(Length).Any(elm => elm == c);
public int IndexOf(char c)
{
for (var i = 0; i < Length; i++)
{
if (_text[Position + i] == c)
{
return i;
}
}
return -1;
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8e9be092790937a59d4e735174d7a0cf
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0e74c9ce3b3038e298ae140ed24be9a6
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d1fde1c55cf0307abe6a38343f5c48df
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3f95fb45824f373fad673bef04ad4f0b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ffabd1fbe2ab3d59a50128c0669b5791
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,9 @@
using System.Runtime.CompilerServices;
// Some code in Unity.Entities.TypeManager
// (https://github.cds.internal.unity3d.com/unity/dots/blob/d82f136abd45af8760235b885b63ecb50dcaf5f8/Packages/com.unity.entities/Unity.Entities/Types/TypeManager.cs#L426)
// uses reflection to call a static Unity.Burst.Editor.BurstLoader.IsDebugging property,
// to ensure that BurstLoader has been initialized.
// It specifically looks in the Unity.Burst.Editor.dll assembly.
// So we use type-forwarding to let it find the "real" BurstLoader.
[assembly: TypeForwardedToAttribute(typeof(Unity.Burst.Editor.BurstLoader))]

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 196062cbef3533e384a45a204b6b9b64
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,94 @@
using UnityEngine;
namespace Unity.Burst.Editor
{
internal static class BurstMath
{
private const float HitBoxAdjust = 2f;
/// <summary>
/// Rotates <see cref="point"/> around a pivot point according to angle given in degrees.
/// </summary>
/// <param name="angle">Angle in degrees.</param>
/// <param name="point">Point to rotate.</param>
/// <param name="pivotPoint">Pivot point to rotate around.</param>
/// <returns>The rotated point.</returns>
internal static Vector2 AnglePoint(float angle, Vector2 point, Vector2 pivotPoint)
{
// https://matthew-brett.github.io/teaching/rotation_2d.html
// Problem Angle is calculates as angle clockwise, and here we use it as it was counterclockwise!
var s = Mathf.Sin(angle);
var c = Mathf.Cos(angle);
point -= pivotPoint;
return new Vector2(c * point.x - s * point.y, s * point.x + c * point.y) + pivotPoint;
}
/// <summary>
/// Calculated angle in degrees between two points.
/// </summary>
/// <param name="start">Starting point.</param>
/// <param name="end">End point.</param>
/// <returns>Angle in degrees.</returns>
internal static float CalculateAngle(Vector2 start, Vector2 end)
{
var distance = end - start;
var angle = Mathf.Rad2Deg * Mathf.Atan(distance.y / distance.x);
if (distance.x < 0)
{
angle += 180;
}
return angle;
}
/// <summary>
/// Checks if <see cref="point"/> is within <see cref="rect"/> enlarged by <see cref="HitBoxAdjust"/>.
/// </summary>
/// <param name="rect">Give rect to enlarge and check with.</param>
/// <param name="point">Given point to match in enlarged <see cref="rect"/>.</param>
/// <returns>Whether <see cref="point"/> is within enlarged <see cref="rect"/>.</returns>
internal static bool AdjustedContains(Rect rect, Vector2 point)
{
return rect.yMax + HitBoxAdjust >= point.y && rect.yMin - HitBoxAdjust <= point.y
&& rect.xMax + HitBoxAdjust >= point.x && rect.xMin - HitBoxAdjust <= point.x;
}
/// <summary>
/// Checks if <see cref="num"/> is within the closed interval defined by endPoint1 and endPoint2.
/// </summary>
/// <param name="endPoint1">One side of range.</param>
/// <param name="endPoint2">Other side of range.</param>
/// <param name="num">Number to check if it is in between <see cref="endPoint1"/> and <see cref="endPoint2"/>.</param>
/// <returns>Whether <see cref="num"/> is within given range.</returns>
internal static bool WithinRange(float endPoint1, float endPoint2, float num)
{
float start, end;
if (endPoint1 < endPoint2)
{
start = endPoint1;
end = endPoint2;
}
else
{
start = endPoint2;
end = endPoint1;
}
return start <= num && num <= end;
}
/// <summary>
/// Rounds down to nearest amount specified by <see cref="to"/>.
/// </summary>
/// <param name="number">Number to round down.</param>
/// <param name="to">Specifies what amount to round down to.</param>
/// <returns><see cref="number"/> rounded down to amount <see cref="to"/>.</returns>
internal static float RoundDownToNearest(float number, float to)
{
//https://www.programmingnotes.org/7601/cs-how-to-round-a-number-to-the-nearest-x-using-cs/
float inverse = 1 / to;
float dividend = Mathf.Floor(number * inverse);
return dividend / inverse;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4783a0e50db93e7bafe8dae157848042
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,194 @@
using Unity.Burst.LowLevel;
using UnityEditor;
using Unity.Jobs.LowLevel.Unsafe;
using UnityEngine;
using System;
namespace Unity.Burst.Editor
{
/// <summary>
/// Register all menu entries for burst to the Editor
/// </summary>
internal static class BurstMenu
{
private const string EnableBurstCompilationText = "Jobs/Burst/Enable Compilation";
private const string EnableSafetyChecksTextOff = "Jobs/Burst/Safety Checks/Off";
private const string EnableSafetyChecksTextOn = "Jobs/Burst/Safety Checks/On";
private const string EnableSafetyChecksTextForceOn = "Jobs/Burst/Safety Checks/Force On";
private const string ForceSynchronousCompilesText = "Jobs/Burst/Synchronous Compilation";
private const string EnableDebugCompilationText = "Jobs/Burst/Native Debug Mode Compilation";
private const string ShowBurstTimingsText = "Jobs/Burst/Show Timings";
private const string BurstInspectorText = "Jobs/Burst/Open Inspector...";
// ----------------------------------------------------------------------------------------------
// #1 Enable Compilation
// ----------------------------------------------------------------------------------------------
[MenuItem(EnableBurstCompilationText, false, 1)]
private static void EnableBurstCompilation()
{
ChangeOptionSafely(() => BurstEditorOptions.EnableBurstCompilation = !BurstEditorOptions.EnableBurstCompilation);
}
[MenuItem(EnableBurstCompilationText, true, 1)]
private static bool EnableBurstCompilationValidate()
{
Menu.SetChecked(EnableBurstCompilationText, BurstEditorOptions.EnableBurstCompilation);
return BurstCompilerService.IsInitialized;
}
// ----------------------------------------------------------------------------------------------
// #2 Safety Checks
// ----------------------------------------------------------------------------------------------
[MenuItem(EnableSafetyChecksTextOff, false, 1)]
private static void EnableBurstSafetyChecksOff()
{
ChangeOptionSafely(() =>
{
BurstEditorOptions.EnableBurstSafetyChecks = false;
BurstEditorOptions.ForceEnableBurstSafetyChecks = false;
});
Menu.SetChecked(EnableSafetyChecksTextOff, true);
Menu.SetChecked(EnableSafetyChecksTextOn, false);
Menu.SetChecked(EnableSafetyChecksTextForceOn, false);
}
[MenuItem(EnableSafetyChecksTextOff, true, 1)]
private static bool EnableBurstSafetyChecksOffValidate()
{
Menu.SetChecked(EnableSafetyChecksTextOff, !BurstEditorOptions.EnableBurstSafetyChecks && !BurstEditorOptions.ForceEnableBurstSafetyChecks);
return BurstCompilerService.IsInitialized && BurstEditorOptions.EnableBurstCompilation;
}
[MenuItem(EnableSafetyChecksTextOn, false, 2)]
private static void EnableBurstSafetyChecksOn()
{
ChangeOptionSafely(() =>
{
BurstEditorOptions.EnableBurstSafetyChecks = true;
BurstEditorOptions.ForceEnableBurstSafetyChecks = false;
});
Menu.SetChecked(EnableSafetyChecksTextOff, false);
Menu.SetChecked(EnableSafetyChecksTextOn, true);
Menu.SetChecked(EnableSafetyChecksTextForceOn, false);
}
[MenuItem(EnableSafetyChecksTextOn, true, 2)]
private static bool EnableBurstSafetyChecksOnValidate()
{
Menu.SetChecked(EnableSafetyChecksTextOn, BurstEditorOptions.EnableBurstSafetyChecks && !BurstEditorOptions.ForceEnableBurstSafetyChecks);
return BurstCompilerService.IsInitialized && BurstEditorOptions.EnableBurstCompilation;
}
[MenuItem(EnableSafetyChecksTextForceOn, false, 3)]
private static void EnableBurstSafetyChecksForceOn()
{
ChangeOptionSafely(() =>
{
BurstEditorOptions.EnableBurstSafetyChecks = true;
BurstEditorOptions.ForceEnableBurstSafetyChecks = true;
});
Menu.SetChecked(EnableSafetyChecksTextOff, false);
Menu.SetChecked(EnableSafetyChecksTextOn, false);
Menu.SetChecked(EnableSafetyChecksTextForceOn, true);
}
[MenuItem(EnableSafetyChecksTextForceOn, true, 3)]
private static bool EnableBurstSafetyChecksForceOnValidate()
{
Menu.SetChecked(EnableSafetyChecksTextForceOn, BurstEditorOptions.ForceEnableBurstSafetyChecks);
return BurstCompilerService.IsInitialized && BurstEditorOptions.EnableBurstCompilation;
}
// ----------------------------------------------------------------------------------------------
// #3 Synchronous Compilation
// ----------------------------------------------------------------------------------------------
[MenuItem(ForceSynchronousCompilesText, false, 5)]
private static void ForceSynchronousCompiles()
{
BurstEditorOptions.EnableBurstCompileSynchronously = !BurstEditorOptions.EnableBurstCompileSynchronously;
}
[MenuItem(ForceSynchronousCompilesText, true, 5)]
private static bool ForceSynchronousCompilesValidate()
{
Menu.SetChecked(ForceSynchronousCompilesText, BurstEditorOptions.EnableBurstCompileSynchronously);
return BurstCompilerService.IsInitialized && BurstEditorOptions.EnableBurstCompilation;
}
// ----------------------------------------------------------------------------------------------
// #4 Synchronous Compilation
// ----------------------------------------------------------------------------------------------
[MenuItem(EnableDebugCompilationText, false, 6)]
private static void EnableDebugMode()
{
ChangeOptionSafely(() =>
{
BurstEditorOptions.EnableBurstDebug = !BurstEditorOptions.EnableBurstDebug;
});
}
[MenuItem(EnableDebugCompilationText, true, 6)]
private static bool EnableDebugModeValidate()
{
Menu.SetChecked(EnableDebugCompilationText, BurstEditorOptions.EnableBurstDebug);
return BurstCompilerService.IsInitialized && BurstEditorOptions.EnableBurstCompilation;
}
// ----------------------------------------------------------------------------------------------
// #5 Show Timings
// ----------------------------------------------------------------------------------------------
[MenuItem(ShowBurstTimingsText, false, 7)]
private static void ShowBurstTimings()
{
BurstEditorOptions.EnableBurstTimings = !BurstEditorOptions.EnableBurstTimings;
}
[MenuItem(ShowBurstTimingsText, true, 7)]
private static bool ShowBurstTimingsValidate()
{
Menu.SetChecked(ShowBurstTimingsText, BurstEditorOptions.EnableBurstTimings);
return BurstCompilerService.IsInitialized && BurstEditorOptions.EnableBurstCompilation;
}
// ----------------------------------------------------------------------------------------------
// #6 Open Inspector...
// ----------------------------------------------------------------------------------------------
[MenuItem(BurstInspectorText, false, 8)]
private static void BurstInspector()
{
// Get existing open window or if none, make a new one:
BurstInspectorGUI window = EditorWindow.GetWindow<BurstInspectorGUI>("Burst Inspector");
window.Show();
}
[MenuItem(BurstInspectorText, true, 8)]
private static bool BurstInspectorValidate()
{
return BurstCompilerService.IsInitialized;
}
private static void ChangeOptionSafely(Action callback)
{
try
{
RequiresRestartUtility.CalledFromUI = true;
callback();
if (RequiresRestartUtility.RequiresRestart)
{
EditorUtility.DisplayDialog(
"Editor Restart Required",
"This setting will not be applied until the Editor has been restarted. Please restart the Editor to continue.",
"OK");
BurstCompiler.Shutdown();
}
}
finally
{
RequiresRestartUtility.RequiresRestart = false;
RequiresRestartUtility.CalledFromUI = false;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 10cda29925873fe1b9148e7e00e4d297
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,214 @@
using System;
using System.Text.RegularExpressions;
namespace Unity.Burst.Editor
{
internal struct SearchCriteria
{
internal string filter;
internal bool isCaseSensitive;
internal bool isWholeWords;
internal bool isRegex;
internal SearchCriteria(string keyword, bool caseSensitive, bool wholeWord, bool regex)
{
filter = keyword;
isCaseSensitive = caseSensitive;
isWholeWords = wholeWord;
isRegex = regex;
}
internal bool Equals(SearchCriteria obj) =>
filter == obj.filter && isCaseSensitive == obj.isCaseSensitive && isWholeWords == obj.isWholeWords && isRegex == obj.isRegex;
public override bool Equals(object obj) =>
obj is SearchCriteria other && Equals(other);
public override int GetHashCode() => base.GetHashCode();
}
internal static class BurstStringSearch
{
/// <summary>
/// Gets index of line end in given string, both absolute and relative to start of line.
/// </summary>
/// <param name="str">String to search in.</param>
/// <param name="line">Line to get end index of.</param>
/// <returns>(absolute line end index of string, line end index relative to line start).</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Argument must be greater than 0 and less than or equal to number of lines in
/// <paramref name="str" />.
/// </exception>
internal static (int total, int relative) GetEndIndexOfPlainLine (string str, int line)
{
var lastIdx = -1;
var newIdx = -1;
for (var i = 0; i <= line; i++)
{
lastIdx = newIdx;
newIdx = str.IndexOf('\n', lastIdx + 1);
if (newIdx == -1 && i < line)
{
throw new ArgumentOutOfRangeException(nameof(line),
"Argument must be greater than 0 and less than or equal to number of lines in str.");
}
}
lastIdx++;
return newIdx != -1 ? (newIdx, newIdx - lastIdx) : (str.Length - 1, str.Length - 1 - lastIdx);
}
/// <summary>
/// Gets index of line end in given string, both absolute and relative to start of line.
/// Adjusts the index so color tags are not included in relative index.
/// </summary>
/// <param name="str">String to search in.</param>
/// <param name="line">Line to find end of in string.</param>
/// <returns>(absolute line end index of string, line end index relative to line start adjusted for color tags).</returns>
internal static (int total, int relative) GetEndIndexOfColoredLine(string str, int line)
{
var (total, relative) = GetEndIndexOfPlainLine(str, line);
return RemoveColorTagFromIdx(str, total, relative);
}
/// <summary>
/// Adjusts index of color tags on line.
/// </summary>
/// <remarks>Assumes that <see cref="tidx"/> is index of something not a color tag.</remarks>
/// <param name="str">String containing the indexes.</param>
/// <param name="tidx">Total index of line end.</param>
/// <param name="ridx">Relative index of line end.</param>
/// <returns>(<see cref="tidx"/>, <see cref="ridx"/>) adjusted for color tags on line.</returns>
private static (int total, int relative) RemoveColorTagFromIdx(string str, int tidx, int ridx)
{
var lineStartIdx = tidx - ridx;
var colorTagFiller = 0;
var tmp = str.LastIndexOf("</color", tidx);
var lastWasStart = true;
var colorTagStart = str.LastIndexOf("<color=", tidx);
if (tmp > colorTagStart)
{
// color tag end was closest
lastWasStart = false;
colorTagStart = tmp;
}
while (colorTagStart != -1 && colorTagStart >= lineStartIdx)
{
var colorTagEnd = str.IndexOf('>', colorTagStart);
// +1 as the index is zero based.
colorTagFiller += colorTagEnd - colorTagStart + 1;
if (lastWasStart)
{
colorTagStart = str.LastIndexOf("</color", colorTagStart);
lastWasStart = false;
}
else
{
colorTagStart = str.LastIndexOf("<color=", colorTagStart);
lastWasStart = true;
}
}
return (tidx - colorTagFiller, ridx - colorTagFiller);
}
/// <summary>
/// Finds the zero indexed line number of given <see cref="matchIdx"/>.
/// </summary>
/// <param name="str">String to search in.</param>
/// <param name="matchIdx">Index to find line number of.</param>
/// <returns>Line number of given index in string.</returns>
internal static int FindLineNr(string str, int matchIdx)
{
var lineNr = 0;
var idxn = str.IndexOf('\n');
while (idxn != -1 && idxn < matchIdx)
{
lineNr++;
idxn = str.IndexOf('\n', idxn + 1);
}
return lineNr;
}
/// <summary>
/// Finds first match of <see cref="criteria"/> in given string.
/// </summary>
/// <param name="str">String to search in.</param>
/// <param name="criteria">Search options.</param>
/// <param name="regx">Used when <see cref="criteria"/> specifies regex search.</param>
/// <param name="startIdx">Index to start the search at.</param>
/// <returns>(start index of match, length of match)</returns>
internal static (int idx, int length) FindMatch(string str, SearchCriteria criteria, Regex regx, int startIdx = 0)
{
var idx = -1;
var len = 0;
if (criteria.isRegex)
{
// regex will have the appropriate options in it if isCaseSensitive or/and isWholeWords is true.
var res = regx.Match(str, startIdx);
if (res.Success) (idx, len) = (res.Index, res.Length);
}
else if (criteria.isWholeWords)
{
(idx, len) = (IndexOfWholeWord(str, startIdx, criteria.filter, criteria.isCaseSensitive
? StringComparison.InvariantCulture
: StringComparison.InvariantCultureIgnoreCase), criteria.filter.Length);
}
else
{
(idx, len) = (str.IndexOf(criteria.filter, startIdx, criteria.isCaseSensitive
? StringComparison.InvariantCulture
: StringComparison.InvariantCultureIgnoreCase), criteria.filter.Length);
}
return (idx, len);
}
/// <summary>
/// Finds index of <see cref="filter"/> matching for whole words.
/// </summary>
/// <param name="str">String to search in.</param>
/// <param name="startIdx">Index to start search from.</param>
/// <param name="filter">Key to search for.</param>
/// <param name="opt">Options for string comparison.</param>
/// <returns>Index of match or -1.</returns>
private static int IndexOfWholeWord(string str, int startIdx, string filter, StringComparison opt)
{
const string wholeWordMatch = @"\w";
var j = startIdx;
var filterLen = filter.Length;
var strLen = str.Length;
while (j < strLen && (j = str.IndexOf(filter, j, opt)) >= 0)
{
var noPrior = true;
if (j != 0)
{
var frontBorder = str[j - 1];
noPrior = !Regex.IsMatch(frontBorder.ToString(), wholeWordMatch);
}
var noAfter = true;
if (j + filterLen != strLen)
{
var endBorder = str[j + filterLen];
noAfter = !Regex.IsMatch(endBorder.ToString(), wholeWordMatch);
}
if (noPrior && noAfter) return j;
j++;
}
return -1;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 502c484521bc39a9950d91fdf34fd285
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,123 @@
using UnityEngine;
using UnityEditor;
namespace Unity.Burst.Editor
{
internal static class LabeledPopup
{
// Because the function given to dropdown menu needs takes its parameter
// in the form of an object, we need someway to wrap the integer into one.
private struct IntegerWrapper
{
public int Value { get; }
public IntegerWrapper(int v)
{
Value = v;
}
}
/// <summary>
/// Enables having several popup menus functioning independently at the same time.
/// </summary>
private class PopperCallBack
{
public static PopperCallBack Instance = null;
/// <summary>
/// Name of the event send when an index have been chosen.
/// </summary>
private const string IndexChangeEventName = "PopperChangingIndex";
private readonly int _controlID;
private int _selectedIdx;
private readonly GUIView _view;
public PopperCallBack(int controlID)
{
_controlID = controlID;
_selectedIdx = -1;
_view = GUIView.current;
}
/// <summary>
/// Tries to get selection chosen by dropdown menu <see cref="controlID"/>.
/// </summary>
/// <param name="controlId">ID of popup menu.</param>
/// <param name="selectedIdx">Current selected index.</param>
/// <returns>
/// Either the selected target, or the <see cref="selectedIdx"/>
/// if none were chosen yet.
/// </returns>
internal static int GetSelectionValue(int controlId, int selectedIdx)
{
var selected = selectedIdx;
// A command event with message IndexChangeEvent will be sent whenever a choice on
// the dropdown menu has been made. So if this is not the case return whatever index was given
var evt = Event.current;
if (evt.type != EventType.ExecuteCommand || evt.commandName != IndexChangeEventName) return selected;
// If this is the popup opened right now: Set the selection idx appropriately
if (Instance != null && controlId == Instance._controlID)
{
selected = Instance._selectedIdx;
Instance = null;
}
return selected;
}
/// <summary>
/// Sets selection on the opened dropdown, and sends an event
/// to the view the popup is within.
/// </summary>
/// <param name="index">Index selected.</param>
internal void SetSelection(object index)
{
_selectedIdx = ((IntegerWrapper)index).Value;
_view.SendEvent(EditorGUIUtility.CommandEvent(IndexChangeEventName));
}
}
/// <summary>
/// Name used for getting a controlID for popup menus.
/// </summary>
private const string LabelControlName = "LabeledPopup";
/// <summary>
/// Create a immediate automatically positioned popup menu.
/// </summary>
/// <param name="index">Current active selection index.</param>
/// <param name="display">Name to display as the button.</param>
/// <param name="options">Display name for the dropdown menu.</param>
/// <returns>The possibly new active selection index.</returns>
public static int Popup(int index, GUIContent display, string[] options)
{
// GetControlRect so space is reserved for the button, and we get a
// position to place the drop down context menu at.
var pos = EditorGUILayout.GetControlRect(false, EditorGUI.kSingleLineHeight,
EditorStyles.popup);
var controlID = GUIUtility.GetControlID(LabelControlName.GetHashCode(), FocusType.Keyboard, pos);
var selected = PopperCallBack.GetSelectionValue(controlID, index);
if (GUI.Button(pos, display, EditorStyles.popup))
{
PopperCallBack.Instance = new PopperCallBack(controlID);
var menu = new GenericMenu();
for (var i = 0; i < options.Length; i++)
{
var size = options[i];
menu.AddItem(EditorGUIUtility.TrTextContent(size), i == index, PopperCallBack.Instance.SetSelection, new IntegerWrapper(i));
}
menu.Popup(pos, index);
}
return selected;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8b3ffde4c8da32a99eafffb5ca0c453d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f429ab8bba2f39c58d3dba8352f74349
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,6 @@
{
"name": "Unity.Burst.Editor",
"references": [ "Unity.Burst" ],
"includePlatforms": [ "Editor" ],
"allowUnsafeCode": true
}

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b75d3cd3037d383a8d1e2f9a26d73d8a
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: