123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- using System;
- using System.Runtime.InteropServices;
- using System.Text;
-
- namespace Unity.Burst
- {
- /// <summary>
- /// Provides helper intrinsics that can be used at runtime.
- /// </summary>
- #if BURST_COMPILER_SHARED
- internal static class BurstRuntimeInternal
- #else
- public static class BurstRuntime
- #endif
- {
- /// <summary>
- /// Gets a 32-bits hashcode from a type computed for the <see cref="System.Type.AssemblyQualifiedName"/>
- /// </summary>
- /// <typeparam name="T">The type to compute the hash from</typeparam>
- /// <returns>The 32-bit hashcode.</returns>
- public static int GetHashCode32<T>()
- {
- #if !UNITY_DOTSRUNTIME_IL2CPP
- return HashCode32<T>.Value;
- #else
- // DOTS Runtime IL2CPP Builds do not use C#'s lazy static initialization order (it uses a C like order, aka random)
- // As such we cannot rely on static init for caching types since any static constructor calling this function
- // may return uninitialized/default-initialized memory
- return HashStringWithFNV1A32(typeof(T).AssemblyQualifiedName);
- #endif
- }
-
- /// <summary>
- /// Gets a 32-bits hashcode from a type computed for the <see cref="System.Type.AssemblyQualifiedName"/>
- /// This method cannot be used from a burst job.
- /// </summary>
- /// <param name="type">The type to compute the hash from</param>
- /// <returns>The 32-bit hashcode.</returns>
- public static int GetHashCode32(Type type)
- {
- return HashStringWithFNV1A32(type.AssemblyQualifiedName);
- }
-
- /// <summary>
- /// Gets a 64-bits hashcode from a type computed for the <see cref="System.Type.AssemblyQualifiedName"/>
- /// </summary>
- /// <typeparam name="T">The type to compute the hash from</typeparam>
- /// <returns>The 64-bit hashcode.</returns>
- public static long GetHashCode64<T>()
- {
- #if !UNITY_DOTSRUNTIME_IL2CPP
- return HashCode64<T>.Value;
- #else
- // DOTS Runtime IL2CPP Builds do not use C#'s lazy static initialization order (it uses a C like order, aka random)
- // As such we cannot rely on static init for caching types since any static constructor calling this function
- // may return uninitialized/default-initialized memory
- return HashStringWithFNV1A64(typeof(T).AssemblyQualifiedName);
- #endif
- }
-
- /// <summary>
- /// Gets a 64-bits hashcode from a type computed for the <see cref="System.Type.AssemblyQualifiedName"/>.
- /// This method cannot be used from a burst job.
- /// </summary>
- /// <param name="type">Type to calculate a hash for</param>
- /// <returns>The 64-bit hashcode.</returns>
- public static long GetHashCode64(Type type)
- {
- return HashStringWithFNV1A64(type.AssemblyQualifiedName);
- }
-
- // method internal as it is used by the compiler directly
- internal static int HashStringWithFNV1A32(string text)
- {
- // Using http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-1a
- // with basis and prime:
- const uint offsetBasis = 2166136261;
- const uint prime = 16777619;
-
- uint result = offsetBasis;
- foreach (var c in text)
- {
- result = prime * (result ^ (byte)(c & 255));
- result = prime * (result ^ (byte)(c >> 8));
- }
- return (int)result;
- }
-
- // method internal as it is used by the compiler directly
- internal static long HashStringWithFNV1A64(string text)
- {
- // Using http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-1a
- // with basis and prime:
- const ulong offsetBasis = 14695981039346656037;
- const ulong prime = 1099511628211;
-
- ulong result = offsetBasis;
- foreach (var c in text)
- {
- result = prime * (result ^ (byte)(c & 255));
- result = prime * (result ^ (byte)(c >> 8));
- }
- return (long)result;
- }
-
- private struct HashCode32<T>
- {
- public static readonly int Value = HashStringWithFNV1A32(typeof(T).AssemblyQualifiedName);
- }
-
- private struct HashCode64<T>
- {
- public static readonly long Value = HashStringWithFNV1A64(typeof(T).AssemblyQualifiedName);
- }
-
- #if !BURST_COMPILER_SHARED
-
- /// <summary>
- /// Allows for loading additional Burst native libraries
- /// Important: Designed for Play mode / Desktop Standalone Players ONLY
- /// In Editor, any libraries that have been loaded will be unloaded on exit of playmode
- /// Only supported from 2020.1 and later. You can use BurstCompiler.IsLoadAdditionalLibrarySupported() to confirm it is available.
- /// </summary>
- /// <param name="pathToLibBurstGenerated">Absolute filesystem location of bursted library to load</param>
- /// <returns>true if the library was loaded successfully</returns>
- public static bool LoadAdditionalLibrary(string pathToLibBurstGenerated)
- {
- if (BurstCompiler.IsLoadAdditionalLibrarySupported())
- {
- return LoadAdditionalLibraryInternal(pathToLibBurstGenerated);
- }
- return false;
- }
-
- internal static bool LoadAdditionalLibraryInternal(string pathToLibBurstGenerated)
- {
- #if !UNITY_DOTSRUNTIME
- return (bool)typeof(Unity.Burst.LowLevel.BurstCompilerService).GetMethod("LoadBurstLibrary").Invoke(null, new object[] { pathToLibBurstGenerated });
- #else
- return false;
- #endif
- }
-
-
- #if UNITY_2020_1_OR_NEWER
- internal static void Initialize()
- {
- }
-
- // Prevent BurstCompilerService.Log from being stripped, introduce PreserveAttribute to avoid
- //requiring a unityengine using directive, il2cpp will see the attribute and know to not strip
- //the Log method and its BurstCompilerService.Log dependency
- internal class PreserveAttribute : System.Attribute {}
-
- [Preserve]
- internal static unsafe void Log(byte* message, int logType, byte* fileName, int lineNumber)
- {
- Unity.Burst.LowLevel.BurstCompilerService.Log((byte*) 0, (Unity.Burst.LowLevel.BurstCompilerService.BurstLogType)logType, message, fileName, lineNumber);
- }
- #elif UNITY_2019_4_OR_NEWER
- // Because we can't back-port the new API BurstCompilerService.Log introduced in 2020.1
- // we are still trying to allow to log on earlier version of Unity by going back to managed
- // code when we are using Debug.Log. It is not great in terms of performance but it should not
- // be a matter when debugging.
-
- internal static unsafe void Log(byte* message, int logType, byte* fileName, int lineNumber)
- {
- var fp = LogHelper.Instance.Data;
- // If we have a domain reload, the function pointer will be cleared, so we can't call it.
- if (fp.IsCreated)
- {
- fp.Invoke(message, logType, fileName, lineNumber);
- }
- }
-
- private unsafe delegate void NativeLogDelegate(byte* message, int logType, byte* filename, int lineNumber);
-
- private static readonly unsafe NativeLogDelegate ManagedNativeLog = ManagedNativeLogImpl;
-
- [AOT.MonoPInvokeCallback(typeof(NativeLogDelegate))]
- private static unsafe void ManagedNativeLogImpl(byte* message, int logType, byte* filename, int lineNumber)
- {
- if (message == null) return;
- int byteCount = 0;
- while (message[byteCount] != 0) byteCount++;
-
- var managedText = Encoding.UTF8.GetString(message, byteCount);
- switch (logType)
- {
- case 1:
- UnityEngine.Debug.LogWarning(managedText);
- break;
- case 2:
- UnityEngine.Debug.LogError(managedText);
- break;
- default:
- UnityEngine.Debug.Log(managedText);
- break;
- }
- }
-
- private class LogHelper
- {
- public static readonly SharedStatic<FunctionPointer<NativeLogDelegate>> Instance = SharedStatic<FunctionPointer<NativeLogDelegate>>.GetOrCreate<LogHelper>();
- }
-
- static BurstRuntime()
- {
- LogHelper.Instance.Data = new FunctionPointer<NativeLogDelegate>(Marshal.GetFunctionPointerForDelegate(ManagedNativeLog));
- }
-
- [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.AfterAssembliesLoaded)]
- internal static void Initialize()
- {
- }
- #else
- internal static void Initialize()
- {
- }
-
- internal static unsafe void Log(byte* message, int logType, byte* fileName, int lineNumber)
- {
- }
- #endif
-
- #endif // !BURST_COMPILER_SHARED
-
-
- /// <summary>
- /// Return a pointer to read-only memory consisting of the literal UTF-8 bytes of a string constant.
- /// </summary>
- /// <param name="str">A string which must a string literal</param>
- /// <param name="byteCount">Receives the number of UTF-8 encoded bytes the constant contains (excluding null terminator)</param>
- /// <returns>A pointer to constant data representing the UTF-8 encoded bytes of the string literal, terminated with a null terminator</returns>
- public unsafe static byte* GetUTF8LiteralPointer(string str, out int byteCount)
- {
- throw new NotImplementedException("This function only works from Burst");
- }
-
- }
- }
|