A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4#if BURST_UNITY_MOCK
5using System.Runtime.CompilerServices;
6#endif
7using Unity.Collections.LowLevel.Unsafe;
8
9namespace 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
19 private SharedStatic(void* buffer)
20 {
21 _buffer = buffer;
22 CheckIf_T_IsUnmanagedOrThrow(); // We will remove this once we have full support for unmanaged constraints with C# 8.0
23 }
24
25 /// <summary>
26 /// Get a writable reference to the shared data.
27 /// </summary>
28 public ref T Data
29 {
30 get
31 {
32 return ref Unsafe.AsRef<T>(_buffer);
33 }
34 }
35
36 /// <summary>
37 /// Get a direct unsafe pointer to the shared data.
38 /// </summary>
39 public void* UnsafeDataPointer
40 {
41 get { return _buffer; }
42 }
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 GetOrCreateUnsafe(
53 alignment,
54 BurstRuntime.GetHashCode64<TContext>(),
55 0);
56 }
57
58 /// <summary>
59 /// Creates a shared static data for the specified context and sub-context (usable from both C# and HPC#)
60 /// </summary>
61 /// <typeparam name="TContext">A type class that uniquely identifies the this shared data.</typeparam>
62 /// <typeparam name="TSubContext">A type class that uniquely identifies this shared data within a sub-context of the primary context</typeparam>
63 /// <param name="alignment">Optional alignment</param>
64 /// <returns>A shared static for the specified context</returns>
65 public static SharedStatic<T> GetOrCreate<TContext, TSubContext>(uint alignment = 0)
66 {
67 return GetOrCreateUnsafe(
68 alignment,
69 BurstRuntime.GetHashCode64<TContext>(),
70 BurstRuntime.GetHashCode64<TSubContext>());
71 }
72
73 /// <summary>
74 /// The default alignment is a user specified one is not provided.
75 /// </summary>
76 private const uint DefaultAlignment = 16;
77
78 /// <summary>
79 /// Creates a shared static data unsafely for the specified context and sub-context (usable from both C# and HPC#).
80 /// </summary>
81 /// <param name="alignment">The alignment (specified in bytes).</param>
82 /// <param name="hashCode">The 64-bit hashcode for the shared-static.</param>
83 /// <param name="subHashCode">The 64-bit sub-hashcode for the shared-static.</param>
84 /// <returns>A newly created or previously cached shared-static for the hashcodes provided.</returns>
85 public static SharedStatic<T> GetOrCreateUnsafe(uint alignment, long hashCode, long subHashCode)
86 {
87 return new SharedStatic<T>(SharedStatic.GetOrCreateSharedStaticInternal(
88 hashCode,
89 subHashCode,
90 (uint)UnsafeUtility.SizeOf<T>(),
91 alignment == 0 ? DefaultAlignment : alignment));
92 }
93
94 /// <summary>
95 /// Creates a shared static data unsafely for the specified context and sub-context (usable from both C# and HPC#).
96 /// </summary>
97 /// <typeparam name="TSubContext">A type class that uniquely identifies this shared data within a sub-context of the primary context</typeparam>
98 /// <param name="alignment">The alignment (specified in bytes).</param>
99 /// <param name="hashCode">The 64-bit hashcode for the shared-static.</param>
100 /// <returns>A newly created or previously cached shared-static for the hashcodes provided.</returns>
101 public static SharedStatic<T> GetOrCreatePartiallyUnsafeWithHashCode<TSubContext>(uint alignment, long hashCode)
102 {
103 return new SharedStatic<T>(SharedStatic.GetOrCreateSharedStaticInternal(
104 hashCode,
105 BurstRuntime.GetHashCode64<TSubContext>(),
106 (uint)UnsafeUtility.SizeOf<T>(),
107 alignment == 0 ? DefaultAlignment : alignment));
108 }
109
110 /// <summary>
111 /// Creates a shared static data unsafely for the specified context and sub-context (usable from both C# and HPC#).
112 /// </summary>
113 /// <typeparam name="TContext">A type class that uniquely identifies the this shared data.</typeparam>
114 /// <param name="alignment">The alignment (specified in bytes).</param>
115 /// <param name="subHashCode">The 64-bit sub-hashcode for the shared-static.</param>
116 /// <returns>A newly created or previously cached shared-static for the hashcodes provided.</returns>
117 public static SharedStatic<T> GetOrCreatePartiallyUnsafeWithSubHashCode<TContext>(uint alignment, long subHashCode)
118 {
119 return new SharedStatic<T>(SharedStatic.GetOrCreateSharedStaticInternal(
120 BurstRuntime.GetHashCode64<TContext>(),
121 subHashCode,
122 (uint)UnsafeUtility.SizeOf<T>(),
123 alignment == 0 ? DefaultAlignment : alignment));
124 }
125
126#if !NET_DOTS
127 /// <summary>
128 /// Creates a shared static data for the specified context (reflection based, only usable from C#, but not from HPC#)
129 /// </summary>
130 /// <param name="contextType">A type class that uniquely identifies the this shared data</param>
131 /// <param name="alignment">Optional alignment</param>
132 /// <returns>A shared static for the specified context</returns>
133 public static SharedStatic<T> GetOrCreate(Type contextType, uint alignment = 0)
134 {
135 return GetOrCreateUnsafe(
136 alignment,
137 BurstRuntime.GetHashCode64(contextType),
138 0);
139 }
140
141 /// <summary>
142 /// Creates a shared static data for the specified context and sub-context (usable from both C# and HPC#)
143 /// </summary>
144 /// <param name="contextType">A type class that uniquely identifies the this shared data</param>
145 /// <param name="subContextType">A type class that uniquely identifies this shared data within a sub-context of the primary context</param>
146 /// <param name="alignment">Optional alignment</param>
147 /// <returns>A shared static for the specified context</returns>
148 public static SharedStatic<T> GetOrCreate(Type contextType, Type subContextType, uint alignment = 0)
149 {
150 return GetOrCreateUnsafe(
151 alignment,
152 BurstRuntime.GetHashCode64(contextType),
153 BurstRuntime.GetHashCode64(subContextType));
154 }
155#endif
156
157 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
158 private static void CheckIf_T_IsUnmanagedOrThrow()
159 {
160 if (!UnsafeUtility.IsUnmanaged<T>())
161 throw new InvalidOperationException($"The type {typeof(T)} used in SharedStatic<{typeof(T)}> must be unmanaged (contain no managed types).");
162 }
163 }
164
165 internal static class SharedStatic
166 {
167 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
168 private static void CheckSizeOf(uint sizeOf)
169 {
170 if (sizeOf == 0) throw new ArgumentException("sizeOf must be > 0", nameof(sizeOf));
171 }
172
173 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
174 private static unsafe void CheckResult(void* result)
175 {
176 if (result == null)
177 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.");
178 }
179
180 // Prevent GetOrCreateSharedMemory from being stripped, by preventing GetOrCreateSharedStaticInteranl fromm being stripped.
181 internal class PreserveAttribute : System.Attribute {}
182
183 /// <summary>
184 /// Get or create a shared-static.
185 /// </summary>
186 /// <param name="getHashCode64">The 64-bit hashcode for the shared-static.</param>
187 /// <param name="getSubHashCode64">The 64-bit sub-hashcode for the shared-static.</param>
188 /// <param name="sizeOf">The size (in bytes) of the shared static memory region.</param>
189 /// <param name="alignment">The alignment (in bytes) of the shared static memory region.</param>
190 /// <returns>Either a newly created or a previously created memory region that matches the hashcodes provided.
191 [Preserve]
192 public static unsafe void* GetOrCreateSharedStaticInternal(long getHashCode64, long getSubHashCode64, uint sizeOf, uint alignment)
193 {
194 CheckSizeOf(sizeOf);
195 var hash128 = new UnityEngine.Hash128((ulong)getHashCode64, (ulong)getSubHashCode64);
196 var result = Unity.Burst.LowLevel.BurstCompilerService.GetOrCreateSharedMemory(ref hash128, sizeOf, alignment);
197 CheckResult(result);
198 return result;
199 }
200 }
201}