2019-12-26 14:45:42 -05:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
2018-10-22 23:01:29 -04:00
|
|
|
|
|
|
|
|
#include "RenderGraphResourcePool.h"
|
2023-01-27 14:54:10 -05:00
|
|
|
#include "RHICommandList.h"
|
2018-10-22 23:01:29 -04:00
|
|
|
#include "RenderGraphResources.h"
|
2023-01-27 14:54:10 -05:00
|
|
|
#include "RHITransientResourceAllocator.h"
|
2022-04-22 17:11:57 -04:00
|
|
|
#include "Trace/Trace.inl"
|
|
|
|
|
#include "ProfilingDebugging/CountersTrace.h"
|
2018-10-22 23:01:29 -04:00
|
|
|
|
2022-04-22 17:11:57 -04:00
|
|
|
TRACE_DECLARE_INT_COUNTER(BufferPoolCount, TEXT("BufferPool/BufferCount"));
|
|
|
|
|
TRACE_DECLARE_INT_COUNTER(BufferPoolCreateCount, TEXT("BufferPool/BufferCreateCount"));
|
|
|
|
|
TRACE_DECLARE_INT_COUNTER(BufferPoolReleaseCount, TEXT("BufferPool/BufferReleaseCount"));
|
|
|
|
|
TRACE_DECLARE_MEMORY_COUNTER(BufferPoolSize, TEXT("BufferPool/Size"));
|
2021-05-05 11:58:15 -04:00
|
|
|
|
2022-04-22 17:11:57 -04:00
|
|
|
UE_TRACE_EVENT_BEGIN(Cpu, FRDGBufferPool_CreateBuffer, NoSync)
|
|
|
|
|
UE_TRACE_EVENT_FIELD(UE::Trace::WideString, Name)
|
|
|
|
|
UE_TRACE_EVENT_FIELD(uint32, SizeInBytes)
|
|
|
|
|
UE_TRACE_EVENT_END()
|
|
|
|
|
|
2022-04-25 11:38:06 -04:00
|
|
|
RENDERCORE_API void DumpBufferPoolMemory(FOutputDevice& OutputDevice)
|
|
|
|
|
{
|
|
|
|
|
GRenderGraphResourcePool.DumpMemoryUsage(OutputDevice);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FAutoConsoleCommandWithOutputDevice GDumpBufferPoolMemoryCmd(
|
|
|
|
|
TEXT("r.DumpBufferPoolMemory"),
|
|
|
|
|
TEXT("Dump allocation information for the buffer pool."),
|
|
|
|
|
FConsoleCommandWithOutputDeviceDelegate::CreateStatic(DumpBufferPoolMemory)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
void FRDGBufferPool::DumpMemoryUsage(FOutputDevice& OutputDevice)
|
|
|
|
|
{
|
|
|
|
|
OutputDevice.Logf(TEXT("Pooled Buffers:"));
|
|
|
|
|
|
|
|
|
|
TArray<TRefCountPtr<FRDGPooledBuffer>> BuffersBySize = AllocatedBuffers;
|
|
|
|
|
|
|
|
|
|
Algo::Sort(BuffersBySize, [](const TRefCountPtr<FRDGPooledBuffer>& LHS, const TRefCountPtr<FRDGPooledBuffer>& RHS)
|
|
|
|
|
{
|
|
|
|
|
return LHS->GetAlignedSize() > RHS->GetAlignedSize();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (const TRefCountPtr<FRDGPooledBuffer>& Buffer : BuffersBySize)
|
|
|
|
|
{
|
|
|
|
|
const uint32 BufferSize = Buffer->GetAlignedSize();
|
|
|
|
|
const uint32 UnusedForNFrames = FrameCounter - Buffer->LastUsedFrame;
|
|
|
|
|
|
|
|
|
|
OutputDevice.Logf(
|
|
|
|
|
TEXT(" %6.3fMB Name: %s, NumElements: %u, BytesPerElement: %u, UAV: %s, Frames Since Requested: %u"),
|
|
|
|
|
(float)BufferSize / (1024.0f * 1024.0f),
|
|
|
|
|
Buffer->Name,
|
|
|
|
|
Buffer->NumAllocatedElements,
|
|
|
|
|
Buffer->Desc.BytesPerElement,
|
|
|
|
|
EnumHasAnyFlags(Buffer->Desc.Usage, EBufferUsageFlags::UnorderedAccess) ? TEXT("Yes") : TEXT("No"),
|
|
|
|
|
UnusedForNFrames);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-22 17:11:57 -04:00
|
|
|
TRefCountPtr<FRDGPooledBuffer> FRDGBufferPool::FindFreeBuffer(const FRDGBufferDesc& Desc, const TCHAR* InDebugName, ERDGPooledBufferAlignment Alignment)
|
2018-10-22 23:01:29 -04:00
|
|
|
{
|
2023-06-19 14:00:50 -04:00
|
|
|
FRHICommandListBase& RHICmdList = FRHICommandListImmediate::Get();
|
|
|
|
|
|
2021-05-06 12:36:40 -04:00
|
|
|
const uint64 BufferPageSize = 64 * 1024;
|
|
|
|
|
|
|
|
|
|
FRDGBufferDesc AlignedDesc = Desc;
|
2022-04-22 17:11:57 -04:00
|
|
|
|
|
|
|
|
switch (Alignment)
|
|
|
|
|
{
|
|
|
|
|
case ERDGPooledBufferAlignment::PowerOfTwo:
|
|
|
|
|
AlignedDesc.NumElements = FMath::RoundUpToPowerOfTwo(AlignedDesc.BytesPerElement * AlignedDesc.NumElements) / AlignedDesc.BytesPerElement;
|
|
|
|
|
// Fall through to align up to page size for small buffers; helps with reuse.
|
|
|
|
|
|
|
|
|
|
case ERDGPooledBufferAlignment::Page:
|
|
|
|
|
AlignedDesc.NumElements = Align(AlignedDesc.BytesPerElement * AlignedDesc.NumElements, BufferPageSize) / AlignedDesc.BytesPerElement;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-25 08:51:15 -04:00
|
|
|
if (!ensureMsgf(AlignedDesc.NumElements >= Desc.NumElements, TEXT("Alignment caused buffer size overflow for buffer '%s' (AlignedDesc.NumElements: %d < Desc.NumElements: %d)"), InDebugName, AlignedDesc.NumElements, Desc.NumElements))
|
|
|
|
|
{
|
|
|
|
|
// Use the unaligned desc since we apparently overflowed when rounding up.
|
|
|
|
|
AlignedDesc = Desc;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-22 17:11:57 -04:00
|
|
|
const uint32 BufferHash = GetTypeHash(AlignedDesc);
|
2022-01-03 18:28:16 -05:00
|
|
|
|
2018-10-22 23:01:29 -04:00
|
|
|
// First find if available.
|
2021-05-05 11:58:15 -04:00
|
|
|
for (int32 Index = 0; Index < AllocatedBufferHashes.Num(); ++Index)
|
2018-10-22 23:01:29 -04:00
|
|
|
{
|
2021-05-05 11:58:15 -04:00
|
|
|
if (AllocatedBufferHashes[Index] != BufferHash)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto& PooledBuffer = AllocatedBuffers[Index];
|
|
|
|
|
|
2018-10-22 23:01:29 -04:00
|
|
|
// Still being used outside the pool.
|
|
|
|
|
if (PooledBuffer->GetRefCount() > 1)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 12:36:40 -04:00
|
|
|
check(PooledBuffer->GetAlignedDesc() == AlignedDesc);
|
2020-07-06 18:58:26 -04:00
|
|
|
|
2021-05-05 11:58:15 -04:00
|
|
|
PooledBuffer->LastUsedFrame = FrameCounter;
|
|
|
|
|
PooledBuffer->ViewCache.SetDebugName(InDebugName);
|
|
|
|
|
PooledBuffer->Name = InDebugName;
|
|
|
|
|
|
2021-10-27 15:14:40 -04:00
|
|
|
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
|
|
|
|
RHIBindDebugLabelName(PooledBuffer->GetRHI(), InDebugName);
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-05-06 12:36:40 -04:00
|
|
|
// We need the external-facing desc to match what the user requested.
|
|
|
|
|
const_cast<FRDGBufferDesc&>(PooledBuffer->Desc).NumElements = Desc.NumElements;
|
|
|
|
|
|
2021-05-05 11:58:15 -04:00
|
|
|
return PooledBuffer;
|
2018-10-22 23:01:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allocate new one
|
|
|
|
|
{
|
2022-04-22 17:11:57 -04:00
|
|
|
const uint32 NumBytes = AlignedDesc.GetSize();
|
2021-04-23 15:48:49 -04:00
|
|
|
|
2022-04-22 17:11:57 -04:00
|
|
|
#if CPUPROFILERTRACE_ENABLED
|
|
|
|
|
UE_TRACE_LOG_SCOPED_T(Cpu, FRDGBufferPool_CreateBuffer, CpuChannel)
|
|
|
|
|
<< FRDGBufferPool_CreateBuffer.Name(InDebugName)
|
|
|
|
|
<< FRDGBufferPool_CreateBuffer.SizeInBytes(NumBytes);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
TRACE_COUNTER_ADD(BufferPoolCount, 1);
|
|
|
|
|
TRACE_COUNTER_ADD(BufferPoolCreateCount, 1);
|
|
|
|
|
TRACE_COUNTER_ADD(BufferPoolSize, NumBytes);
|
2018-10-22 23:01:29 -04:00
|
|
|
|
2022-05-06 15:44:23 -04:00
|
|
|
const ERHIAccess InitialAccess = RHIGetDefaultResourceState(Desc.Usage, false);
|
2021-02-16 08:37:39 -04:00
|
|
|
FRHIResourceCreateInfo CreateInfo(InDebugName);
|
2023-06-19 14:00:50 -04:00
|
|
|
TRefCountPtr<FRHIBuffer> BufferRHI = RHICmdList.CreateBuffer(NumBytes, Desc.Usage, Desc.BytesPerElement, InitialAccess, CreateInfo);
|
2020-09-24 00:43:27 -04:00
|
|
|
|
2021-10-27 15:14:40 -04:00
|
|
|
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
|
|
|
|
RHIBindDebugLabelName(BufferRHI, InDebugName);
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-06-22 11:25:09 -04:00
|
|
|
TRefCountPtr<FRDGPooledBuffer> PooledBuffer = new FRDGPooledBuffer(RHICmdList, MoveTemp(BufferRHI), Desc, AlignedDesc.NumElements, InDebugName);
|
2021-03-17 12:44:59 -04:00
|
|
|
AllocatedBuffers.Add(PooledBuffer);
|
2021-05-05 11:58:15 -04:00
|
|
|
AllocatedBufferHashes.Add(BufferHash);
|
2021-03-17 12:44:59 -04:00
|
|
|
check(PooledBuffer->GetRefCount() == 2);
|
|
|
|
|
|
|
|
|
|
PooledBuffer->LastUsedFrame = FrameCounter;
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
return PooledBuffer;
|
2018-10-22 23:01:29 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-09 12:58:33 -04:00
|
|
|
void FRDGBufferPool::ReleaseRHI()
|
2018-10-22 23:01:29 -04:00
|
|
|
{
|
|
|
|
|
AllocatedBuffers.Empty();
|
2022-01-26 13:54:46 -05:00
|
|
|
AllocatedBufferHashes.Empty();
|
2018-10-22 23:01:29 -04:00
|
|
|
}
|
|
|
|
|
|
2022-01-03 18:28:16 -05:00
|
|
|
void FRDGBufferPool::TickPoolElements()
|
2018-10-22 23:01:29 -04:00
|
|
|
{
|
2019-07-09 17:22:17 -04:00
|
|
|
const uint32 kFramesUntilRelease = 30;
|
|
|
|
|
|
|
|
|
|
int32 BufferIndex = 0;
|
2022-04-22 17:11:57 -04:00
|
|
|
int32 NumReleasedBuffers = 0;
|
|
|
|
|
int64 NumReleasedBufferBytes = 0;
|
2019-07-09 17:22:17 -04:00
|
|
|
|
|
|
|
|
while (BufferIndex < AllocatedBuffers.Num())
|
2018-10-22 23:01:29 -04:00
|
|
|
{
|
2020-09-24 00:43:27 -04:00
|
|
|
TRefCountPtr<FRDGPooledBuffer>& Buffer = AllocatedBuffers[BufferIndex];
|
2019-07-09 17:22:17 -04:00
|
|
|
|
|
|
|
|
const bool bIsUnused = Buffer.GetRefCount() == 1;
|
|
|
|
|
|
|
|
|
|
const bool bNotRequestedRecently = (FrameCounter - Buffer->LastUsedFrame) > kFramesUntilRelease;
|
|
|
|
|
|
|
|
|
|
if (bIsUnused && bNotRequestedRecently)
|
2018-10-22 23:01:29 -04:00
|
|
|
{
|
2022-04-22 17:11:57 -04:00
|
|
|
NumReleasedBufferBytes += Buffer->GetAlignedDesc().GetSize();
|
|
|
|
|
|
2021-05-05 11:58:15 -04:00
|
|
|
AllocatedBuffers.RemoveAtSwap(BufferIndex);
|
|
|
|
|
AllocatedBufferHashes.RemoveAtSwap(BufferIndex);
|
2022-04-22 17:11:57 -04:00
|
|
|
|
|
|
|
|
++NumReleasedBuffers;
|
2019-07-09 17:22:17 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
++BufferIndex;
|
2018-10-22 23:01:29 -04:00
|
|
|
}
|
|
|
|
|
}
|
2019-07-09 17:22:17 -04:00
|
|
|
|
2022-04-22 17:11:57 -04:00
|
|
|
TRACE_COUNTER_SUBTRACT(BufferPoolSize, NumReleasedBufferBytes);
|
|
|
|
|
TRACE_COUNTER_SUBTRACT(BufferPoolCount, NumReleasedBuffers);
|
|
|
|
|
TRACE_COUNTER_SET(BufferPoolReleaseCount, NumReleasedBuffers);
|
|
|
|
|
TRACE_COUNTER_SET(BufferPoolCreateCount, 0);
|
|
|
|
|
|
2019-07-09 17:22:17 -04:00
|
|
|
++FrameCounter;
|
2018-10-22 23:01:29 -04:00
|
|
|
}
|
|
|
|
|
|
2022-01-03 18:28:16 -05:00
|
|
|
TGlobalResource<FRDGBufferPool> GRenderGraphResourcePool;
|
|
|
|
|
|
|
|
|
|
uint32 FRDGTransientRenderTarget::AddRef() const
|
|
|
|
|
{
|
|
|
|
|
check(LifetimeState == ERDGTransientResourceLifetimeState::Allocated);
|
2022-07-01 18:40:59 -04:00
|
|
|
return uint32(FPlatformAtomics::InterlockedIncrement(&RefCount));
|
2022-01-03 18:28:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32 FRDGTransientRenderTarget::Release()
|
|
|
|
|
{
|
2022-07-01 18:40:59 -04:00
|
|
|
const int32 Refs = FPlatformAtomics::InterlockedDecrement(&RefCount);
|
|
|
|
|
check(Refs >= 0 && LifetimeState == ERDGTransientResourceLifetimeState::Allocated);
|
2022-01-03 18:28:16 -05:00
|
|
|
if (Refs == 0)
|
|
|
|
|
{
|
2022-01-14 16:28:58 -05:00
|
|
|
if (GRDGTransientResourceAllocator.IsValid())
|
|
|
|
|
{
|
|
|
|
|
GRDGTransientResourceAllocator.AddPendingDeallocation(this);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
delete this;
|
|
|
|
|
}
|
2022-01-03 18:28:16 -05:00
|
|
|
}
|
|
|
|
|
return Refs;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-19 14:00:50 -04:00
|
|
|
void FRDGTransientResourceAllocator::InitRHI(FRHICommandListBase&)
|
2022-01-03 18:28:16 -05:00
|
|
|
{
|
|
|
|
|
Allocator = RHICreateTransientResourceAllocator();
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-09 12:58:33 -04:00
|
|
|
void FRDGTransientResourceAllocator::ReleaseRHI()
|
2022-01-03 18:28:16 -05:00
|
|
|
{
|
|
|
|
|
if (Allocator)
|
|
|
|
|
{
|
|
|
|
|
FRHICommandListImmediate& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList();
|
|
|
|
|
|
|
|
|
|
ReleasePendingDeallocations();
|
|
|
|
|
PendingDeallocationList.Empty();
|
|
|
|
|
|
|
|
|
|
for (FRDGTransientRenderTarget* RenderTarget : DeallocatedList)
|
|
|
|
|
{
|
|
|
|
|
delete RenderTarget;
|
|
|
|
|
}
|
|
|
|
|
DeallocatedList.Empty();
|
|
|
|
|
|
|
|
|
|
Allocator->Flush(RHICmdList);
|
2022-03-10 21:53:51 -05:00
|
|
|
|
|
|
|
|
// Allocator->Flush() enqueues some lambdas on the command list, so make sure they are executed
|
|
|
|
|
// before the allocator is deleted.
|
|
|
|
|
RHICmdList.ImmediateFlush(EImmediateFlushType::FlushRHIThread);
|
|
|
|
|
|
2022-01-03 18:28:16 -05:00
|
|
|
Allocator->Release(RHICmdList);
|
|
|
|
|
Allocator = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRefCountPtr<FRDGTransientRenderTarget> FRDGTransientResourceAllocator::AllocateRenderTarget(FRHITransientTexture* Texture)
|
|
|
|
|
{
|
|
|
|
|
check(Texture);
|
|
|
|
|
|
|
|
|
|
FRDGTransientRenderTarget* RenderTarget = nullptr;
|
|
|
|
|
|
|
|
|
|
if (!FreeList.IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
RenderTarget = FreeList.Pop();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RenderTarget = new FRDGTransientRenderTarget();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RenderTarget->Texture = Texture;
|
|
|
|
|
RenderTarget->Desc = Translate(Texture->CreateInfo);
|
|
|
|
|
RenderTarget->Desc.DebugName = Texture->GetName();
|
|
|
|
|
RenderTarget->LifetimeState = ERDGTransientResourceLifetimeState::Allocated;
|
2023-04-25 10:24:28 -04:00
|
|
|
RenderTarget->RenderTargetItem.TargetableTexture = Texture->GetRHI();
|
|
|
|
|
RenderTarget->RenderTargetItem.ShaderResourceTexture = Texture->GetRHI();
|
2022-01-03 18:28:16 -05:00
|
|
|
return RenderTarget;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FRDGTransientResourceAllocator::Release(TRefCountPtr<FRDGTransientRenderTarget>&& RenderTarget, FRDGPassHandle PassHandle)
|
|
|
|
|
{
|
|
|
|
|
check(RenderTarget);
|
|
|
|
|
|
2022-03-25 11:19:10 -04:00
|
|
|
// If this is true, we hold the final reference in the RenderTarget argument. We want to zero out its
|
|
|
|
|
// members before dereferencing to zero so that it gets marked as deallocated rather than pending.
|
2022-01-03 18:28:16 -05:00
|
|
|
if (RenderTarget->GetRefCount() == 1)
|
|
|
|
|
{
|
|
|
|
|
Allocator->DeallocateMemory(RenderTarget->Texture, PassHandle.GetIndex());
|
|
|
|
|
RenderTarget->Reset();
|
|
|
|
|
RenderTarget = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FRDGTransientResourceAllocator::AddPendingDeallocation(FRDGTransientRenderTarget* RenderTarget)
|
|
|
|
|
{
|
|
|
|
|
check(RenderTarget);
|
|
|
|
|
check(RenderTarget->GetRefCount() == 0);
|
|
|
|
|
|
2022-07-01 18:40:59 -04:00
|
|
|
FScopeLock Lock(&CS);
|
|
|
|
|
|
2022-01-03 18:28:16 -05:00
|
|
|
if (RenderTarget->Texture)
|
|
|
|
|
{
|
|
|
|
|
RenderTarget->LifetimeState = ERDGTransientResourceLifetimeState::PendingDeallocation;
|
|
|
|
|
PendingDeallocationList.Emplace(RenderTarget);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RenderTarget->LifetimeState = ERDGTransientResourceLifetimeState::Deallocated;
|
|
|
|
|
DeallocatedList.Emplace(RenderTarget);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FRDGTransientResourceAllocator::ReleasePendingDeallocations()
|
|
|
|
|
{
|
2022-07-01 18:40:59 -04:00
|
|
|
FScopeLock Lock(&CS);
|
|
|
|
|
|
2022-01-03 18:28:16 -05:00
|
|
|
if (!PendingDeallocationList.IsEmpty())
|
|
|
|
|
{
|
2022-06-30 19:55:24 -04:00
|
|
|
TArray<FRHITransitionInfo, SceneRenderingAllocator> Transitions;
|
2022-01-03 18:28:16 -05:00
|
|
|
Transitions.Reserve(PendingDeallocationList.Num());
|
|
|
|
|
|
2022-06-30 19:55:24 -04:00
|
|
|
TArray<FRHITransientAliasingInfo, SceneRenderingAllocator> Aliases;
|
2022-01-03 18:28:16 -05:00
|
|
|
Aliases.Reserve(PendingDeallocationList.Num());
|
|
|
|
|
|
|
|
|
|
for (FRDGTransientRenderTarget* RenderTarget : PendingDeallocationList)
|
|
|
|
|
{
|
|
|
|
|
Allocator->DeallocateMemory(RenderTarget->Texture, 0);
|
|
|
|
|
|
|
|
|
|
Aliases.Emplace(FRHITransientAliasingInfo::Discard(RenderTarget->Texture->GetRHI()));
|
|
|
|
|
Transitions.Emplace(RenderTarget->Texture->GetRHI(), ERHIAccess::Unknown, ERHIAccess::Discard);
|
|
|
|
|
|
|
|
|
|
RenderTarget->Reset();
|
|
|
|
|
RenderTarget->LifetimeState = ERDGTransientResourceLifetimeState::Deallocated;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const FRHITransition* Transition = RHICreateTransition(FRHITransitionCreateInfo(ERHIPipeline::Graphics, ERHIPipeline::Graphics, ERHITransitionCreateFlags::None, Transitions, Aliases));
|
|
|
|
|
|
|
|
|
|
FRHICommandListImmediate& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList();
|
|
|
|
|
RHICmdList.BeginTransition(Transition);
|
|
|
|
|
RHICmdList.EndTransition(Transition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FreeList.Append(PendingDeallocationList);
|
|
|
|
|
PendingDeallocationList.Reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!DeallocatedList.IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
FreeList.Append(DeallocatedList);
|
|
|
|
|
DeallocatedList.Reset();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-28 19:29:34 -04:00
|
|
|
TGlobalResource<FRDGTransientResourceAllocator, FRenderResource::EInitPhase::Pre> GRDGTransientResourceAllocator;
|