Add RenderListAlloc to simplify rendering memory allocations

This commit is contained in:
Wojtek Figat
2025-09-03 13:00:28 +02:00
parent 5a2555f845
commit 212b0de29b
3 changed files with 53 additions and 33 deletions

View File

@@ -210,31 +210,10 @@ void DrawEmitterCPU(RenderContextBatch& renderContextBatch, ParticleBuffer* buff
const int32 stride = buffer->Stride;
const int32 listSize = buffer->CPU.Count;
const int32 indicesByteSize = listSize * buffer->GPU.SortedIndices->GetStride();
Array<uint32, RendererAllocation> sortingKeysList[4];
Array<byte, RendererAllocation> sortingIndicesList[2];
uint32* sortingKeys[2];
void* sortingIndices[2];
if (listSize < 500)
{
// Use fast stack allocator from RenderList
auto& memory = renderContextBatch.GetMainContext().List->Memory;
sortingKeys[0] = memory.Allocate<uint32>(listSize);
sortingKeys[1] = memory.Allocate<uint32>(listSize);
sortingIndices[0] = memory.Allocate(indicesByteSize, GPU_SHADER_DATA_ALIGNMENT);
sortingIndices[1] = memory.Allocate(indicesByteSize, GPU_SHADER_DATA_ALIGNMENT);
}
else
{
// Use shared pooled memory from RendererAllocation
sortingKeysList[0].Resize(listSize);
sortingKeysList[1].Resize(listSize);
sortingIndicesList[0].Resize(indicesByteSize);
sortingIndicesList[1].Resize(indicesByteSize);
sortingKeys[0] = sortingKeysList[0].Get();
sortingKeys[1] = sortingKeysList[1].Get();
sortingIndices[0] = sortingIndicesList[0].Get();
sortingIndices[1] = sortingIndicesList[1].Get();
}
RenderListAlloc sortingAllocs[4];
auto* renderList = renderContextBatch.GetMainContext().List;
uint32* sortingKeys[2] = { sortingAllocs[0].Init<uint32>(renderList, listSize), sortingAllocs[1].Init<uint32>(renderList, listSize) };
void* sortingIndices[2] = { sortingAllocs[2].Init(renderList, indicesByteSize, GPU_SHADER_DATA_ALIGNMENT), sortingAllocs[3].Init(renderList, indicesByteSize, GPU_SHADER_DATA_ALIGNMENT) };
uint32* sortedKeys = sortingKeys[0];
const uint32 sortKeyXor = sortMode != ParticleSortMode::CustomAscending ? MAX_uint32 : 0;
switch (sortMode)
@@ -321,7 +300,7 @@ void DrawEmitterCPU(RenderContextBatch& renderContextBatch, ParticleBuffer* buff
{
case PixelFormat::R16_UInt:
for (int32 i = 0; i < listSize; i++)
((uint16*)sortedIndices)[i] = i;
((uint16*)sortedIndices)[i] = (uint16)i;
break;
case PixelFormat::R32_UInt:
for (int32 i = 0; i < listSize; i++)

View File

@@ -461,6 +461,25 @@ bool DrawCallsList::IsEmpty() const
return Indices.Count() + PreBatchedDrawCalls.Count() == 0;
}
RenderListAlloc::~RenderListAlloc()
{
if (!List && Data) // Render List memory doesn't need free (arena allocator)
RendererAllocation::Free(Data, Size);
}
void* RenderListAlloc::Init(RenderList* list, uintptr size, uintptr alignment)
{
ASSERT_LOW_LAYER(!Data);
Size = size;
bool useList = alignment <= 16 && size < 1024;
List = useList ? list : nullptr;
if (useList)
Data = list->Memory.Allocate(size, alignment);
else
Data = RendererAllocation::Allocate(size);
return Data;
}
RenderList::RenderList(const SpawnParams& params)
: ScriptingObject(params)
, Memory(4 * 1024 * 1024, RendererAllocation::Allocate, RendererAllocation::Free) // 4MB pages, use page pooling via RendererAllocation
@@ -692,12 +711,10 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD
ZoneValue(listSize);
// Use shared memory from renderer allocator
Array<uint64, RendererAllocation> SortingKeys[2];
Array<int32, RendererAllocation> SortingIndices;
SortingKeys[0].Resize(listSize);
SortingKeys[1].Resize(listSize);
SortingIndices.Resize(listSize);
uint64* sortedKeys = SortingKeys[0].Get();
RenderListAlloc allocs[3];
uint64* sortedKeys = allocs[0].Init<uint64>(this, listSize);
uint64* tempKeys = allocs[1].Init<uint64>(this, listSize);
int32* tempIndices = allocs[2].Init<int32>(this, listSize);
// Setup sort keys
if (reverseDistance)
@@ -740,7 +757,7 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD
// Sort draw calls indices
int32* resultIndices = list.Indices.Get();
Sorting::RadixSort(sortedKeys, resultIndices, SortingKeys[1].Get(), SortingIndices.Get(), listSize);
Sorting::RadixSort(sortedKeys, resultIndices, tempKeys, tempIndices, listSize);
if (resultIndices != list.Indices.Get())
Platform::MemoryCopy(list.Indices.Get(), resultIndices, sizeof(int32) * listSize);

View File

@@ -278,6 +278,30 @@ struct DrawCallsList
bool IsEmpty() const;
};
// Small utility for allocating memory from RenderList arena pool with automatic fallback to shared RendererAllocation for larger memory blocks.
struct RenderListAlloc
{
RenderList* List;
void* Data = nullptr;
uintptr Size;
~RenderListAlloc();
void* Init(RenderList* list, uintptr size, uintptr alignment = 1);
template<typename T>
FORCE_INLINE T* Init(RenderList* list, int32 count, uintptr alignment = 1)
{
return (T*)Init(list, count * sizeof(T), alignment);
}
template<typename T>
FORCE_INLINE T* Get()
{
return (T*)Data;
}
};
/// <summary>
/// Rendering cache container object for the draw calls collecting, sorting and executing.
/// </summary>