164 lines
5.4 KiB
C#
164 lines
5.4 KiB
C#
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using Unity.Collections;
|
||
|
using UnityEngine.Assertions;
|
||
|
|
||
|
namespace UnityEngine.Rendering.UnifiedRayTracing
|
||
|
{
|
||
|
internal sealed class PersistentGpuArray<Tstruct> : IDisposable
|
||
|
where Tstruct : struct
|
||
|
{
|
||
|
BlockAllocator m_SlotAllocator;
|
||
|
ComputeBuffer m_GpuBuffer;
|
||
|
NativeArray<Tstruct> m_CpuList;
|
||
|
BitArray m_Updates;
|
||
|
bool m_gpuBufferDirty = true;
|
||
|
int m_ElementCount = 0;
|
||
|
public int elementCount { get { return m_ElementCount; } }
|
||
|
|
||
|
public PersistentGpuArray(int initialSize)
|
||
|
{
|
||
|
m_SlotAllocator.Initialize(initialSize);
|
||
|
m_GpuBuffer = new ComputeBuffer(initialSize, Marshal.SizeOf<Tstruct>());
|
||
|
m_CpuList = new NativeArray<Tstruct>(initialSize, Allocator.Persistent);
|
||
|
m_Updates = new BitArray(initialSize);
|
||
|
m_ElementCount = 0;
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
m_ElementCount = 0;
|
||
|
m_SlotAllocator.Dispose();
|
||
|
m_GpuBuffer.Dispose();
|
||
|
m_CpuList.Dispose();
|
||
|
}
|
||
|
|
||
|
public BlockAllocator.Allocation Add(Tstruct element)
|
||
|
{
|
||
|
m_ElementCount++;
|
||
|
var slotAllocation = m_SlotAllocator.Allocate(1);
|
||
|
if (!slotAllocation.valid)
|
||
|
{
|
||
|
Grow();
|
||
|
slotAllocation = m_SlotAllocator.Allocate(1);
|
||
|
Assert.IsTrue(slotAllocation.valid);
|
||
|
}
|
||
|
m_CpuList[slotAllocation.block.offset] = element;
|
||
|
m_Updates[slotAllocation.block.offset] = true;
|
||
|
m_gpuBufferDirty = true;
|
||
|
|
||
|
return slotAllocation;
|
||
|
}
|
||
|
|
||
|
public BlockAllocator.Allocation[] Add(int elementCount)
|
||
|
{
|
||
|
m_ElementCount+= elementCount;
|
||
|
var slotAllocation = m_SlotAllocator.Allocate(elementCount);
|
||
|
if (!slotAllocation.valid)
|
||
|
{
|
||
|
Grow();
|
||
|
slotAllocation = m_SlotAllocator.Allocate(elementCount);
|
||
|
Assert.IsTrue(slotAllocation.valid);
|
||
|
}
|
||
|
|
||
|
return m_SlotAllocator.SplitAllocation(slotAllocation, elementCount);
|
||
|
}
|
||
|
|
||
|
|
||
|
public void Remove(BlockAllocator.Allocation allocation)
|
||
|
{
|
||
|
m_ElementCount--;
|
||
|
m_SlotAllocator.FreeAllocation(allocation);
|
||
|
}
|
||
|
|
||
|
public void Clear()
|
||
|
{
|
||
|
m_ElementCount = 0;
|
||
|
var currentCapacity = m_SlotAllocator.capacity;
|
||
|
m_SlotAllocator.Dispose();
|
||
|
m_SlotAllocator = new BlockAllocator();
|
||
|
m_SlotAllocator.Initialize(currentCapacity);
|
||
|
m_Updates = new BitArray(currentCapacity);
|
||
|
m_gpuBufferDirty = false;
|
||
|
}
|
||
|
|
||
|
public void Set(BlockAllocator.Allocation allocation, Tstruct element)
|
||
|
{
|
||
|
m_CpuList[allocation.block.offset] = element;
|
||
|
m_Updates[allocation.block.offset] = true;
|
||
|
m_gpuBufferDirty = true;
|
||
|
}
|
||
|
|
||
|
public Tstruct Get(BlockAllocator.Allocation allocation)
|
||
|
{
|
||
|
return m_CpuList[allocation.block.offset];
|
||
|
}
|
||
|
|
||
|
public void ModifyForEach(Func<Tstruct, Tstruct> lambda)
|
||
|
{
|
||
|
for (int i = 0; i < m_CpuList.Length; ++i)
|
||
|
{
|
||
|
m_CpuList[i] = lambda(m_CpuList[i]);
|
||
|
m_Updates[i] = true;
|
||
|
}
|
||
|
m_gpuBufferDirty = true;
|
||
|
}
|
||
|
|
||
|
// 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.
|
||
|
public ComputeBuffer GetGpuBuffer(CommandBuffer cmd)
|
||
|
{
|
||
|
if (m_gpuBufferDirty)
|
||
|
{
|
||
|
int copyStartIndex = -1;
|
||
|
for (int i = 0; i < m_Updates.Length; ++i)
|
||
|
{
|
||
|
if (m_Updates[i])
|
||
|
{
|
||
|
if (copyStartIndex == -1)
|
||
|
copyStartIndex = i;
|
||
|
|
||
|
m_Updates[i] = false;
|
||
|
}
|
||
|
else if (copyStartIndex != -1)
|
||
|
{
|
||
|
int copyEndIndex = i;
|
||
|
cmd.SetBufferData(m_GpuBuffer, m_CpuList, copyStartIndex, copyStartIndex, copyEndIndex - copyStartIndex);
|
||
|
copyStartIndex = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (copyStartIndex != -1)
|
||
|
{
|
||
|
int copyEndIndex = m_Updates.Length;
|
||
|
cmd.SetBufferData(m_GpuBuffer, m_CpuList, copyStartIndex, copyStartIndex, copyEndIndex - copyStartIndex);
|
||
|
}
|
||
|
|
||
|
m_gpuBufferDirty = false;
|
||
|
}
|
||
|
|
||
|
return m_GpuBuffer;
|
||
|
}
|
||
|
|
||
|
private void Grow()
|
||
|
{
|
||
|
var oldCapacity = m_SlotAllocator.capacity;
|
||
|
m_SlotAllocator.Grow(m_SlotAllocator.capacity + 1);
|
||
|
|
||
|
m_GpuBuffer.Dispose();
|
||
|
m_GpuBuffer = new ComputeBuffer(m_SlotAllocator.capacity, Marshal.SizeOf<Tstruct>());
|
||
|
|
||
|
var oldList = m_CpuList;
|
||
|
m_CpuList = new NativeArray<Tstruct>(m_SlotAllocator.capacity, Allocator.Persistent);
|
||
|
NativeArray<Tstruct>.Copy(oldList, m_CpuList, oldCapacity);
|
||
|
oldList.Dispose();
|
||
|
|
||
|
var oldUpdates = m_Updates;
|
||
|
m_Updates = new BitArray(m_SlotAllocator.capacity);
|
||
|
for (int i = 0; i < oldCapacity; ++i)
|
||
|
m_Updates[i] = oldUpdates[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|