Optimize renderer memory allocations with RenderListAllocation (mem pooling)

This commit is contained in:
Wojtek Figat
2021-07-08 00:34:36 +02:00
parent 4765e1af12
commit 38bf3d87ed
4 changed files with 120 additions and 4 deletions

View File

@@ -174,7 +174,7 @@ private:
}; };
typedef Array<struct BatchedDrawCall, InlinedAllocation<8>> DrawCallsList; typedef Array<struct BatchedDrawCall, InlinedAllocation<8>> DrawCallsList;
typedef Dictionary<DrawKey, struct BatchedDrawCall, HeapAllocation> BatchedDrawCalls; typedef Dictionary<DrawKey, struct BatchedDrawCall, class RenderListAllocation> BatchedDrawCalls;
void DrawInstance(RenderContext& renderContext, FoliageInstance& instance, FoliageType& type, Model* model, int32 lod, float lodDitherFactor, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const; void DrawInstance(RenderContext& renderContext, FoliageInstance& instance, FoliageType& type, Model* model, int32 lod, float lodDitherFactor, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const;
void DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, FoliageType& type, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const; void DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, FoliageType& type, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const;
#else #else

View File

@@ -31,6 +31,14 @@ namespace
Array<uint64> SortingKeys[2]; Array<uint64> SortingKeys[2];
Array<int32> SortingIndices; Array<int32> SortingIndices;
Array<RenderList*> FreeRenderList; Array<RenderList*> FreeRenderList;
struct MemPoolEntry
{
void* Ptr;
uintptr Size;
};
Array<MemPoolEntry> MemPool;
} }
void RendererDirectionalLightData::SetupLightData(LightData* data, const RenderView& view, bool useShadow) const void RendererDirectionalLightData::SetupLightData(LightData* data, const RenderView& view, bool useShadow) const
@@ -101,6 +109,30 @@ void RendererSkyLightData::SetupLightData(LightData* data, const RenderView& vie
data->RadiusInv = 1.0f / Radius; data->RadiusInv = 1.0f / Radius;
} }
void* RenderListAllocation::Allocate(uintptr size)
{
void* result = nullptr;
for (int32 i = 0; i < MemPool.Count(); i++)
{
if (MemPool[i].Size == size)
{
result = MemPool[i].Ptr;
MemPool.RemoveAt(i);
break;
}
}
if (!result)
{
result = Platform::Allocate(size, 16);
}
return result;
}
void RenderListAllocation::Free(void* ptr, uintptr size)
{
MemPool.Add({ ptr, size });
}
RenderList* RenderList::GetFromPool() RenderList* RenderList::GetFromPool()
{ {
if (FreeRenderList.HasItems()) if (FreeRenderList.HasItems())
@@ -132,6 +164,9 @@ void RenderList::CleanupCache()
SortingKeys[1].Resize(0); SortingKeys[1].Resize(0);
SortingIndices.Resize(0); SortingIndices.Resize(0);
FreeRenderList.ClearDelete(); FreeRenderList.ClearDelete();
for (auto& e : MemPool)
Platform::Free(e.Ptr);
MemPool.Clear();
} }
bool RenderList::BlendableSettings::operator<(const BlendableSettings& other) const bool RenderList::BlendableSettings::operator<(const BlendableSettings& other) const

View File

@@ -203,10 +203,91 @@ struct DrawBatch
} }
}; };
class RenderListAllocation
{
public:
static void* Allocate(uintptr size);
static void Free(void* ptr, uintptr size);
template<typename T>
class Data
{
T* _data = nullptr;
uintptr _size;
public:
FORCE_INLINE Data()
{
}
FORCE_INLINE ~Data()
{
if (_data)
RenderListAllocation::Free(_data, _size);
}
FORCE_INLINE T* Get()
{
return _data;
}
FORCE_INLINE const T* Get() const
{
return _data;
}
FORCE_INLINE int32 CalculateCapacityGrow(int32 capacity, int32 minCapacity) const
{
capacity = capacity ? capacity * 2 : 64;
if (capacity < minCapacity)
capacity = minCapacity;
return capacity;
}
FORCE_INLINE void Allocate(uint64 capacity)
{
_size = capacity * sizeof(T);
_data = (T*)RenderListAllocation::Allocate(_size);
}
FORCE_INLINE void Relocate(uint64 capacity, int32 oldCount, int32 newCount)
{
T* newData = capacity != 0 ? (T*)RenderListAllocation::Allocate(capacity * sizeof(T)) : nullptr;
if (oldCount)
{
if (newCount > 0)
Memory::MoveItems(newData, _data, newCount);
Memory::DestructItems(_data, oldCount);
}
if (_data)
RenderListAllocation::Free(_data, _size);
_data = newData;
_size = capacity * sizeof(T);
}
FORCE_INLINE void Free()
{
if (_data)
{
RenderListAllocation::Free(_data, _size);
_data = nullptr;
}
}
FORCE_INLINE void Swap(Data& other)
{
::Swap(_data, other._data);
::Swap(_size, other._size);
}
};
};
struct BatchedDrawCall struct BatchedDrawCall
{ {
DrawCall DrawCall; DrawCall DrawCall;
Array<struct InstanceData> Instances; Array<struct InstanceData, RenderListAllocation> Instances;
}; };
/// <summary> /// <summary>

View File

@@ -579,8 +579,8 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
GPUTextureView* localShadowedLightScattering = nullptr; GPUTextureView* localShadowedLightScattering = nullptr;
{ {
// Get lights to render // Get lights to render
Array<const RendererPointLightData*> pointLights; Array<const RendererPointLightData*, InlinedAllocation<64, RenderListAllocation>> pointLights;
Array<const RendererSpotLightData*> spotLights; Array<const RendererSpotLightData*, InlinedAllocation<64, RenderListAllocation>> spotLights;
for (int32 i = 0; i < renderContext.List->PointLights.Count(); i++) for (int32 i = 0; i < renderContext.List->PointLights.Count(); i++)
{ {
const auto& light = renderContext.List->PointLights[i]; const auto& light = renderContext.List->PointLights[i];