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.

PersistentGPUArray.cs 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. using System;
  2. using System.Collections;
  3. using System.Runtime.InteropServices;
  4. using Unity.Collections;
  5. using UnityEngine.Assertions;
  6. namespace UnityEngine.Rendering.UnifiedRayTracing
  7. {
  8. internal class PersistentGpuArray<Tstruct> : IDisposable
  9. where Tstruct : struct
  10. {
  11. BlockAllocator m_SlotAllocator;
  12. ComputeBuffer m_GpuBuffer;
  13. NativeArray<Tstruct> m_CpuList;
  14. BitArray m_Updates;
  15. bool m_gpuBufferDirty = true;
  16. int m_ElementCount = 0;
  17. public int elementCount { get { return m_ElementCount; } }
  18. public PersistentGpuArray(int initialSize)
  19. {
  20. m_SlotAllocator.Initialize(initialSize);
  21. m_GpuBuffer = new ComputeBuffer(initialSize, Marshal.SizeOf<Tstruct>());
  22. m_CpuList = new NativeArray<Tstruct>(initialSize, Allocator.Persistent);
  23. m_Updates = new BitArray(initialSize);
  24. m_ElementCount = 0;
  25. }
  26. public void Dispose()
  27. {
  28. m_ElementCount = 0;
  29. m_SlotAllocator.Dispose();
  30. m_GpuBuffer.Dispose();
  31. m_CpuList.Dispose();
  32. }
  33. public BlockAllocator.Allocation Add(Tstruct element)
  34. {
  35. m_ElementCount++;
  36. var slotAllocation = m_SlotAllocator.Allocate(1);
  37. if (!slotAllocation.valid)
  38. {
  39. Grow();
  40. slotAllocation = m_SlotAllocator.Allocate(1);
  41. Assert.IsTrue(slotAllocation.valid);
  42. }
  43. m_CpuList[slotAllocation.block.offset] = element;
  44. m_Updates[slotAllocation.block.offset] = true;
  45. m_gpuBufferDirty = true;
  46. return slotAllocation;
  47. }
  48. public void Remove(BlockAllocator.Allocation allocation)
  49. {
  50. m_ElementCount--;
  51. m_SlotAllocator.FreeAllocation(allocation);
  52. }
  53. public void Clear()
  54. {
  55. m_ElementCount = 0;
  56. var currentCapacity = m_SlotAllocator.capacity;
  57. m_SlotAllocator.Dispose();
  58. m_SlotAllocator = new BlockAllocator();
  59. m_SlotAllocator.Initialize(currentCapacity);
  60. m_Updates = new BitArray(currentCapacity);
  61. m_gpuBufferDirty = false;
  62. }
  63. public void Set(BlockAllocator.Allocation allocation, Tstruct element)
  64. {
  65. m_CpuList[allocation.block.offset] = element;
  66. m_Updates[allocation.block.offset] = true;
  67. }
  68. public Tstruct Get(BlockAllocator.Allocation allocation)
  69. {
  70. return m_CpuList[allocation.block.offset];
  71. }
  72. public void ModifyForEach(Func<Tstruct, Tstruct> lambda)
  73. {
  74. for (int i = 0; i < m_CpuList.Length; ++i)
  75. {
  76. m_CpuList[i] = lambda(m_CpuList[i]);
  77. m_Updates[i] = true;
  78. }
  79. m_gpuBufferDirty = true;
  80. }
  81. // Note: this should ideally be used with only one command buffer. If used with more than one cmd buffers, the order of their execution is important.
  82. public ComputeBuffer GetGpuBuffer(CommandBuffer cmd)
  83. {
  84. if (m_gpuBufferDirty)
  85. {
  86. int copyStartIndex = -1;
  87. for (int i = 0; i < m_Updates.Length; ++i)
  88. {
  89. if (m_Updates[i])
  90. {
  91. if (copyStartIndex == -1)
  92. copyStartIndex = i;
  93. m_Updates[i] = false;
  94. }
  95. else if (copyStartIndex != -1)
  96. {
  97. int copyEndIndex = i;
  98. cmd.SetBufferData(m_GpuBuffer, m_CpuList, copyStartIndex, copyStartIndex, copyEndIndex - copyStartIndex);
  99. copyStartIndex = -1;
  100. }
  101. }
  102. if (copyStartIndex != -1)
  103. {
  104. int copyEndIndex = m_Updates.Length;
  105. cmd.SetBufferData(m_GpuBuffer, m_CpuList, copyStartIndex, copyStartIndex, copyEndIndex - copyStartIndex);
  106. }
  107. m_gpuBufferDirty = false;
  108. }
  109. return m_GpuBuffer;
  110. }
  111. private void Grow()
  112. {
  113. var oldCapacity = m_SlotAllocator.capacity;
  114. m_SlotAllocator.Grow(m_SlotAllocator.capacity + 1);
  115. m_GpuBuffer.Dispose();
  116. m_GpuBuffer = new ComputeBuffer(m_SlotAllocator.capacity, Marshal.SizeOf<Tstruct>());
  117. var oldList = m_CpuList;
  118. m_CpuList = new NativeArray<Tstruct>(m_SlotAllocator.capacity, Allocator.Persistent);
  119. NativeArray<Tstruct>.Copy(oldList, m_CpuList, oldCapacity);
  120. oldList.Dispose();
  121. var oldUpdates = m_Updates;
  122. m_Updates = new BitArray(m_SlotAllocator.capacity);
  123. for (int i = 0; i < oldCapacity; ++i)
  124. m_Updates[i] = oldUpdates[i];
  125. }
  126. }
  127. }