using System; using System.Collections.Generic; using System.Diagnostics; #if BURST_UNITY_MOCK using System.Runtime.CompilerServices; #endif using Unity.Collections.LowLevel.Unsafe; namespace Unity.Burst { /// /// A structure that allows to share mutable static data between C# and HPC#. /// /// Type of the data to share (must not contain any reference types) public readonly unsafe struct SharedStatic where T : struct { private readonly void* _buffer; private SharedStatic(void* buffer) { _buffer = buffer; CheckIf_T_IsUnmanagedOrThrow(); // We will remove this once we have full support for unmanaged constraints with C# 8.0 } /// /// Get a writable reference to the shared data. /// public ref T Data { get { return ref Unsafe.AsRef(_buffer); } } /// /// Get a direct unsafe pointer to the shared data. /// public void* UnsafeDataPointer { get { return _buffer; } } /// /// Creates a shared static data for the specified context (usable from both C# and HPC#) /// /// A type class that uniquely identifies the this shared data. /// Optional alignment /// A shared static for the specified context public static SharedStatic GetOrCreate(uint alignment = 0) { return GetOrCreateUnsafe( alignment, BurstRuntime.GetHashCode64(), 0); } /// /// Creates a shared static data for the specified context and sub-context (usable from both C# and HPC#) /// /// A type class that uniquely identifies the this shared data. /// A type class that uniquely identifies this shared data within a sub-context of the primary context /// Optional alignment /// A shared static for the specified context public static SharedStatic GetOrCreate(uint alignment = 0) { return GetOrCreateUnsafe( alignment, BurstRuntime.GetHashCode64(), BurstRuntime.GetHashCode64()); } /// /// The default alignment is a user specified one is not provided. /// private const uint DefaultAlignment = 16; /// /// Creates a shared static data unsafely for the specified context and sub-context (usable from both C# and HPC#). /// /// The alignment (specified in bytes). /// The 64-bit hashcode for the shared-static. /// The 64-bit sub-hashcode for the shared-static. /// A newly created or previously cached shared-static for the hashcodes provided. public static SharedStatic GetOrCreateUnsafe(uint alignment, long hashCode, long subHashCode) { return new SharedStatic(SharedStatic.GetOrCreateSharedStaticInternal( hashCode, subHashCode, (uint)UnsafeUtility.SizeOf(), alignment == 0 ? DefaultAlignment : alignment)); } /// /// Creates a shared static data unsafely for the specified context and sub-context (usable from both C# and HPC#). /// /// A type class that uniquely identifies this shared data within a sub-context of the primary context /// The alignment (specified in bytes). /// The 64-bit hashcode for the shared-static. /// A newly created or previously cached shared-static for the hashcodes provided. public static SharedStatic GetOrCreatePartiallyUnsafeWithHashCode(uint alignment, long hashCode) { return new SharedStatic(SharedStatic.GetOrCreateSharedStaticInternal( hashCode, BurstRuntime.GetHashCode64(), (uint)UnsafeUtility.SizeOf(), alignment == 0 ? DefaultAlignment : alignment)); } /// /// Creates a shared static data unsafely for the specified context and sub-context (usable from both C# and HPC#). /// /// A type class that uniquely identifies the this shared data. /// The alignment (specified in bytes). /// The 64-bit sub-hashcode for the shared-static. /// A newly created or previously cached shared-static for the hashcodes provided. public static SharedStatic GetOrCreatePartiallyUnsafeWithSubHashCode(uint alignment, long subHashCode) { return new SharedStatic(SharedStatic.GetOrCreateSharedStaticInternal( BurstRuntime.GetHashCode64(), subHashCode, (uint)UnsafeUtility.SizeOf(), alignment == 0 ? DefaultAlignment : alignment)); } #if !NET_DOTS /// /// Creates a shared static data for the specified context (reflection based, only usable from C#, but not from HPC#) /// /// A type class that uniquely identifies the this shared data /// Optional alignment /// A shared static for the specified context public static SharedStatic GetOrCreate(Type contextType, uint alignment = 0) { return GetOrCreateUnsafe( alignment, BurstRuntime.GetHashCode64(contextType), 0); } /// /// Creates a shared static data for the specified context and sub-context (usable from both C# and HPC#) /// /// A type class that uniquely identifies the this shared data /// A type class that uniquely identifies this shared data within a sub-context of the primary context /// Optional alignment /// A shared static for the specified context public static SharedStatic GetOrCreate(Type contextType, Type subContextType, uint alignment = 0) { return GetOrCreateUnsafe( alignment, BurstRuntime.GetHashCode64(contextType), BurstRuntime.GetHashCode64(subContextType)); } #endif [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] private static void CheckIf_T_IsUnmanagedOrThrow() { if (!UnsafeUtility.IsUnmanaged()) throw new InvalidOperationException($"The type {typeof(T)} used in SharedStatic<{typeof(T)}> must be unmanaged (contain no managed types)."); } } internal static class SharedStatic { [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] private static void CheckSizeOf(uint sizeOf) { if (sizeOf == 0) throw new ArgumentException("sizeOf must be > 0", nameof(sizeOf)); } [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] private static unsafe void CheckResult(void* result) { if (result == null) throw new InvalidOperationException("Unable to create a SharedStatic for this key. This is most likely due to the size of the struct inside of the SharedStatic having changed or the same key being reused for differently sized values. To fix this the editor needs to be restarted."); } // Prevent GetOrCreateSharedMemory from being stripped, by preventing GetOrCreateSharedStaticInteranl fromm being stripped. internal class PreserveAttribute : System.Attribute {} /// /// Get or create a shared-static. /// /// The 64-bit hashcode for the shared-static. /// The 64-bit sub-hashcode for the shared-static. /// The size (in bytes) of the shared static memory region. /// The alignment (in bytes) of the shared static memory region. /// Either a newly created or a previously created memory region that matches the hashcodes provided. [Preserve] public static unsafe void* GetOrCreateSharedStaticInternal(long getHashCode64, long getSubHashCode64, uint sizeOf, uint alignment) { CheckSizeOf(sizeOf); var hash128 = new UnityEngine.Hash128((ulong)getHashCode64, (ulong)getSubHashCode64); var result = Unity.Burst.LowLevel.BurstCompilerService.GetOrCreateSharedMemory(ref hash128, sizeOf, alignment); CheckResult(result); return result; } } }