FixedChunkNativeArray.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. // Magica Cloth.
  2. // Copyright (c) MagicaSoft, 2020-2022.
  3. // https://magicasoft.jp
  4. using System;
  5. using System.Collections.Generic;
  6. using Unity.Collections;
  7. using UnityEngine;
  8. namespace MagicaCloth
  9. {
  10. /// <summary>
  11. /// かたまり(チャンク)ごとに確保した固定インデックスNativeList
  12. /// 一度確保したインデックスはズレない(ここ重要)
  13. /// </summary>
  14. /// <typeparam name="T"></typeparam>
  15. public class FixedChunkNativeArray<T> : IDisposable where T : struct
  16. {
  17. /// <summary>
  18. /// ネイティブリスト
  19. /// </summary>
  20. NativeArray<T> nativeArray0;
  21. NativeArray<T> nativeArray1;
  22. /// <summary>
  23. /// ネイティブリストの配列数
  24. /// ※ジョブでエラーが出ないように事前に確保しておく
  25. /// </summary>
  26. int nativeLength;
  27. /// <summary>
  28. /// 空インデックススタック
  29. /// </summary>
  30. List<ChunkData> emptyChunkList = new List<ChunkData>();
  31. /// <summary>
  32. /// 使用インデックスセット
  33. /// </summary>
  34. List<ChunkData> useChunkList = new List<ChunkData>();
  35. int chunkSeed;
  36. //int initLength = 256;
  37. int initLength = 64;
  38. T emptyElement;
  39. int useLength;
  40. //=========================================================================================
  41. public FixedChunkNativeArray()
  42. {
  43. nativeArray0 = new NativeArray<T>(initLength, Allocator.Persistent);
  44. nativeLength = nativeArray0.Length;
  45. useLength = 0;
  46. }
  47. //public FixedChunkNativeArray(int length)
  48. //{
  49. // initLength = length;
  50. // nativeArray0 = new NativeArray<T>(initLength, Allocator.Persistent);
  51. // nativeLength = nativeArray0.Length;
  52. // useLength = 0;
  53. //}
  54. public void Dispose()
  55. {
  56. if (nativeArray0.IsCreated)
  57. {
  58. nativeArray0.Dispose();
  59. }
  60. if (nativeArray1.IsCreated)
  61. {
  62. nativeArray1.Dispose();
  63. }
  64. nativeLength = 0;
  65. useLength = 0;
  66. emptyChunkList.Clear();
  67. useChunkList.Clear();
  68. }
  69. public void SetEmptyElement(T empty)
  70. {
  71. emptyElement = empty;
  72. }
  73. //=========================================================================================
  74. /// <summary>
  75. /// データチャンクの追加
  76. /// </summary>
  77. /// <param name="length"></param>
  78. /// <returns></returns>
  79. public ChunkData AddChunk(int length)
  80. {
  81. // 再利用チェック
  82. for (int i = 0; i < emptyChunkList.Count; i++)
  83. {
  84. var cdata = emptyChunkList[i];
  85. if (cdata.dataLength >= length)
  86. {
  87. // このチャンクを再利用する
  88. int remainder = cdata.dataLength - length;
  89. if (remainder > 0)
  90. {
  91. // 分割
  92. var rchunk = new ChunkData()
  93. {
  94. chunkNo = ++chunkSeed,
  95. startIndex = cdata.startIndex + length,
  96. dataLength = remainder,
  97. };
  98. emptyChunkList[i] = rchunk;
  99. }
  100. else
  101. {
  102. emptyChunkList.RemoveAt(i);
  103. }
  104. cdata.dataLength = length;
  105. // 使用リストに追加
  106. useChunkList.Add(cdata);
  107. return cdata;
  108. }
  109. }
  110. // 新規追加
  111. var data = new ChunkData()
  112. {
  113. chunkNo = ++chunkSeed,
  114. startIndex = useLength,
  115. dataLength = length,
  116. };
  117. useChunkList.Add(data);
  118. useLength += length;
  119. if (nativeArray0.Length < useLength)
  120. {
  121. // 拡張
  122. int len = nativeArray0.Length;
  123. while (len < useLength)
  124. len += Mathf.Min(len, 4096);
  125. //len += len;
  126. var nativeArray2 = new NativeArray<T>(len, Allocator.Persistent);
  127. nativeArray2.CopyFromFast(nativeArray0);
  128. nativeArray0.Dispose();
  129. nativeArray0 = nativeArray2;
  130. nativeLength = nativeArray0.Length;
  131. }
  132. return data;
  133. }
  134. /// <summary>
  135. /// サイズ1のチャンクを追加しデータを設定する
  136. /// </summary>
  137. /// <param name="data"></param>
  138. /// <returns></returns>
  139. public ChunkData Add(T data)
  140. {
  141. var c = AddChunk(1);
  142. nativeArray0[c.startIndex] = data;
  143. return c;
  144. }
  145. /// <summary>
  146. /// データチャンクの削除
  147. /// </summary>
  148. /// <param name="chunkNo"></param>
  149. public void RemoveChunk(int chunkNo)
  150. {
  151. for (int i = 0; i < useChunkList.Count; i++)
  152. {
  153. if (useChunkList[i].chunkNo == chunkNo)
  154. {
  155. // このチャンクを削除する
  156. var cdata = useChunkList[i];
  157. useChunkList.RemoveAt(i);
  158. // データクリア
  159. nativeArray0.SetValue(cdata.startIndex, cdata.dataLength, emptyElement);
  160. // 前後の未使用チャンクと接続できるなら結合する
  161. for (int j = 0; j < emptyChunkList.Count;)
  162. {
  163. var edata = emptyChunkList[j];
  164. if ((edata.startIndex + edata.dataLength) == cdata.startIndex)
  165. {
  166. // 結合
  167. edata.dataLength += cdata.dataLength;
  168. cdata = edata;
  169. emptyChunkList.RemoveAt(j);
  170. continue;
  171. }
  172. else if (edata.startIndex == (cdata.startIndex + cdata.dataLength))
  173. {
  174. // 結合
  175. cdata.dataLength += edata.dataLength;
  176. emptyChunkList.RemoveAt(j);
  177. continue;
  178. }
  179. j++;
  180. }
  181. // チャンクを空リストに追加
  182. emptyChunkList.Add(cdata);
  183. return;
  184. }
  185. }
  186. }
  187. /// <summary>
  188. /// データチャンクの削除
  189. /// </summary>
  190. /// <param name="chunk"></param>
  191. public void RemoveChunk(ChunkData chunk)
  192. {
  193. if (chunk.IsValid())
  194. RemoveChunk(chunk.chunkNo);
  195. }
  196. /// <summary>
  197. /// 指定データで埋める
  198. /// </summary>
  199. /// <param name="chunk"></param>
  200. /// <param name="data"></param>
  201. public void Fill(ChunkData chunk, T data)
  202. {
  203. //int end = chunk.startIndex + chunk.dataLength;
  204. //for (int i = chunk.startIndex; i < end; i++)
  205. //{
  206. // nativeArray[i] = data;
  207. //}
  208. nativeArray0.SetValue(chunk.startIndex, chunk.dataLength, data);
  209. }
  210. /// <summary>
  211. /// 確保されているネイティブ配列の要素数を返す
  212. /// </summary>
  213. public int Length
  214. {
  215. get
  216. {
  217. return nativeLength;
  218. }
  219. }
  220. /// <summary>
  221. /// 実際に利用されているチャンク数を返す
  222. /// </summary>
  223. public int ChunkCount
  224. {
  225. get
  226. {
  227. return useChunkList.Count;
  228. }
  229. }
  230. /// <summary>
  231. /// 実際に使用されている要素数を返す
  232. /// </summary>
  233. public int Count
  234. {
  235. get
  236. {
  237. int cnt = 0;
  238. foreach (var c in useChunkList)
  239. cnt += c.dataLength;
  240. return cnt;
  241. }
  242. }
  243. public T this[int index]
  244. {
  245. get
  246. {
  247. return nativeArray0[index];
  248. }
  249. set
  250. {
  251. nativeArray0[index] = value;
  252. }
  253. }
  254. //public void Clear()
  255. //{
  256. // if (nativeArray0.IsCreated)
  257. // nativeArray0.Dispose();
  258. // nativeArray0 = new NativeArray<T>(initLength, Allocator.Persistent);
  259. // nativeLength = initLength;
  260. // useLength = 0;
  261. // emptyChunkList.Clear();
  262. // useChunkList.Clear();
  263. //}
  264. //public T[] ToArray()
  265. //{
  266. // return nativeArray.ToArray();
  267. //}
  268. /// <summary>
  269. /// Jobで利用する場合はこの関数でNativeArrayに変換して受け渡す
  270. /// </summary>
  271. /// <returns></returns>
  272. public NativeArray<T> ToJobArray()
  273. {
  274. return nativeArray0;
  275. }
  276. public NativeArray<T> ToJobArray(int bufferIndex)
  277. {
  278. return bufferIndex == 0 ? nativeArray0 : nativeArray1;
  279. }
  280. //public NativeArray<T> BackJobArray()
  281. //{
  282. // return nativeArray1;
  283. //}
  284. public void SwapBuffer()
  285. {
  286. var back = nativeArray1;
  287. nativeArray1 = nativeArray0;
  288. // サイズを合わせる
  289. if (back.IsCreated == false || back.Length != nativeArray0.Length)
  290. {
  291. if (back.IsCreated)
  292. back.Dispose();
  293. //back = new NativeArray<T>(nativeArray0.Length, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  294. back = new NativeArray<T>(nativeArray0.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
  295. back.CopyFromFast(nativeArray0);
  296. //Debug.Log("★サイズ変更!");
  297. }
  298. nativeArray0 = back;
  299. }
  300. //=========================================================================================
  301. public override string ToString()
  302. {
  303. string str = string.Empty;
  304. str += "nativeList length=" + Length + "\n";
  305. str += "use chunk count=" + ChunkCount + "\n";
  306. str += "empty chunk count=" + emptyChunkList.Count + "\n";
  307. str += "<< use chunks >>\n";
  308. foreach (var cdata in useChunkList)
  309. {
  310. str += cdata;
  311. }
  312. str += "<< empty chunks >>\n";
  313. foreach (var cdata in emptyChunkList)
  314. {
  315. str += cdata;
  316. }
  317. return str;
  318. }
  319. }
  320. }