You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
10 KiB
258 lines
10 KiB
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 |
|
// WARNING: This **must** be kept in sync with the definition in ILPostProcessing.cs! |
|
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 2021.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_2022_1_OR_NEWER |
|
[Preserve] |
|
internal static unsafe void RuntimeLog(byte* message, int logType, byte* fileName, int lineNumber) |
|
{ |
|
Unity.Burst.LowLevel.BurstCompilerService.RuntimeLog((byte*) 0, (Unity.Burst.LowLevel.BurstCompilerService.BurstLogType)logType, message, fileName, lineNumber); |
|
} |
|
#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 void PreventDiscardAttributeStrip() |
|
{ |
|
new BurstDiscardAttribute(); |
|
} |
|
|
|
[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, (byte*) 0, 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"); |
|
} |
|
|
|
} |
|
}
|
|
|