You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Replaced legacy transient support from RDG and replaced with new API. - Reworked acquire / discard operations a bit and added RHI validation to track correctness. - Reworked RDG barrier batching to include acquire / discard operations. - Hardened render pass merging logic and expanded to support lifetime extension of transient resources. - Added transient tag to RDG insights to track which resources are transient. #rb luke.thatcher, kenzo.terelst [CL 15726534 by zach bethel in ue5-main branch]
507 lines
14 KiB
C++
507 lines
14 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "RenderGraphAllocator.h"
|
|
#include "ProfilingDebugging/RealtimeGPUProfiler.h"
|
|
|
|
/** DEFINES */
|
|
|
|
/** Whether render graph debugging is enabled. */
|
|
#define RDG_ENABLE_DEBUG (!UE_BUILD_SHIPPING && !UE_BUILD_TEST)
|
|
|
|
/** Performs the operation if RDG_ENABLE_DEBUG is enabled. Useful for one-line checks without explicitly wrapping in #if. */
|
|
#if RDG_ENABLE_DEBUG
|
|
#define IF_RDG_ENABLE_DEBUG(Op) Op
|
|
#else
|
|
#define IF_RDG_ENABLE_DEBUG(Op)
|
|
#endif
|
|
|
|
/** Whether render graph debugging is enabled and we are compiling with the engine. */
|
|
#define RDG_ENABLE_DEBUG_WITH_ENGINE (RDG_ENABLE_DEBUG && WITH_ENGINE)
|
|
|
|
/** Whether render graph insight tracing is enabled. */
|
|
#define RDG_ENABLE_TRACE UE_TRACE_ENABLED && !IS_PROGRAM && !UE_BUILD_SHIPPING
|
|
|
|
#if RDG_ENABLE_TRACE
|
|
#define IF_RDG_ENABLE_TRACE(Op) Op
|
|
#else
|
|
#define IF_RDG_ENABLE_TRACE(Op)
|
|
#endif
|
|
|
|
/** The type of GPU events the render graph system supports.
|
|
* RDG_EVENTS == 0 means there is no string processing at all.
|
|
* RDG_EVENTS == 1 means the format component of the event name is stored as a const TCHAR*.
|
|
* RDG_EVENTS == 2 means string formatting is evaluated and stored in an FString.
|
|
*/
|
|
#define RDG_EVENTS_NONE 0
|
|
#define RDG_EVENTS_STRING_REF 1
|
|
#define RDG_EVENTS_STRING_COPY 2
|
|
|
|
/** Whether render graph GPU events are enabled. */
|
|
#if WITH_PROFILEGPU
|
|
#define RDG_EVENTS RDG_EVENTS_STRING_COPY
|
|
#else
|
|
#define RDG_EVENTS RDG_EVENTS_NONE
|
|
#endif
|
|
|
|
#define RDG_GPU_SCOPES (RDG_EVENTS || HAS_GPU_STATS)
|
|
|
|
#if RDG_GPU_SCOPES
|
|
#define IF_RDG_GPU_SCOPES(Op) Op
|
|
#else
|
|
#define IF_RDG_GPU_SCOPES(Op)
|
|
#endif
|
|
|
|
#define RDG_CPU_SCOPES (CSV_PROFILER)
|
|
|
|
#if RDG_CPU_SCOPES
|
|
#define IF_RDG_CPU_SCOPES(Op) Op
|
|
#else
|
|
#define IF_RDG_CPU_SCOPES(Op)
|
|
#endif
|
|
|
|
#define RDG_CMDLIST_STATS (STATS || ENABLE_STATNAMEDEVENTS)
|
|
|
|
#if RDG_CMDLIST_STATS
|
|
#define IF_RDG_CMDLIST_STATS(Op) Op
|
|
#else
|
|
#define IF_RDG_CMDLIST_STATS(Op)
|
|
#endif
|
|
|
|
/** ENUMS */
|
|
|
|
/** Flags to annotate a pass with when calling AddPass. */
|
|
enum class ERDGPassFlags : uint8
|
|
{
|
|
/** Pass doesn't have any inputs or outputs tracked by the graph. This may only be used by the parameterless AddPass function. */
|
|
None = 0,
|
|
|
|
/** Pass uses rasterization on the graphics pipe. */
|
|
Raster = 1 << 0,
|
|
|
|
/** Pass uses compute on the graphics pipe. */
|
|
Compute = 1 << 1,
|
|
|
|
/** Pass uses compute on the async compute pipe. */
|
|
AsyncCompute = 1 << 2,
|
|
|
|
/** Pass uses copy commands on the graphics pipe. */
|
|
Copy = 1 << 3,
|
|
|
|
/** Pass (and its producers) will never be culled. Necessary if outputs cannot be tracked by the graph. */
|
|
NeverCull = 1 << 4,
|
|
|
|
/** Render pass begin / end is skipped and left to the user. Only valid when combined with 'Raster'. Disables render pass merging for the pass. */
|
|
SkipRenderPass = 1 << 5,
|
|
|
|
/** Pass uses copy commands but writes to a staging resource. */
|
|
Readback = Copy | NeverCull
|
|
};
|
|
ENUM_CLASS_FLAGS(ERDGPassFlags);
|
|
|
|
/** Flags to annotate a render graph buffer. */
|
|
enum class ERDGBufferFlags : uint8
|
|
{
|
|
None = 0,
|
|
|
|
/** Tag the buffer to survive through frame, that is important for multi GPU alternate frame rendering. */
|
|
MultiFrame = 1 << 0,
|
|
|
|
/** The buffer may only be used for read-only access within the graph. This flag is only allowed for registered buffers. */
|
|
ReadOnly = 1 << 1
|
|
};
|
|
ENUM_CLASS_FLAGS(ERDGBufferFlags);
|
|
|
|
/** Flags to annotate a render graph texture. */
|
|
enum class ERDGTextureFlags : uint8
|
|
{
|
|
None = 0,
|
|
|
|
/** Tag the texture to survive through frame, that is important for multi GPU alternate frame rendering. */
|
|
MultiFrame = 1 << 0,
|
|
|
|
/** The texture may only be used for read-only access within the graph. This flag is only allowed for registered textures. */
|
|
ReadOnly = 1 << 1,
|
|
|
|
/** Prevents metadata decompression on this texture. */
|
|
MaintainCompression = 1 << 2,
|
|
};
|
|
ENUM_CLASS_FLAGS(ERDGTextureFlags);
|
|
|
|
/** Flags to annotate a view with when calling CreateUAV. */
|
|
enum class ERDGUnorderedAccessViewFlags : uint8
|
|
{
|
|
None = 0,
|
|
|
|
// The view will not perform UAV barriers between consecutive usage.
|
|
SkipBarrier = 1 << 0
|
|
};
|
|
ENUM_CLASS_FLAGS(ERDGUnorderedAccessViewFlags);
|
|
|
|
/** The set of concrete parent resource types. */
|
|
enum class ERDGParentResourceType : uint8
|
|
{
|
|
Texture,
|
|
Buffer,
|
|
MAX
|
|
};
|
|
|
|
/** The set of concrete view types. */
|
|
enum class ERDGViewType : uint8
|
|
{
|
|
TextureUAV,
|
|
TextureSRV,
|
|
BufferUAV,
|
|
BufferSRV,
|
|
MAX
|
|
};
|
|
|
|
/** Returns the equivalent parent resource type for a view type. */
|
|
inline ERDGParentResourceType GetParentResourceType(ERDGViewType ViewType)
|
|
{
|
|
switch (ViewType)
|
|
{
|
|
case ERDGViewType::TextureUAV:
|
|
case ERDGViewType::TextureSRV:
|
|
return ERDGParentResourceType::Texture;
|
|
case ERDGViewType::BufferUAV:
|
|
case ERDGViewType::BufferSRV:
|
|
return ERDGParentResourceType::Buffer;
|
|
default:
|
|
checkNoEntry();
|
|
return ERDGParentResourceType::MAX;
|
|
}
|
|
}
|
|
|
|
/** Used to specify a texture metadata plane when creating a view. */
|
|
enum class ERDGTextureMetaDataAccess : uint8
|
|
{
|
|
/** The primary plane is used with default compression behavior. */
|
|
None = 0,
|
|
|
|
/** The primary plane is used without decompressing it. */
|
|
CompressedSurface,
|
|
|
|
/** The depth plane is used with default compression behavior. */
|
|
Depth,
|
|
|
|
/** The stencil plane is used with default compression behavior. */
|
|
Stencil,
|
|
|
|
/** The HTile plane is used. */
|
|
HTile,
|
|
|
|
/** the FMask plane is used. */
|
|
FMask,
|
|
|
|
/** the CMask plane is used. */
|
|
CMask
|
|
};
|
|
|
|
/** Returns the associated FRHITransitionInfo plane index. */
|
|
inline int32 GetResourceTransitionPlaneForMetadataAccess(ERDGTextureMetaDataAccess Metadata)
|
|
{
|
|
switch (Metadata)
|
|
{
|
|
case ERDGTextureMetaDataAccess::CompressedSurface:
|
|
case ERDGTextureMetaDataAccess::HTile:
|
|
case ERDGTextureMetaDataAccess::Depth:
|
|
return FRHITransitionInfo::kDepthPlaneSlice;
|
|
case ERDGTextureMetaDataAccess::Stencil:
|
|
return FRHITransitionInfo::kStencilPlaneSlice;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/** HANDLE UTILITIES */
|
|
|
|
/** Handle helper class for internal tracking of RDG types. */
|
|
template <typename LocalObjectType, typename LocalIndexType>
|
|
class TRDGHandle
|
|
{
|
|
public:
|
|
using ObjectType = LocalObjectType;
|
|
using IndexType = LocalIndexType;
|
|
|
|
static const TRDGHandle Null;
|
|
|
|
TRDGHandle() = default;
|
|
|
|
explicit inline TRDGHandle(int32 InIndex)
|
|
{
|
|
check(InIndex >= 0 && InIndex <= kNullIndex);
|
|
Index = InIndex;
|
|
}
|
|
|
|
FORCEINLINE IndexType GetIndex() const { check(IsValid()); return Index; }
|
|
FORCEINLINE IndexType GetIndexUnchecked() const { return Index; }
|
|
FORCEINLINE bool IsNull() const { return Index == kNullIndex; }
|
|
FORCEINLINE bool IsValid() const { return Index != kNullIndex; }
|
|
FORCEINLINE bool operator==(TRDGHandle Other) const { return Index == Other.Index; }
|
|
FORCEINLINE bool operator!=(TRDGHandle Other) const { return Index != Other.Index; }
|
|
FORCEINLINE bool operator<=(TRDGHandle Other) const { check(IsValid() && Other.IsValid()); return Index <= Other.Index; }
|
|
FORCEINLINE bool operator>=(TRDGHandle Other) const { check(IsValid() && Other.IsValid()); return Index >= Other.Index; }
|
|
FORCEINLINE bool operator< (TRDGHandle Other) const { check(IsValid() && Other.IsValid()); return Index < Other.Index; }
|
|
FORCEINLINE bool operator> (TRDGHandle Other) const { check(IsValid() && Other.IsValid()); return Index > Other.Index; }
|
|
|
|
FORCEINLINE TRDGHandle& operator++()
|
|
{
|
|
check(IsValid());
|
|
++Index;
|
|
return *this;
|
|
}
|
|
|
|
FORCEINLINE TRDGHandle& operator--()
|
|
{
|
|
check(IsValid());
|
|
--Index;
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
static const IndexType kNullIndex = TNumericLimits<IndexType>::Max();
|
|
IndexType Index = kNullIndex;
|
|
};
|
|
|
|
template <typename ObjectType, typename IndexType>
|
|
FORCEINLINE uint32 GetTypeHash(TRDGHandle<ObjectType, IndexType> Handle)
|
|
{
|
|
return Handle.GetIndex();
|
|
}
|
|
|
|
/** Helper handle registry class for internal tracking of RDG types. */
|
|
template <typename LocalHandleType>
|
|
class TRDGHandleRegistry
|
|
{
|
|
public:
|
|
using HandleType = LocalHandleType;
|
|
using ObjectType = typename HandleType::ObjectType;
|
|
using IndexType = typename HandleType::IndexType;
|
|
|
|
void Insert(ObjectType* Object)
|
|
{
|
|
Array.Emplace(Object);
|
|
Object->Handle = Last();
|
|
}
|
|
|
|
template<typename DerivedType = ObjectType, class ...TArgs>
|
|
DerivedType* Allocate(FRDGAllocator& Allocator, TArgs&&... Args)
|
|
{
|
|
static_assert(TIsDerivedFrom<DerivedType, ObjectType>::Value, "You must specify a type that derives from ObjectType");
|
|
DerivedType* Object = Allocator.AllocNoDestruct<DerivedType>(Forward<TArgs>(Args)...);
|
|
Insert(Object);
|
|
return Object;
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
for (int32 Index = Array.Num() - 1; Index >= 0; --Index)
|
|
{
|
|
Array[Index]->~ObjectType();
|
|
}
|
|
Array.Empty();
|
|
}
|
|
|
|
FORCEINLINE const ObjectType* Get(HandleType Handle) const
|
|
{
|
|
return Array[Handle.GetIndex()];
|
|
}
|
|
|
|
FORCEINLINE ObjectType* Get(HandleType Handle)
|
|
{
|
|
return Array[Handle.GetIndex()];
|
|
}
|
|
|
|
FORCEINLINE const ObjectType* operator[] (HandleType Handle) const
|
|
{
|
|
return Get(Handle);
|
|
}
|
|
|
|
FORCEINLINE ObjectType* operator[] (HandleType Handle)
|
|
{
|
|
return Get(Handle);
|
|
}
|
|
|
|
FORCEINLINE HandleType Begin() const
|
|
{
|
|
return HandleType(0);
|
|
}
|
|
|
|
FORCEINLINE HandleType End() const
|
|
{
|
|
return HandleType(Array.Num());
|
|
}
|
|
|
|
FORCEINLINE HandleType Last() const
|
|
{
|
|
return HandleType(Array.Num() - 1);
|
|
}
|
|
|
|
FORCEINLINE int32 Num() const
|
|
{
|
|
return Array.Num();
|
|
}
|
|
|
|
private:
|
|
TArray<ObjectType*, FRDGArrayAllocator> Array;
|
|
};
|
|
|
|
/** Specialization of bit array with compile-time type checking for handles and a pre-configured allocator. */
|
|
template <typename HandleType>
|
|
class TRDGHandleBitArray : public TBitArray<FRDGBitArrayAllocator>
|
|
{
|
|
using Base = TBitArray<FRDGBitArrayAllocator>;
|
|
public:
|
|
TRDGHandleBitArray() = default;
|
|
TRDGHandleBitArray(const TRDGHandleBitArray&) = default;
|
|
TRDGHandleBitArray& operator=(const TRDGHandleBitArray&) = default;
|
|
|
|
explicit TRDGHandleBitArray(bool bValue, int32 InNumBits)
|
|
: Base(bValue, InNumBits)
|
|
{}
|
|
|
|
FORCEINLINE FBitReference operator[](HandleType Handle)
|
|
{
|
|
return Base::operator[](Handle.GetIndex());
|
|
}
|
|
|
|
FORCEINLINE const FConstBitReference operator[](HandleType Handle) const
|
|
{
|
|
return Base::operator[](Handle.GetIndex());
|
|
}
|
|
};
|
|
|
|
/** Esoteric helper class which accumulates handles and will return a valid handle only if a single unique
|
|
* handle was added. Otherwise, it returns null until reset. This helper is chiefly used to track UAVs
|
|
* tagged as 'no UAV barrier'; such that a UAV barrier is issued only if a unique no-barrier UAV is used
|
|
* on a pass. Intended for internal use only.
|
|
*/
|
|
template <typename HandleType>
|
|
class TRDGHandleUniqueFilter
|
|
{
|
|
public:
|
|
TRDGHandleUniqueFilter() = default;
|
|
|
|
TRDGHandleUniqueFilter(HandleType InHandle)
|
|
{
|
|
AddHandle(InHandle);
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
Handle = HandleType::Null;
|
|
bUnique = false;
|
|
}
|
|
|
|
void AddHandle(HandleType InHandle)
|
|
{
|
|
if (Handle != InHandle && InHandle.IsValid())
|
|
{
|
|
bUnique = Handle.IsNull();
|
|
Handle = InHandle;
|
|
}
|
|
}
|
|
|
|
HandleType GetUniqueHandle() const
|
|
{
|
|
return bUnique ? Handle : HandleType::Null;
|
|
}
|
|
|
|
private:
|
|
HandleType Handle;
|
|
bool bUnique = false;
|
|
};
|
|
|
|
template <typename ObjectType, typename IndexType>
|
|
const TRDGHandle<ObjectType, IndexType> TRDGHandle<ObjectType, IndexType>::Null;
|
|
|
|
/** FORWARD DECLARATIONS */
|
|
|
|
using FRDGTextureDesc = FRHITextureCreateInfo;
|
|
|
|
class FRDGBlackboard;
|
|
|
|
class FRDGAsyncComputeBudgetScopeGuard;
|
|
class FRDGEventScopeGuard;
|
|
class FRDGGPUStatScopeGuard;
|
|
class FRDGScopedCsvStatExclusive;
|
|
class FRDGScopedCsvStatExclusiveConditional;
|
|
|
|
class FRDGBarrierBatch;
|
|
class FRDGBarrierBatchBegin;
|
|
class FRDGBarrierBatchEnd;
|
|
class FRDGBarrierValidation;
|
|
class FRDGBuilder;
|
|
class FRDGEventName;
|
|
class FRDGUserValidation;
|
|
class FRenderGraphResourcePool;
|
|
|
|
class FRDGResource;
|
|
using FRDGResourceRef = FRDGResource*;
|
|
|
|
class FRDGParentResource;
|
|
using FRDGParentResourceRef = FRDGParentResource*;
|
|
|
|
class FRDGShaderResourceView;
|
|
using FRDGShaderResourceViewRef = FRDGShaderResourceView*;
|
|
|
|
class FRDGUnorderedAccessView;
|
|
using FRDGUnorderedAccessViewRef = FRDGUnorderedAccessView*;
|
|
|
|
class FRDGTextureSRV;
|
|
using FRDGTextureSRVRef = FRDGTextureSRV*;
|
|
|
|
class FRDGTextureUAV;
|
|
using FRDGTextureUAVRef = FRDGTextureUAV*;
|
|
|
|
class FRDGBufferSRV;
|
|
using FRDGBufferSRVRef = FRDGBufferSRV*;
|
|
|
|
class FRDGBufferUAV;
|
|
using FRDGBufferUAVRef = FRDGBufferUAV*;
|
|
|
|
class FRDGPass;
|
|
using FRDGPassRef = const FRDGPass*;
|
|
using FRDGPassHandle = TRDGHandle<FRDGPass, uint16>;
|
|
using FRDGPassRegistry = TRDGHandleRegistry<FRDGPassHandle>;
|
|
using FRDGPassHandleArray = TArray<FRDGPassHandle, TInlineAllocator<4, FRDGArrayAllocator>>;
|
|
using FRDGPassBitArray = TRDGHandleBitArray<FRDGPassHandle>;
|
|
|
|
class FRDGUniformBuffer;
|
|
using FRDGUniformBufferRef = FRDGUniformBuffer*;
|
|
using FRDGUniformBufferHandle = TRDGHandle<FRDGUniformBuffer, uint16>;
|
|
using FRDGUniformBufferRegistry = TRDGHandleRegistry<FRDGUniformBufferHandle>;
|
|
using FRDGUniformBufferBitArray = TRDGHandleBitArray<FRDGUniformBufferHandle>;
|
|
|
|
class FRDGView;
|
|
using FRDGViewRef = FRDGView*;
|
|
using FRDGViewHandle = TRDGHandle<FRDGView, uint16>;
|
|
using FRDGViewRegistry = TRDGHandleRegistry<FRDGViewHandle>;
|
|
using FRDGViewUniqueFilter = TRDGHandleUniqueFilter<FRDGViewHandle>;
|
|
|
|
class FRDGTexture;
|
|
using FRDGTextureRef = FRDGTexture*;
|
|
using FRDGTextureHandle = TRDGHandle<FRDGTexture, uint16>;
|
|
using FRDGTextureRegistry = TRDGHandleRegistry<FRDGTextureHandle>;
|
|
using FRDGTextureBitArray = TRDGHandleBitArray<FRDGTextureHandle>;
|
|
|
|
class FRDGBuffer;
|
|
using FRDGBufferRef = FRDGBuffer*;
|
|
using FRDGBufferHandle = TRDGHandle<FRDGBuffer, uint16>;
|
|
using FRDGBufferRegistry = TRDGHandleRegistry<FRDGBufferHandle>;
|
|
using FRDGBufferBitArray = TRDGHandleBitArray<FRDGBufferHandle>;
|
|
|
|
class FRDGPooledTexture;
|
|
class FRDGPooledBuffer;
|
|
|
|
template <typename TUniformStruct> class TRDGUniformBuffer;
|
|
template <typename TUniformStruct> using TRDGUniformBufferRef = TRDGUniformBuffer<TUniformStruct>*;
|
|
|
|
template <typename InElementType, typename InAllocatorType = FDefaultAllocator>
|
|
using TRDGTextureSubresourceArray = TArray<InElementType, TInlineAllocator<1, InAllocatorType>>;
|
|
|
|
using FRDGPassHandlesByPipeline = TRHIPipelineArray<FRDGPassHandle>;
|
|
|
|
class FRDGTrace; |