暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

SharedStatic.cs 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #if UNITY_2019_3_OR_NEWER
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. #if BURST_UNITY_MOCK
  6. using System.Runtime.CompilerServices;
  7. #endif
  8. using Unity.Collections.LowLevel.Unsafe;
  9. namespace Unity.Burst
  10. {
  11. /// <summary>
  12. /// A structure that allows to share mutable static data between C# and HPC#.
  13. /// </summary>
  14. /// <typeparam name="T">Type of the data to share (must not contain any reference types)</typeparam>
  15. public readonly unsafe struct SharedStatic<T> where T : struct
  16. {
  17. private readonly void* _buffer;
  18. private SharedStatic(void* buffer)
  19. {
  20. _buffer = buffer;
  21. CheckIf_T_IsUnmanagedOrThrow(); // We will remove this once we have full support for unmanaged constraints with C# 8.0
  22. }
  23. /// <summary>
  24. /// Get a writable reference to the shared data.
  25. /// </summary>
  26. public ref T Data
  27. {
  28. get
  29. {
  30. #if UNITY_DOTSPLAYER
  31. return ref UnsafeUtility.AsRef<T>(_buffer);
  32. #else
  33. return ref Unsafe.AsRef<T>(_buffer);
  34. #endif
  35. }
  36. }
  37. /// <summary>
  38. /// Get a direct unsafe pointer to the shared data.
  39. /// </summary>
  40. public void* UnsafeDataPointer
  41. {
  42. get { return _buffer; }
  43. }
  44. /// <summary>
  45. /// Creates a shared static data for the specified context (usable from both C# and HPC#)
  46. /// </summary>
  47. /// <typeparam name="TContext">A type class that uniquely identifies the this shared data.</typeparam>
  48. /// <param name="alignment">Optional alignment</param>
  49. /// <returns>A shared static for the specified context</returns>
  50. public static SharedStatic<T> GetOrCreate<TContext>(uint alignment = 0)
  51. {
  52. return new SharedStatic<T>(SharedStatic.GetOrCreateSharedStaticInternal(
  53. BurstRuntime.GetHashCode64<TContext>(), 0, (uint)UnsafeUtility.SizeOf<T>(), alignment == 0 ? 4 : alignment));
  54. }
  55. /// <summary>
  56. /// Creates a shared static data for the specified context and sub-context (usable from both C# and HPC#)
  57. /// </summary>
  58. /// <typeparam name="TContext">A type class that uniquely identifies the this shared data.</typeparam>
  59. /// <typeparam name="TSubContext">A type class that uniquely identifies this shared data within a sub-context of the primary context</typeparam>
  60. /// <param name="alignment">Optional alignment</param>
  61. /// <returns>A shared static for the specified context</returns>
  62. public static SharedStatic<T> GetOrCreate<TContext, TSubContext>(uint alignment = 0)
  63. {
  64. return new SharedStatic<T>(SharedStatic.GetOrCreateSharedStaticInternal(
  65. BurstRuntime.GetHashCode64<TContext>(), BurstRuntime.GetHashCode64<TSubContext>(),
  66. (uint)UnsafeUtility.SizeOf<T>(), alignment == 0 ? 4 : alignment));
  67. }
  68. #if !NET_DOTS
  69. /// <summary>
  70. /// Creates a shared static data for the specified context (reflection based, only usable from C#, but not from HPC#)
  71. /// </summary>
  72. /// <param name="contextType">A type class that uniquely identifies the this shared data</param>
  73. /// <param name="alignment">Optional alignment</param>
  74. /// <returns>A shared static for the specified context</returns>
  75. public static SharedStatic<T> GetOrCreate(Type contextType, uint alignment = 0)
  76. {
  77. return new SharedStatic<T>(SharedStatic.GetOrCreateSharedStaticInternal(
  78. BurstRuntime.GetHashCode64(contextType), 0, (uint)UnsafeUtility.SizeOf<T>(), alignment == 0 ? 4 : alignment));
  79. }
  80. /// <summary>
  81. /// Creates a shared static data for the specified context and sub-context (usable from both C# and HPC#)
  82. /// </summary>
  83. /// <param name="contextType">A type class that uniquely identifies the this shared data</param>
  84. /// <param name="subContextType">A type class that uniquely identifies this shared data within a sub-context of the primary context</param>
  85. /// <param name="alignment">Optional alignment</param>
  86. /// <returns>A shared static for the specified context</returns>
  87. public static SharedStatic<T> GetOrCreate(Type contextType, Type subContextType, uint alignment = 0)
  88. {
  89. return new SharedStatic<T>(SharedStatic.GetOrCreateSharedStaticInternal(
  90. BurstRuntime.GetHashCode64(contextType), BurstRuntime.GetHashCode64(subContextType),
  91. (uint)UnsafeUtility.SizeOf<T>(), alignment == 0 ? (uint)4 : alignment));
  92. }
  93. #endif
  94. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  95. private static void CheckIf_T_IsUnmanagedOrThrow()
  96. {
  97. if (!UnsafeUtility.IsUnmanaged<T>())
  98. throw new InvalidOperationException($"The type {typeof(T)} used in SharedStatic<{typeof(T)}> must be unmanaged (contain no managed types).");
  99. }
  100. }
  101. internal static class SharedStatic
  102. {
  103. #if !NET_DOTS
  104. private static readonly Dictionary<long, Type> HashToType = new Dictionary<long, Type>();
  105. public static unsafe void* GetOrCreateSharedStaticInternal(Type typeContext, Type subTypeContext, uint sizeOf,
  106. uint alignment)
  107. {
  108. return GetOrCreateSharedStaticInternal(GetSafeHashCode64(typeContext), GetSafeHashCode64(subTypeContext),
  109. sizeOf, alignment);
  110. }
  111. private static long GetSafeHashCode64(Type type)
  112. {
  113. var hash = BurstRuntime.GetHashCode64(type);
  114. lock (HashToType)
  115. {
  116. Type existingType;
  117. if (HashToType.TryGetValue(hash, out existingType))
  118. {
  119. if (existingType != type)
  120. {
  121. var message = $"The type `{type}` has a hash conflict with `{existingType}`";
  122. #if !BURST_UNITY_MOCK && !UNITY_DOTSPLAYER
  123. UnityEngine.Debug.LogError(message);
  124. #endif
  125. throw new InvalidOperationException(message);
  126. }
  127. }
  128. else
  129. {
  130. HashToType.Add(hash, type);
  131. }
  132. }
  133. return hash;
  134. }
  135. #endif
  136. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  137. private static void CheckSizeOf(uint sizeOf)
  138. {
  139. if (sizeOf == 0) throw new ArgumentException("sizeOf must be > 0", nameof(sizeOf));
  140. }
  141. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  142. private static unsafe void CheckResult(void* result)
  143. {
  144. if (result == null)
  145. 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.");
  146. }
  147. // Prevent GetOrCreateSharedMemory from being stripped, by preventing GetOrCreateSharedStaticInteranl fromm being stripped.
  148. internal class PreserveAttribute : System.Attribute {}
  149. [Preserve]
  150. public static unsafe void* GetOrCreateSharedStaticInternal(long getHashCode64, long getSubHashCode64, uint sizeOf, uint alignment)
  151. {
  152. CheckSizeOf(sizeOf);
  153. var hash128 = new UnityEngine.Hash128((ulong)getHashCode64, (ulong)getSubHashCode64);
  154. var result = Unity.Burst.LowLevel.BurstCompilerService.GetOrCreateSharedMemory(ref hash128, sizeOf, alignment);
  155. CheckResult(result);
  156. return result;
  157. }
  158. }
  159. }
  160. #endif