initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cf87faa2d38c376e8e9adb8eb79abd10
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 86710f5f973f3eb6ac4556540734abe2
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: baf945884d1937c2a53bce1dfcac594c
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: caa879909c953e51b623b5371e13b0dc
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3b07e41fd0073a288687109ac0c6250f
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 60718cfd7019357fa8f224817c4f4e31
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 59dd88516199395585b8d7d3fcb486f4
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0e74c9ce3b3038e298ae140ed24be9a6
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ffabd1fbe2ab3d59a50128c0669b5791
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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))]
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 196062cbef3533e384a45a204b6b9b64
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4783a0e50db93e7bafe8dae157848042
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
194
Library/PackageCache/com.unity.burst@1.8.4/Editor/BurstMenu.cs
Normal file
194
Library/PackageCache/com.unity.burst@1.8.4/Editor/BurstMenu.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 10cda29925873fe1b9148e7e00e4d297
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 502c484521bc39a9950d91fdf34fd285
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8b3ffde4c8da32a99eafffb5ca0c453d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3267
Library/PackageCache/com.unity.burst@1.8.4/Editor/LongTextArea.cs
Normal file
3267
Library/PackageCache/com.unity.burst@1.8.4/Editor/LongTextArea.cs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f429ab8bba2f39c58d3dba8352f74349
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "Unity.Burst.Editor",
|
||||
"references": [ "Unity.Burst" ],
|
||||
"includePlatforms": [ "Editor" ],
|
||||
"allowUnsafeCode": true
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b75d3cd3037d383a8d1e2f9a26d73d8a
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Add table
Add a link
Reference in a new issue