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.

SpriteSkinComposite.cs 34KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. using System;
  2. using Unity.Mathematics;
  3. using System.Collections.Generic;
  4. using Unity.Collections;
  5. using Unity.Jobs;
  6. using Unity.Collections.LowLevel.Unsafe;
  7. using UnityEngine.U2D.Common;
  8. using Unity.Burst;
  9. using Unity.Profiling;
  10. using UnityEngine.Assertions;
  11. namespace UnityEngine.U2D.Animation
  12. {
  13. internal struct PerSkinJobData
  14. {
  15. public int deformVerticesStartPos;
  16. public int2 bindPosesIndex;
  17. public int2 verticesIndex;
  18. }
  19. internal struct SpriteSkinData
  20. {
  21. public NativeCustomSlice<Vector3> vertices;
  22. public NativeCustomSlice<BoneWeight> boneWeights;
  23. public NativeCustomSlice<Matrix4x4> bindPoses;
  24. public NativeCustomSlice<Vector4> tangents;
  25. public bool hasTangents;
  26. public int spriteVertexStreamSize;
  27. public int spriteVertexCount;
  28. public int tangentVertexOffset;
  29. public int deformVerticesStartPos;
  30. public int transformId;
  31. public NativeCustomSlice<int> boneTransformId;
  32. }
  33. [BurstCompile]
  34. internal struct PrepareDeformJob :IJob
  35. {
  36. [ReadOnly]
  37. public NativeArray<PerSkinJobData> perSkinJobData;
  38. [ReadOnly]
  39. public int batchDataSize;
  40. [WriteOnly]
  41. public NativeArray<int2> boneLookupData;
  42. [WriteOnly]
  43. public NativeArray<int2> vertexLookupData;
  44. public void Execute()
  45. {
  46. for (var i = 0; i < batchDataSize; ++i)
  47. {
  48. var jobData = perSkinJobData[i];
  49. for (int k = 0, j = jobData.bindPosesIndex.x; j < jobData.bindPosesIndex.y; ++j, ++k)
  50. {
  51. boneLookupData[j] = new int2(i, k);
  52. }
  53. for (int k = 0, j = jobData.verticesIndex.x; j < jobData.verticesIndex.y; ++j, ++k)
  54. {
  55. vertexLookupData[j] = new int2(i, k);
  56. }
  57. }
  58. }
  59. }
  60. [BurstCompile]
  61. internal struct BoneDeformBatchedJob : IJobParallelFor
  62. {
  63. [ReadOnly]
  64. public NativeArray<float4x4> boneTransform;
  65. [ReadOnly]
  66. public NativeArray<float4x4> rootTransform;
  67. [ReadOnly]
  68. public NativeArray<int2> boneLookupData;
  69. [ReadOnly]
  70. public NativeArray<SpriteSkinData> spriteSkinData;
  71. [ReadOnly]
  72. public NativeHashMap<int, TransformAccessJob.TransformData> rootTransformIndex;
  73. [ReadOnly]
  74. public NativeHashMap<int, TransformAccessJob.TransformData> boneTransformIndex;
  75. [WriteOnly]
  76. public NativeArray<float4x4> finalBoneTransforms;
  77. public void Execute(int i)
  78. {
  79. var x = boneLookupData[i].x;
  80. var y = boneLookupData[i].y;
  81. var ssd = spriteSkinData[x];
  82. var v = ssd.boneTransformId[y];
  83. var index = boneTransformIndex[v].transformIndex;
  84. if (index < 0)
  85. return;
  86. var aa = boneTransform[index];
  87. var bb = ssd.bindPoses[y];
  88. var cc = rootTransformIndex[ssd.transformId].transformIndex;
  89. finalBoneTransforms[i] = math.mul(rootTransform[cc], math.mul(aa, bb));
  90. }
  91. }
  92. [BurstCompile]
  93. internal struct SkinDeformBatchedJob : IJobParallelFor
  94. {
  95. public NativeSlice<byte> vertices;
  96. [ReadOnly]
  97. public NativeArray<float4x4> finalBoneTransforms;
  98. [ReadOnly]
  99. public NativeArray<PerSkinJobData> perSkinJobData;
  100. [ReadOnly]
  101. public NativeArray<SpriteSkinData> spriteSkinData;
  102. [ReadOnly]
  103. public NativeArray<int2> vertexLookupData;
  104. public unsafe void Execute(int i)
  105. {
  106. var j = vertexLookupData[i].x;
  107. var k = vertexLookupData[i].y;
  108. var perSkinData = perSkinJobData[j];
  109. var spriteSkin = spriteSkinData[j];
  110. var srcVertex = (float3)spriteSkin.vertices[k];
  111. var tangents = (float4)spriteSkin.tangents[k];
  112. var influence = spriteSkin.boneWeights[k];
  113. var bone0 = influence.boneIndex0 + perSkinData.bindPosesIndex.x;
  114. var bone1 = influence.boneIndex1 + perSkinData.bindPosesIndex.x;
  115. var bone2 = influence.boneIndex2 + perSkinData.bindPosesIndex.x;
  116. var bone3 = influence.boneIndex3 + perSkinData.bindPosesIndex.x;
  117. var deformedPosOffset = (byte*)vertices.GetUnsafePtr();
  118. var deformedPosStart = deformedPosOffset + spriteSkin.deformVerticesStartPos;
  119. var deformableVerticesFloat3 = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<float3>(deformedPosStart, spriteSkin.spriteVertexStreamSize, spriteSkin.spriteVertexCount);
  120. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  121. NativeSliceUnsafeUtility.SetAtomicSafetyHandle(ref deformableVerticesFloat3, NativeSliceUnsafeUtility.GetAtomicSafetyHandle(vertices));
  122. #endif
  123. if (spriteSkin.hasTangents)
  124. {
  125. var deformedTanOffset = deformedPosStart + spriteSkin.tangentVertexOffset;
  126. var deformableTangentsFloat4 = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<float4>(deformedTanOffset, spriteSkin.spriteVertexStreamSize, spriteSkin.spriteVertexCount);
  127. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  128. NativeSliceUnsafeUtility.SetAtomicSafetyHandle(ref deformableTangentsFloat4, NativeSliceUnsafeUtility.GetAtomicSafetyHandle(vertices));
  129. #endif
  130. var tangent = new float4(tangents.xyz, 0.0f);
  131. tangent =
  132. math.mul(finalBoneTransforms[bone0], tangent) * influence.weight0 +
  133. math.mul(finalBoneTransforms[bone1], tangent) * influence.weight1 +
  134. math.mul(finalBoneTransforms[bone2], tangent) * influence.weight2 +
  135. math.mul(finalBoneTransforms[bone3], tangent) * influence.weight3;
  136. deformableTangentsFloat4[k] = new float4(math.normalize(tangent.xyz), tangents.w);
  137. }
  138. deformableVerticesFloat3[k] =
  139. math.transform(finalBoneTransforms[bone0], srcVertex) * influence.weight0 +
  140. math.transform(finalBoneTransforms[bone1], srcVertex) * influence.weight1 +
  141. math.transform(finalBoneTransforms[bone2], srcVertex) * influence.weight2 +
  142. math.transform(finalBoneTransforms[bone3], srcVertex) * influence.weight3;
  143. }
  144. }
  145. [BurstCompile]
  146. internal struct CalculateSpriteSkinAABBJob : IJobParallelFor
  147. {
  148. public NativeSlice<byte> vertices;
  149. [ReadOnly]
  150. public NativeArray<bool> isSpriteSkinValidForDeformArray;
  151. [ReadOnly]
  152. public NativeArray<SpriteSkinData> spriteSkinData;
  153. [WriteOnly]
  154. public NativeArray<Bounds> bounds;
  155. public unsafe void Execute(int i)
  156. {
  157. if (!isSpriteSkinValidForDeformArray[i])
  158. return;
  159. var spriteSkin = spriteSkinData[i];
  160. var deformedPosOffset = (byte*)vertices.GetUnsafePtr();
  161. var deformableVerticesFloat3 = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<float3>(deformedPosOffset + spriteSkin.deformVerticesStartPos, spriteSkin.spriteVertexStreamSize, spriteSkin.spriteVertexCount);
  162. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  163. NativeSliceUnsafeUtility.SetAtomicSafetyHandle(ref deformableVerticesFloat3, NativeSliceUnsafeUtility.GetAtomicSafetyHandle(vertices));
  164. #endif
  165. bounds[i] = SpriteSkinUtility.CalculateSpriteSkinBounds(deformableVerticesFloat3);
  166. }
  167. }
  168. [BurstCompile]
  169. internal struct FillPerSkinJobSingleThread : IJob
  170. {
  171. public PerSkinJobData combinedSkinBatch;
  172. [ReadOnly]
  173. public NativeArray<bool> isSpriteSkinValidForDeformArray;
  174. public NativeArray<SpriteSkinData> spriteSkinDataArray;
  175. public NativeArray<PerSkinJobData> perSkinJobDataArray;
  176. public NativeArray<PerSkinJobData> combinedSkinBatchArray;
  177. public void Execute()
  178. {
  179. var startIndex = 0;
  180. var endIndex = spriteSkinDataArray.Length;
  181. for (var index = startIndex; index < endIndex; ++index)
  182. {
  183. var spriteSkinData = spriteSkinDataArray[index];
  184. spriteSkinData.deformVerticesStartPos = -1;
  185. var vertexBufferSize = 0;
  186. var vertexCount = 0;
  187. var bindPoseCount = 0;
  188. if (isSpriteSkinValidForDeformArray[index])
  189. {
  190. spriteSkinData.deformVerticesStartPos = combinedSkinBatch.deformVerticesStartPos;
  191. vertexBufferSize = spriteSkinData.spriteVertexCount * spriteSkinData.spriteVertexStreamSize;
  192. vertexCount = spriteSkinData.spriteVertexCount;
  193. bindPoseCount = spriteSkinData.bindPoses.Length;
  194. }
  195. combinedSkinBatch.verticesIndex.x = combinedSkinBatch.verticesIndex.y;
  196. combinedSkinBatch.verticesIndex.y = combinedSkinBatch.verticesIndex.x + vertexCount;
  197. combinedSkinBatch.bindPosesIndex.x = combinedSkinBatch.bindPosesIndex.y;
  198. combinedSkinBatch.bindPosesIndex.y = combinedSkinBatch.bindPosesIndex.x + bindPoseCount;
  199. spriteSkinDataArray[index] = spriteSkinData;
  200. perSkinJobDataArray[index] = combinedSkinBatch;
  201. combinedSkinBatch.deformVerticesStartPos += vertexBufferSize;
  202. }
  203. combinedSkinBatchArray[0] = combinedSkinBatch;
  204. }
  205. }
  206. [BurstCompile]
  207. internal struct CopySpriteRendererBuffersJob : IJobParallelFor
  208. {
  209. [ReadOnly]
  210. public NativeArray<bool> isSpriteSkinValidForDeformArray;
  211. [ReadOnly]
  212. public NativeArray<SpriteSkinData> spriteSkinData;
  213. [ReadOnly, NativeDisableUnsafePtrRestriction]
  214. public IntPtr ptrVertices;
  215. [WriteOnly]
  216. public NativeArray<IntPtr> buffers;
  217. [WriteOnly]
  218. public NativeArray<int> bufferSizes;
  219. public void Execute(int i)
  220. {
  221. var skinData = spriteSkinData[i];
  222. var startVertices = default(IntPtr);
  223. var vertexBufferLength = 0;
  224. if (isSpriteSkinValidForDeformArray[i])
  225. {
  226. startVertices = ptrVertices + skinData.deformVerticesStartPos;
  227. vertexBufferLength = skinData.spriteVertexCount * skinData.spriteVertexStreamSize;
  228. }
  229. buffers[i] = startVertices;
  230. bufferSizes[i] = vertexBufferLength;
  231. }
  232. }
  233. internal class SpriteSkinComposite : ScriptableObject
  234. {
  235. static class Profiling
  236. {
  237. public static readonly ProfilerMarker batchAddSpriteSkin = new ProfilerMarker("SpriteSkinComposite.BatchAddSpriteSkin");
  238. public static readonly ProfilerMarker batchRemoveSpriteSkin = new ProfilerMarker("SpriteSkinComposite.BatchRemoveSpriteSkin");
  239. public static readonly ProfilerMarker prepareData = new ProfilerMarker("SpriteSkinComposite.PrepareData");
  240. public static readonly ProfilerMarker validateSpriteSkinData = new ProfilerMarker("SpriteSkinComposite.ValidateSpriteSkinData");
  241. public static readonly ProfilerMarker transformAccessJob = new ProfilerMarker("SpriteSkinComposite.TransformAccessJob");
  242. public static readonly ProfilerMarker getSpriteSkinBatchData = new ProfilerMarker("SpriteSkinComposite.GetSpriteSkinBatchData");
  243. public static readonly ProfilerMarker resizeBuffers = new ProfilerMarker("SpriteSkinComposite.ResizeBuffers");
  244. public static readonly ProfilerMarker prepare = new ProfilerMarker("SpriteSkinComposite.Prepare");
  245. public static readonly ProfilerMarker scheduleJobs = new ProfilerMarker("SpriteSkinComposite.ScheduleJobs");
  246. public static readonly ProfilerMarker setBatchDeformableBufferAndLocalAABB = new ProfilerMarker("SpriteSkinComposite.SetBatchDeformableBufferAndLocalAABB");
  247. public static readonly ProfilerMarker deactivateDeformableBuffer = new ProfilerMarker("SpriteSkinComposite.DeactivateDeformableBuffer");
  248. }
  249. static SpriteSkinComposite s_Instance;
  250. public static SpriteSkinComposite instance
  251. {
  252. get
  253. {
  254. if (s_Instance == null)
  255. {
  256. var composite = Resources.FindObjectsOfTypeAll<SpriteSkinComposite>();
  257. if (composite.Length > 0)
  258. s_Instance = composite[0];
  259. else
  260. s_Instance = ScriptableObject.CreateInstance<SpriteSkinComposite>();
  261. s_Instance.hideFlags = HideFlags.HideAndDontSave;
  262. s_Instance.Init();
  263. }
  264. return s_Instance;
  265. }
  266. }
  267. List<SpriteSkin> m_SpriteSkinsToAdd = new List<SpriteSkin>();
  268. List<SpriteSkin> m_SpriteSkinsToRemove = new List<SpriteSkin>();
  269. List<int> m_TransformIdsToRemove = new List<int>();
  270. List<SpriteSkin> m_SpriteSkins = new List<SpriteSkin>();
  271. SpriteRenderer[] m_SpriteRenderers = new SpriteRenderer[0];
  272. NativeByteArray m_DeformedVerticesBuffer;
  273. NativeArray<float4x4> m_FinalBoneTransforms;
  274. NativeArray<bool> m_IsSpriteSkinActiveForDeform;
  275. NativeArray<SpriteSkinData> m_SpriteSkinData;
  276. NativeArray<PerSkinJobData> m_PerSkinJobData;
  277. NativeArray<Bounds> m_BoundsData;
  278. NativeArray<IntPtr> m_Buffers;
  279. NativeArray<int> m_BufferSizes;
  280. NativeArray<int2> m_BoneLookupData;
  281. NativeArray<int2> m_VertexLookupData;
  282. NativeArray<PerSkinJobData> m_SkinBatchArray;
  283. TransformAccessJob m_LocalToWorldTransformAccessJob;
  284. TransformAccessJob m_WorldToLocalTransformAccessJob;
  285. JobHandle m_BoundJobHandle;
  286. JobHandle m_DeformJobHandle;
  287. JobHandle m_CopyJobHandle;
  288. [SerializeField]
  289. GameObject m_Helper;
  290. internal GameObject helperGameObject => m_Helper;
  291. internal void RemoveTransformById(int transformId)
  292. {
  293. m_LocalToWorldTransformAccessJob.RemoveTransformById(transformId);
  294. }
  295. internal void AddSpriteSkinBoneTransform(SpriteSkin spriteSkin)
  296. {
  297. if (spriteSkin == null)
  298. return;
  299. if (spriteSkin.boneTransforms != null)
  300. {
  301. foreach (var t in spriteSkin.boneTransforms)
  302. {
  303. if(t != null)
  304. m_LocalToWorldTransformAccessJob.AddTransform(t);
  305. }
  306. }
  307. }
  308. internal void AddSpriteSkinRootBoneTransform(SpriteSkin spriteSkin)
  309. {
  310. if (spriteSkin == null || spriteSkin.rootBone == null)
  311. return;
  312. m_LocalToWorldTransformAccessJob.AddTransform(spriteSkin.rootBone);
  313. }
  314. internal void AddSpriteSkin(SpriteSkin spriteSkin)
  315. {
  316. if (spriteSkin == null)
  317. return;
  318. if (!DoesContainSpriteSkin(m_SpriteSkins, spriteSkin) && !DoesContainSpriteSkin(m_SpriteSkinsToAdd, spriteSkin))
  319. m_SpriteSkinsToAdd.Add(spriteSkin);
  320. if (DoesContainSpriteSkin(m_SpriteSkinsToRemove, spriteSkin))
  321. {
  322. m_SpriteSkinsToRemove.Remove(spriteSkin);
  323. m_TransformIdsToRemove.Remove(spriteSkin.transform.GetInstanceID());
  324. }
  325. }
  326. internal void CopyToSpriteSkinData(SpriteSkin spriteSkin)
  327. {
  328. if (spriteSkin == null)
  329. return;
  330. var index = m_SpriteSkins.IndexOf(spriteSkin);
  331. if (index < 0)
  332. return;
  333. CopyToSpriteSkinData(index);
  334. }
  335. private void CopyToSpriteSkinData(int index)
  336. {
  337. if (index < 0 || index >= m_SpriteSkins.Count || m_SpriteSkins[index] == null)
  338. return;
  339. if (!m_SpriteSkinData.IsCreated)
  340. return;
  341. var spriteSkinData = default(SpriteSkinData);
  342. var spriteSkin = m_SpriteSkins[index];
  343. spriteSkin.CopyToSpriteSkinData(ref spriteSkinData, index);
  344. m_SpriteSkinData[index] = spriteSkinData;
  345. m_SpriteRenderers[index] = spriteSkin.spriteRenderer;
  346. }
  347. internal void RemoveSpriteSkin(SpriteSkin spriteSkin)
  348. {
  349. if (spriteSkin == null)
  350. return;
  351. if (DoesContainSpriteSkin(m_SpriteSkins, spriteSkin) && !DoesContainSpriteSkin(m_SpriteSkinsToRemove, spriteSkin))
  352. {
  353. m_SpriteSkinsToRemove.Add(spriteSkin);
  354. m_TransformIdsToRemove.Add(spriteSkin.transform.GetInstanceID());
  355. }
  356. if (DoesContainSpriteSkin(m_SpriteSkinsToAdd, spriteSkin))
  357. m_SpriteSkinsToAdd.Remove(spriteSkin);
  358. }
  359. static bool DoesContainSpriteSkin(in List<SpriteSkin> collection, SpriteSkin skin)
  360. {
  361. var index = collection.IndexOf(skin);
  362. if (index < 0)
  363. return false;
  364. return collection[index] != null;
  365. }
  366. void Init()
  367. {
  368. if (m_LocalToWorldTransformAccessJob == null)
  369. m_LocalToWorldTransformAccessJob = new TransformAccessJob();
  370. if (m_WorldToLocalTransformAccessJob == null)
  371. m_WorldToLocalTransformAccessJob = new TransformAccessJob();
  372. CreateHelper();
  373. }
  374. void CreateHelper()
  375. {
  376. if (m_Helper != null)
  377. return;
  378. m_Helper = new GameObject("SpriteSkinUpdateHelper");
  379. m_Helper.hideFlags = HideFlags.HideAndDontSave;
  380. var helperComponent = m_Helper.AddComponent<SpriteSkinUpdateHelper>();
  381. helperComponent.onDestroyingComponent += OnHelperDestroyed;
  382. #if !UNITY_EDITOR
  383. GameObject.DontDestroyOnLoad(m_Helper);
  384. #endif
  385. }
  386. void OnHelperDestroyed(GameObject helperGo)
  387. {
  388. if (m_Helper != helperGo)
  389. return;
  390. m_Helper = null;
  391. CreateHelper();
  392. }
  393. internal void ResetComposite()
  394. {
  395. m_SpriteSkins.Clear();
  396. m_LocalToWorldTransformAccessJob.Destroy();
  397. m_WorldToLocalTransformAccessJob.Destroy();
  398. m_LocalToWorldTransformAccessJob = new TransformAccessJob();
  399. m_WorldToLocalTransformAccessJob = new TransformAccessJob();
  400. }
  401. public void OnEnable()
  402. {
  403. s_Instance = this;
  404. m_FinalBoneTransforms = new NativeArray<float4x4>(1, Allocator.Persistent);
  405. m_BoneLookupData = new NativeArray<int2>(1, Allocator.Persistent);
  406. m_VertexLookupData = new NativeArray<int2>(1, Allocator.Persistent);
  407. m_SkinBatchArray = new NativeArray<PerSkinJobData>(1, Allocator.Persistent);
  408. Init();
  409. InitializeArrays();
  410. BatchRemoveSpriteSkins();
  411. BatchAddSpriteSkins();
  412. // Initialise all existing SpriteSkins as execution order is indeterminate
  413. for (var i = 0; i < m_SpriteSkins.Count; ++i)
  414. CopyToSpriteSkinData(i);
  415. }
  416. void InitializeArrays()
  417. {
  418. const int startingCount = 0;
  419. m_IsSpriteSkinActiveForDeform = new NativeArray<bool>(startingCount, Allocator.Persistent);
  420. m_PerSkinJobData = new NativeArray<PerSkinJobData>(startingCount, Allocator.Persistent);
  421. m_SpriteSkinData = new NativeArray<SpriteSkinData>(startingCount, Allocator.Persistent);
  422. m_BoundsData = new NativeArray<Bounds>(startingCount, Allocator.Persistent);
  423. m_Buffers = new NativeArray<IntPtr>(startingCount, Allocator.Persistent);
  424. m_BufferSizes = new NativeArray<int>(startingCount, Allocator.Persistent);
  425. }
  426. void OnDisable()
  427. {
  428. m_DeformJobHandle.Complete();
  429. m_BoundJobHandle.Complete();
  430. m_CopyJobHandle.Complete();
  431. m_SpriteSkins.Clear();
  432. m_SpriteRenderers = new SpriteRenderer[0];
  433. BufferManager.instance.ReturnBuffer(GetInstanceID());
  434. m_IsSpriteSkinActiveForDeform.DisposeIfCreated();
  435. m_PerSkinJobData.DisposeIfCreated();
  436. m_SpriteSkinData.DisposeIfCreated();
  437. m_Buffers.DisposeIfCreated();
  438. m_BufferSizes.DisposeIfCreated();
  439. m_BoneLookupData.DisposeIfCreated();
  440. m_VertexLookupData.DisposeIfCreated();
  441. m_SkinBatchArray.DisposeIfCreated();
  442. m_FinalBoneTransforms.DisposeIfCreated();
  443. m_BoundsData.DisposeIfCreated();
  444. if (m_Helper != null)
  445. {
  446. m_Helper.GetComponent<SpriteSkinUpdateHelper>().onDestroyingComponent -= OnHelperDestroyed;
  447. GameObject.DestroyImmediate(m_Helper);
  448. }
  449. m_LocalToWorldTransformAccessJob.Destroy();
  450. m_WorldToLocalTransformAccessJob.Destroy();
  451. }
  452. internal unsafe void LateUpdate()
  453. {
  454. BatchRemoveSpriteSkins();
  455. BatchAddSpriteSkins();
  456. var count = m_SpriteSkins.Count;
  457. if (count == 0)
  458. return;
  459. Profiling.prepareData.Begin();
  460. Assert.AreEqual(m_IsSpriteSkinActiveForDeform.Length, count);
  461. Assert.AreEqual(m_PerSkinJobData.Length, count);
  462. Assert.AreEqual(m_SpriteSkinData.Length, count);
  463. Assert.AreEqual(m_BoundsData.Length, count);
  464. Assert.AreEqual(m_Buffers.Length, count);
  465. Assert.AreEqual(m_BufferSizes.Length, count);
  466. Assert.AreEqual(m_SpriteRenderers.Length, count);
  467. using (Profiling.validateSpriteSkinData.Auto())
  468. {
  469. for (var i = 0; i < m_SpriteSkins.Count; ++i)
  470. {
  471. var spriteSkin = m_SpriteSkins[i];
  472. m_IsSpriteSkinActiveForDeform[i] = spriteSkin.BatchValidate();
  473. if (m_IsSpriteSkinActiveForDeform[i] && spriteSkin.NeedUpdateCompositeCache())
  474. {
  475. CopyToSpriteSkinData(i);
  476. }
  477. }
  478. }
  479. Profiling.transformAccessJob.Begin();
  480. var localToWorldJobHandle = m_LocalToWorldTransformAccessJob.StartLocalToWorldJob();
  481. var worldToLocalJobHandle = m_WorldToLocalTransformAccessJob.StartWorldToLocalJob();
  482. Profiling.transformAccessJob.End();
  483. using (Profiling.getSpriteSkinBatchData.Auto())
  484. {
  485. NativeArrayHelpers.ResizeIfNeeded(ref m_SkinBatchArray, 1);
  486. var fillPerSkinJobSingleThread = new FillPerSkinJobSingleThread()
  487. {
  488. isSpriteSkinValidForDeformArray = m_IsSpriteSkinActiveForDeform,
  489. combinedSkinBatchArray = m_SkinBatchArray,
  490. spriteSkinDataArray = m_SpriteSkinData,
  491. perSkinJobDataArray = m_PerSkinJobData,
  492. };
  493. fillPerSkinJobSingleThread.Run();
  494. }
  495. Profiling.prepareData.End();
  496. var skinBatch = m_SkinBatchArray[0];
  497. var batchCount = m_SpriteSkinData.Length;
  498. var vertexBufferSize = skinBatch.deformVerticesStartPos;
  499. if (vertexBufferSize <= 0)
  500. {
  501. localToWorldJobHandle.Complete();
  502. worldToLocalJobHandle.Complete();
  503. DeactivateDeformableBuffers();
  504. return;
  505. }
  506. using (Profiling.resizeBuffers.Auto())
  507. {
  508. m_DeformedVerticesBuffer = BufferManager.instance.GetBuffer(GetInstanceID(), vertexBufferSize);
  509. NativeArrayHelpers.ResizeIfNeeded(ref m_FinalBoneTransforms, skinBatch.bindPosesIndex.y);
  510. NativeArrayHelpers.ResizeIfNeeded(ref m_BoneLookupData, skinBatch.bindPosesIndex.y);
  511. NativeArrayHelpers.ResizeIfNeeded(ref m_VertexLookupData, skinBatch.verticesIndex.y);
  512. }
  513. Profiling.prepare.Begin();
  514. var prepareJob = new PrepareDeformJob
  515. {
  516. batchDataSize = batchCount,
  517. perSkinJobData = m_PerSkinJobData,
  518. boneLookupData = m_BoneLookupData,
  519. vertexLookupData = m_VertexLookupData
  520. };
  521. var jobHandle = prepareJob.Schedule();
  522. Profiling.prepare.End();
  523. Profiling.scheduleJobs.Begin();
  524. var boneJobBatched = new BoneDeformBatchedJob()
  525. {
  526. boneTransform = m_LocalToWorldTransformAccessJob.transformMatrix,
  527. rootTransform = m_WorldToLocalTransformAccessJob.transformMatrix,
  528. spriteSkinData = m_SpriteSkinData,
  529. boneLookupData = m_BoneLookupData,
  530. finalBoneTransforms = m_FinalBoneTransforms,
  531. rootTransformIndex = m_WorldToLocalTransformAccessJob.transformData,
  532. boneTransformIndex = m_LocalToWorldTransformAccessJob.transformData
  533. };
  534. jobHandle = JobHandle.CombineDependencies(localToWorldJobHandle, worldToLocalJobHandle, jobHandle);
  535. jobHandle = boneJobBatched.Schedule(skinBatch.bindPosesIndex.y, 8, jobHandle);
  536. var skinJobBatched = new SkinDeformBatchedJob()
  537. {
  538. vertices = m_DeformedVerticesBuffer.array,
  539. vertexLookupData = m_VertexLookupData,
  540. spriteSkinData = m_SpriteSkinData,
  541. perSkinJobData = m_PerSkinJobData,
  542. finalBoneTransforms = m_FinalBoneTransforms,
  543. };
  544. m_DeformJobHandle = skinJobBatched.Schedule(skinBatch.verticesIndex.y, 16, jobHandle);
  545. var copySpriteRendererBuffersJob = new CopySpriteRendererBuffersJob()
  546. {
  547. isSpriteSkinValidForDeformArray = m_IsSpriteSkinActiveForDeform,
  548. spriteSkinData = m_SpriteSkinData,
  549. ptrVertices = (IntPtr) NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(m_DeformedVerticesBuffer.array),
  550. buffers = m_Buffers,
  551. bufferSizes = m_BufferSizes,
  552. };
  553. m_CopyJobHandle = copySpriteRendererBuffersJob.Schedule(batchCount, 16, jobHandle);
  554. var updateBoundJob = new CalculateSpriteSkinAABBJob
  555. {
  556. vertices = m_DeformedVerticesBuffer.array,
  557. isSpriteSkinValidForDeformArray = m_IsSpriteSkinActiveForDeform,
  558. spriteSkinData = m_SpriteSkinData,
  559. bounds = m_BoundsData,
  560. };
  561. m_BoundJobHandle = updateBoundJob.Schedule(batchCount, 4, m_DeformJobHandle);
  562. Profiling.scheduleJobs.End();
  563. JobHandle.ScheduleBatchedJobs();
  564. jobHandle = JobHandle.CombineDependencies(m_BoundJobHandle, m_CopyJobHandle);
  565. jobHandle.Complete();
  566. using (Profiling.setBatchDeformableBufferAndLocalAABB.Auto())
  567. {
  568. InternalEngineBridge.SetBatchDeformableBufferAndLocalAABBArray(m_SpriteRenderers, m_Buffers, m_BufferSizes, m_BoundsData);
  569. }
  570. DeactivateDeformableBuffers();
  571. }
  572. void BatchRemoveSpriteSkins()
  573. {
  574. if (m_SpriteSkinsToRemove.Count == 0)
  575. return;
  576. using (Profiling.batchRemoveSpriteSkin.Auto())
  577. {
  578. m_WorldToLocalTransformAccessJob.RemoveTransformsByIds(m_TransformIdsToRemove);
  579. var updatedCount = Mathf.Max(m_SpriteSkins.Count - m_SpriteSkinsToRemove.Count, 0);
  580. if (updatedCount == 0)
  581. {
  582. m_SpriteSkins.Clear();
  583. }
  584. else
  585. {
  586. foreach (var spriteSkin in m_SpriteSkinsToRemove)
  587. {
  588. var index = m_SpriteSkins.IndexOf(spriteSkin);
  589. if (index < 0)
  590. continue;
  591. // Check if it is not the last SpriteSkin
  592. if (index < m_SpriteSkins.Count - 1)
  593. {
  594. m_SpriteSkins.RemoveAtSwapBack(index);
  595. CopyToSpriteSkinData(index);
  596. }
  597. else
  598. m_SpriteSkins.RemoveAt(index);
  599. }
  600. }
  601. Array.Resize(ref m_SpriteRenderers, updatedCount);
  602. ResizeAndCopyArrays(updatedCount);
  603. m_TransformIdsToRemove.Clear();
  604. m_SpriteSkinsToRemove.Clear();
  605. }
  606. }
  607. void BatchAddSpriteSkins()
  608. {
  609. if (m_SpriteSkinsToAdd.Count == 0)
  610. return;
  611. using (Profiling.batchAddSpriteSkin.Auto())
  612. {
  613. var updatedCount = m_SpriteSkins.Count + m_SpriteSkinsToAdd.Count;
  614. Array.Resize(ref m_SpriteRenderers, updatedCount);
  615. if (m_IsSpriteSkinActiveForDeform.IsCreated)
  616. ResizeAndCopyArrays(updatedCount);
  617. foreach (var spriteSkin in m_SpriteSkinsToAdd)
  618. {
  619. if (DoesContainSpriteSkin(m_SpriteSkins, spriteSkin))
  620. {
  621. Debug.LogError($"Skin already exists! Name={spriteSkin.name}");
  622. continue;
  623. }
  624. m_SpriteSkins.Add(spriteSkin);
  625. var count = m_SpriteSkins.Count;
  626. m_SpriteRenderers[count - 1] = spriteSkin.spriteRenderer;
  627. m_WorldToLocalTransformAccessJob.AddTransform(spriteSkin.transform);
  628. if (m_IsSpriteSkinActiveForDeform.IsCreated)
  629. CopyToSpriteSkinData(count - 1);
  630. }
  631. m_SpriteSkinsToAdd.Clear();
  632. }
  633. }
  634. void ResizeAndCopyArrays(int updatedCount)
  635. {
  636. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_IsSpriteSkinActiveForDeform, updatedCount);
  637. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_PerSkinJobData, updatedCount);
  638. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_SpriteSkinData, updatedCount);
  639. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_BoundsData, updatedCount);
  640. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_Buffers, updatedCount);
  641. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_BufferSizes, updatedCount);
  642. }
  643. void DeactivateDeformableBuffers()
  644. {
  645. using (Profiling.deactivateDeformableBuffer.Auto())
  646. {
  647. for (var i = 0; i < m_IsSpriteSkinActiveForDeform.Length; ++i)
  648. {
  649. if (m_IsSpriteSkinActiveForDeform[i] || InternalEngineBridge.IsUsingDeformableBuffer(m_SpriteRenderers[i], IntPtr.Zero))
  650. continue;
  651. m_SpriteRenderers[i].DeactivateDeformableBuffer();
  652. }
  653. }
  654. }
  655. internal bool HasDeformableBufferForSprite(int dataIndex)
  656. {
  657. if (dataIndex < 0 && m_IsSpriteSkinActiveForDeform.Length >= dataIndex)
  658. throw new InvalidOperationException("Invalid index for deformable buffer");
  659. return m_IsSpriteSkinActiveForDeform[dataIndex];
  660. }
  661. internal unsafe NativeArray<byte> GetDeformableBufferForSprite(int dataIndex)
  662. {
  663. if (dataIndex < 0 && m_SpriteSkinData.Length >= dataIndex)
  664. throw new InvalidOperationException("Invalid index for deformable buffer");
  665. if (!m_DeformJobHandle.IsCompleted)
  666. m_DeformJobHandle.Complete();
  667. var skinData = m_SpriteSkinData[dataIndex];
  668. if (skinData.deformVerticesStartPos < 0)
  669. throw new InvalidOperationException("There are no currently deformed vertices.");
  670. var vertexBufferLength = skinData.spriteVertexCount * skinData.spriteVertexStreamSize;
  671. byte* ptrVertices = (byte*)m_DeformedVerticesBuffer.array.GetUnsafeReadOnlyPtr();
  672. ptrVertices += skinData.deformVerticesStartPos;
  673. var buffer = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>(ptrVertices, vertexBufferLength, Allocator.None);
  674. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  675. NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref buffer, NativeArrayUnsafeUtility.GetAtomicSafetyHandle(m_DeformedVerticesBuffer.array));
  676. #endif
  677. return buffer;
  678. }
  679. // Code for tests
  680. #region Code For Tests
  681. internal string GetDebugLog()
  682. {
  683. var log = "";
  684. log += "===SpriteSkinBatch===\n";
  685. log += "Count: " + m_SpriteSkins.Count +"\n";
  686. foreach (var ss in m_SpriteSkins)
  687. {
  688. log += ss == null ? "null" : ss.name;
  689. log += "\n";
  690. }
  691. log += "===LocalToWorldTransformAccessJob===\n";
  692. log += m_LocalToWorldTransformAccessJob.GetDebugLog();
  693. log += "\n";
  694. log += "===WorldToLocalTransformAccessJob===\n";
  695. log += "\n";
  696. log += m_WorldToLocalTransformAccessJob.GetDebugLog();
  697. return log;
  698. }
  699. internal SpriteSkin[] GetSpriteSkins()
  700. {
  701. return m_SpriteSkins.ToArray();
  702. }
  703. internal TransformAccessJob GetWorldToLocalTransformAccessJob()
  704. {
  705. return m_WorldToLocalTransformAccessJob;
  706. }
  707. internal TransformAccessJob GetLocalToWorldTransformAccessJob()
  708. {
  709. return m_LocalToWorldTransformAccessJob;
  710. }
  711. #endregion
  712. }
  713. #if UNITY_EDITOR
  714. [UnityEditor.InitializeOnLoad]
  715. internal class SpriteSkinCompositeStartup
  716. {
  717. static SpriteSkinCompositeStartup()
  718. {
  719. if (null == SpriteSkinComposite.instance.helperGameObject)
  720. throw new System.InvalidOperationException("SpriteSkinComposite not initialized properly.");
  721. }
  722. }
  723. #endif
  724. }