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.
171 lines
6.1 KiB
171 lines
6.1 KiB
using System; |
|
using System.Runtime.InteropServices; |
|
using Unity.Collections; |
|
using UnityEngine.Rendering.Universal.Internal; |
|
|
|
namespace UnityEngine.Rendering.Universal |
|
{ |
|
class DeferredShaderData : IDisposable |
|
{ |
|
static DeferredShaderData m_Instance = null; |
|
|
|
struct ComputeBufferInfo |
|
{ |
|
public uint frameUsed; |
|
public ComputeBufferType type; // There is no interface to retrieve the type of a ComputeBuffer, so we must save it on our side |
|
} |
|
|
|
// Precomputed tiles (for each tiler). |
|
NativeArray<PreTile>[] m_PreTiles = null; |
|
// Structured buffers and constant buffers are all allocated from this array. |
|
ComputeBuffer[] m_Buffers = null; |
|
// We need to store extra info per ComputeBuffer. |
|
ComputeBufferInfo[] m_BufferInfos; |
|
|
|
// How many buffers have been created so far. This is <= than m_Buffers.Length. |
|
int m_BufferCount = 0; |
|
// Remember index of last buffer used. This optimizes the search for available buffer. |
|
int m_CachedBufferIndex = 0; |
|
// This counter is allowed to cycle back to 0. |
|
uint m_FrameIndex = 0; |
|
|
|
DeferredShaderData() |
|
{ |
|
m_PreTiles = new NativeArray<PreTile>[DeferredConfig.kTilerDepth]; |
|
m_Buffers = new ComputeBuffer[64]; |
|
m_BufferInfos = new ComputeBufferInfo[64]; |
|
} |
|
|
|
internal static DeferredShaderData instance |
|
{ |
|
get |
|
{ |
|
if (m_Instance == null) |
|
m_Instance = new DeferredShaderData(); |
|
|
|
return m_Instance; |
|
} |
|
} |
|
|
|
public void Dispose() |
|
{ |
|
DisposeNativeArrays(ref m_PreTiles); |
|
|
|
for (int i = 0; i < m_Buffers.Length; ++i) |
|
{ |
|
if (m_Buffers[i] != null) |
|
{ |
|
m_Buffers[i].Dispose(); |
|
m_Buffers[i] = null; |
|
} |
|
} |
|
m_BufferCount = 0; |
|
} |
|
|
|
internal void ResetBuffers() |
|
{ |
|
++m_FrameIndex; // Allowed to cycle back to 0. |
|
} |
|
|
|
internal NativeArray<PreTile> GetPreTiles(int level, int count) |
|
{ |
|
return GetOrUpdateNativeArray<PreTile>(ref m_PreTiles, level, count); |
|
} |
|
|
|
internal ComputeBuffer ReserveBuffer<T>(int count, bool asCBuffer) where T : struct |
|
{ |
|
int stride = Marshal.SizeOf<T>(); |
|
int paddedCount = asCBuffer ? Align(stride * count, 16) / stride : count; |
|
return GetOrUpdateBuffer(paddedCount, stride, asCBuffer); |
|
} |
|
|
|
NativeArray<T> GetOrUpdateNativeArray<T>(ref NativeArray<T>[] nativeArrays, int level, int count) where T : struct |
|
{ |
|
if (!nativeArrays[level].IsCreated) |
|
{ |
|
nativeArrays[level] = new NativeArray<T>(count, Allocator.Persistent); |
|
} |
|
else if (count > nativeArrays[level].Length) |
|
{ |
|
nativeArrays[level].Dispose(); |
|
nativeArrays[level] = new NativeArray<T>(count, Allocator.Persistent); |
|
} |
|
|
|
return nativeArrays[level]; |
|
} |
|
|
|
void DisposeNativeArrays<T>(ref NativeArray<T>[] nativeArrays) where T : struct |
|
{ |
|
for (int i = 0; i < nativeArrays.Length; ++i) |
|
{ |
|
if (nativeArrays[i].IsCreated) |
|
nativeArrays[i].Dispose(); |
|
} |
|
} |
|
|
|
ComputeBuffer GetOrUpdateBuffer(int count, int stride, bool isConstantBuffer) |
|
{ |
|
ComputeBufferType type = isConstantBuffer ? ComputeBufferType.Constant : ComputeBufferType.Structured; |
|
int maxQueuedFrames = QualitySettings.maxQueuedFrames; |
|
Assertions.Assert.IsTrue(maxQueuedFrames >= 1, "invalid QualitySettings.maxQueuedFrames"); |
|
|
|
for (int i = 0; i < m_BufferCount; ++i) |
|
{ |
|
int bufferIndex = (m_CachedBufferIndex + i + 1) % m_BufferCount; |
|
|
|
if (IsLessCircular(m_BufferInfos[bufferIndex].frameUsed + (uint)maxQueuedFrames, m_FrameIndex) |
|
&& m_BufferInfos[bufferIndex].type == type && m_Buffers[bufferIndex].count == count && m_Buffers[bufferIndex].stride == stride) |
|
{ |
|
m_BufferInfos[bufferIndex].frameUsed = m_FrameIndex; |
|
m_CachedBufferIndex = bufferIndex; |
|
return m_Buffers[bufferIndex]; |
|
} |
|
} |
|
|
|
if (m_BufferCount == m_Buffers.Length) // If all buffers used: allocate more space. |
|
{ |
|
ComputeBuffer[] newBuffers = new ComputeBuffer[m_BufferCount * 2]; |
|
for (int i = 0; i < m_BufferCount; ++i) |
|
newBuffers[i] = m_Buffers[i]; |
|
m_Buffers = newBuffers; |
|
|
|
ComputeBufferInfo[] newBufferInfos = new ComputeBufferInfo[m_BufferCount * 2]; |
|
for (int i = 0; i < m_BufferCount; ++i) |
|
newBufferInfos[i] = m_BufferInfos[i]; |
|
m_BufferInfos = newBufferInfos; |
|
} |
|
|
|
// Create new buffer. |
|
m_Buffers[m_BufferCount] = new ComputeBuffer(count, stride, type, ComputeBufferMode.Immutable); |
|
m_BufferInfos[m_BufferCount].frameUsed = m_FrameIndex; |
|
m_BufferInfos[m_BufferCount].type = type; |
|
m_CachedBufferIndex = m_BufferCount; |
|
return m_Buffers[m_BufferCount++]; |
|
} |
|
|
|
void DisposeBuffers(ComputeBuffer[,] buffers) |
|
{ |
|
for (int i = 0; i < buffers.GetLength(0); ++i) |
|
{ |
|
for (int j = 0; j < buffers.GetLength(1); ++j) |
|
{ |
|
if (buffers[i, j] != null) |
|
{ |
|
buffers[i, j].Dispose(); |
|
buffers[i, j] = null; |
|
} |
|
} |
|
} |
|
} |
|
|
|
static bool IsLessCircular(uint a, uint b) |
|
{ |
|
return a != b ? (b - a) < 0x80000000 : false; |
|
} |
|
|
|
static int Align(int s, int alignment) |
|
{ |
|
return ((s + alignment - 1) / alignment) * alignment; |
|
} |
|
} |
|
}
|
|
|