Files
UnrealEngineUWP/Engine/Source/Runtime/RenderCore/Private/RenderGraphResourcePool.cpp
zach bethel 47cf1f4458 Rewrite of RHI transient resource system.
- Views are cached on RHI transient resources; view renames are no longer necessary.
 - RHI Transient resources utilize a single cache per heap keyed off of the descriptor + offset. Resource caches and heaps are garbage collected.
 - CPU performance is effectively equivalent to the existing pooled resource method.
 - Added common RHI transient resource allocator implementation in RHI core; significantly reduces the amount of platform code.
 - Resource aliasing overlaps are tracked by the RHI and submitted through an acquire operation.
 - Fixed D3D12 implementation to support multi-GPU.
 - Removed condition that excluded small (<64k) buffers in the transient allocator.
 - RHI validation now checks that resource overlaps are valid; i.e. if an overlap occurs between resource A and B during an acquire of B, validation checks that A has been discarded.

#rb graham.wihlidal, luke.thatcher, kenzo.terelst

[CL 16076280 by zach bethel in ue5-main branch]
2021-04-21 13:03:28 -04:00

122 lines
3.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
RenderTargetPool.cpp: Scene render target pool manager.
=============================================================================*/
#include "RenderGraphResourcePool.h"
#include "RenderGraphResources.h"
FRenderGraphResourcePool::FRenderGraphResourcePool()
{ }
TRefCountPtr<FRDGPooledBuffer> FRenderGraphResourcePool::FindFreeBuffer(
FRHICommandList& RHICmdList,
const FRDGBufferDesc& Desc,
const TCHAR* InDebugName)
{
TRefCountPtr<FRDGPooledBuffer> Result = FindFreeBufferInternal(RHICmdList, Desc, InDebugName);
Result->Reset();
return Result;
}
TRefCountPtr<FRDGPooledBuffer> FRenderGraphResourcePool::FindFreeBufferInternal(
FRHICommandList& RHICmdList,
const FRDGBufferDesc& Desc,
const TCHAR* InDebugName)
{
// First find if available.
for (auto& PooledBuffer : AllocatedBuffers)
{
// Still being used outside the pool.
if (PooledBuffer->GetRefCount() > 1)
{
continue;
}
if (PooledBuffer->Desc == Desc)
{
PooledBuffer->LastUsedFrame = FrameCounter;
PooledBuffer->Name = InDebugName;
//@todo - rename other resources too
for (const auto& Pair : PooledBuffer->UAVs)
{
RHIBindDebugLabelName(Pair.Value, InDebugName);
}
return PooledBuffer;
}
}
// Allocate new one
{
uint32 NumBytes = Desc.GetTotalNumBytes();
FRHIResourceCreateInfo CreateInfo(InDebugName);
TRefCountPtr<FRHIBuffer> BufferRHI;
if (Desc.UnderlyingType == FRDGBufferDesc::EUnderlyingType::VertexBuffer)
{
BufferRHI = RHICreateVertexBuffer(NumBytes, Desc.Usage, CreateInfo);
}
else if (Desc.UnderlyingType == FRDGBufferDesc::EUnderlyingType::StructuredBuffer)
{
BufferRHI = RHICreateStructuredBuffer(Desc.BytesPerElement, NumBytes, Desc.Usage, CreateInfo);
}
else if (Desc.UnderlyingType == FRDGBufferDesc::EUnderlyingType::AccelerationStructure)
{
BufferRHI = RHICreateBuffer(NumBytes, Desc.Usage, 0, ERHIAccess::BVHWrite, CreateInfo);
}
else
{
check(0);
}
TRefCountPtr<FRDGPooledBuffer> PooledBuffer = new FRDGPooledBuffer(MoveTemp(BufferRHI), Desc);
AllocatedBuffers.Add(PooledBuffer);
check(PooledBuffer->GetRefCount() == 2);
PooledBuffer->Name = InDebugName;
PooledBuffer->LastUsedFrame = FrameCounter;
return PooledBuffer;
}
}
void FRenderGraphResourcePool::ReleaseDynamicRHI()
{
AllocatedBuffers.Empty();
}
void FRenderGraphResourcePool::TickPoolElements()
{
const uint32 kFramesUntilRelease = 30;
int32 BufferIndex = 0;
while (BufferIndex < AllocatedBuffers.Num())
{
TRefCountPtr<FRDGPooledBuffer>& Buffer = AllocatedBuffers[BufferIndex];
const bool bIsUnused = Buffer.GetRefCount() == 1;
const bool bNotRequestedRecently = (FrameCounter - Buffer->LastUsedFrame) > kFramesUntilRelease;
if (bIsUnused && bNotRequestedRecently)
{
Swap(Buffer, AllocatedBuffers.Last());
AllocatedBuffers.Pop();
}
else
{
++BufferIndex;
}
}
++FrameCounter;
}
TGlobalResource<FRenderGraphResourcePool> GRenderGraphResourcePool;