No Description
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.

ArraySlice.cs 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. using System;
  2. using Unity.Collections;
  3. using System.Diagnostics;
  4. using System.Runtime.InteropServices;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. namespace UnityEngine.Rendering.Universal.UTess
  7. {
  8. [StructLayout(LayoutKind.Sequential)]
  9. [DebuggerDisplay("Length = {Length}")]
  10. [DebuggerTypeProxy(typeof(ArraySliceDebugView<>))]
  11. internal unsafe struct ArraySlice<T> : System.IEquatable<ArraySlice<T>> where T : struct
  12. {
  13. [NativeDisableUnsafePtrRestriction] internal byte* m_Buffer;
  14. internal int m_Stride;
  15. internal int m_Length;
  16. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  17. internal int m_MinIndex;
  18. internal int m_MaxIndex;
  19. internal AtomicSafetyHandle m_Safety;
  20. #endif
  21. public ArraySlice(NativeArray<T> array, int start, int length)
  22. {
  23. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  24. if (start < 0)
  25. throw new ArgumentOutOfRangeException(nameof(start), $"Slice start {start} < 0.");
  26. if (length < 0)
  27. throw new ArgumentOutOfRangeException(nameof(length), $"Slice length {length} < 0.");
  28. if (start + length > array.Length)
  29. throw new ArgumentException(
  30. $"Slice start + length ({start + length}) range must be <= array.Length ({array.Length})");
  31. m_MinIndex = 0;
  32. m_MaxIndex = length - 1;
  33. m_Safety = Unity.Collections.LowLevel.Unsafe.NativeArrayUnsafeUtility.GetAtomicSafetyHandle(array);
  34. #endif
  35. m_Stride = UnsafeUtility.SizeOf<T>();
  36. var ptr = (byte*)array.GetUnsafePtr() + m_Stride * start;
  37. m_Buffer = ptr;
  38. m_Length = length;
  39. }
  40. public bool Equals(ArraySlice<T> other)
  41. {
  42. return m_Buffer == other.m_Buffer && m_Stride == other.m_Stride && m_Length == other.m_Length;
  43. }
  44. public override bool Equals(object obj)
  45. {
  46. if (ReferenceEquals(null, obj)) return false;
  47. return obj is ArraySlice<T> && Equals((ArraySlice<T>)obj);
  48. }
  49. public override int GetHashCode()
  50. {
  51. unchecked
  52. {
  53. var hashCode = (int)m_Buffer;
  54. hashCode = (hashCode * 397) ^ m_Stride;
  55. hashCode = (hashCode * 397) ^ m_Length;
  56. return hashCode;
  57. }
  58. }
  59. public static bool operator==(ArraySlice<T> left, ArraySlice<T> right)
  60. {
  61. return left.Equals(right);
  62. }
  63. public static bool operator!=(ArraySlice<T> left, ArraySlice<T> right)
  64. {
  65. return !left.Equals(right);
  66. }
  67. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  68. // These are double-whammy excluded to we can elide bounds checks in the Burst disassembly view
  69. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  70. void CheckReadIndex(int index)
  71. {
  72. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  73. if (index < m_MinIndex || index > m_MaxIndex)
  74. FailOutOfRangeError(index);
  75. #endif
  76. }
  77. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  78. void CheckWriteIndex(int index)
  79. {
  80. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  81. if (index < m_MinIndex || index > m_MaxIndex)
  82. FailOutOfRangeError(index);
  83. #endif
  84. }
  85. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  86. private void FailOutOfRangeError(int index)
  87. {
  88. if (index < Length && (m_MinIndex != 0 || m_MaxIndex != Length - 1))
  89. throw new System.IndexOutOfRangeException(
  90. $"Index {index} is out of restricted IJobParallelFor range [{m_MinIndex}...{m_MaxIndex}] in ReadWriteBuffer.\n" +
  91. "ReadWriteBuffers are restricted to only read & write the element at the job index. " +
  92. "You can use double buffering strategies to avoid race conditions due to " +
  93. "reading & writing in parallel to the same elements from a job.");
  94. throw new System.IndexOutOfRangeException($"Index {index} is out of range of '{Length}' Length.");
  95. }
  96. #endif
  97. public static unsafe ArraySlice<T> ConvertExistingDataToArraySlice(void* dataPointer, int stride, int length)
  98. {
  99. if (length < 0)
  100. throw new System.ArgumentException($"Invalid length of '{length}'. It must be greater than 0.",
  101. nameof(length));
  102. if (stride < 0)
  103. throw new System.ArgumentException($"Invalid stride '{stride}'. It must be greater than 0.",
  104. nameof(stride));
  105. var newSlice = new ArraySlice<T>
  106. {
  107. m_Stride = stride,
  108. m_Buffer = (byte*)dataPointer,
  109. m_Length = length,
  110. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  111. m_MinIndex = 0,
  112. m_MaxIndex = length - 1,
  113. #endif
  114. };
  115. return newSlice;
  116. }
  117. public T this[int index]
  118. {
  119. get
  120. {
  121. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  122. CheckReadIndex(index);
  123. #endif
  124. return UnsafeUtility.ReadArrayElementWithStride<T>(m_Buffer, index, m_Stride);
  125. }
  126. [WriteAccessRequired]
  127. set
  128. {
  129. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  130. CheckWriteIndex(index);
  131. #endif
  132. UnsafeUtility.WriteArrayElementWithStride(m_Buffer, index, m_Stride, value);
  133. }
  134. }
  135. internal unsafe void* GetUnsafeReadOnlyPtr()
  136. {
  137. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  138. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  139. #endif
  140. return m_Buffer;
  141. }
  142. internal void CopyTo(T[] array)
  143. {
  144. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  145. if (Length != array.Length)
  146. throw new ArgumentException($"array.Length ({array.Length}) does not match the Length of this instance ({Length}).", nameof(array));
  147. #endif
  148. unsafe
  149. {
  150. GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
  151. IntPtr addr = handle.AddrOfPinnedObject();
  152. var sizeOf = UnsafeUtility.SizeOf<T>();
  153. UnsafeUtility.MemCpyStride((byte*)addr, sizeOf, this.GetUnsafeReadOnlyPtr(), Stride, sizeOf, m_Length);
  154. handle.Free();
  155. }
  156. }
  157. internal T[] ToArray()
  158. {
  159. var array = new T[Length];
  160. CopyTo(array);
  161. return array;
  162. }
  163. public int Stride => m_Stride;
  164. public int Length => m_Length;
  165. }
  166. /// <summary>
  167. /// DebuggerTypeProxy for <see cref="ArraySlice{T}"/>
  168. /// </summary>
  169. internal sealed class ArraySliceDebugView<T> where T : struct
  170. {
  171. ArraySlice<T> m_Slice;
  172. public ArraySliceDebugView(ArraySlice<T> slice)
  173. {
  174. m_Slice = slice;
  175. }
  176. public T[] Items
  177. {
  178. get { return m_Slice.ToArray(); }
  179. }
  180. }
  181. }