2024-02-05 09:54:25 +08:00
|
|
|
|
---
|
|
|
|
|
title: 剖析虚幻渲染体系(11)- RDG
|
|
|
|
|
date: 2024-02-04 21:42:54
|
|
|
|
|
excerpt:
|
|
|
|
|
tags:
|
|
|
|
|
rating: ⭐
|
|
|
|
|
---
|
|
|
|
|
# 前言
|
2024-02-05 14:28:02 +08:00
|
|
|
|
https://www.cnblogs.com/timlly/p/15217090.html
|
|
|
|
|
|
2024-02-05 17:20:01 +08:00
|
|
|
|
# 概念
|
|
|
|
|
- FRDGAllocator:简单的C++对象分配器, 用MemStack分配器追踪和销毁物体。
|
|
|
|
|
- FComputeShaderUtils
|
|
|
|
|
- Dispatch():派发ComputeShader到RHI命令列表,携带其参数。
|
|
|
|
|
- DispatchIndirect():派发非直接的ComputeShader到RHI命令列表,,携带其参数。
|
|
|
|
|
- AddPass():派发计算着色器到**RenderGraphBuilder**, 携带其参数。
|
|
|
|
|
- ClearUAV():清理UAV。
|
|
|
|
|
- AddCopyTexturePass():增加拷贝纹理Pass。
|
|
|
|
|
- AddCopyToResolveTargetPass():增加拷贝到解析目标的Pass。
|
|
|
|
|
- AddEnqueueCopyPass():增加回读纹理的Pass。
|
|
|
|
|
- AddPass():无参数的Pass增加。
|
|
|
|
|
- AddBeginUAVOverlapPass()/AddEndUAVOverlapPass(): 其它特殊Pass。
|
|
|
|
|
- FRDGResource:RDG资源并不是直接用RHI资源,而是包裹了RHI资源引用,然后针对不同类型的资源各自封装,且增加了额外的信息。
|
|
|
|
|
- FRDGUniformBuffer、TRDGUniformBuffer
|
|
|
|
|
- FRDGParentResource:一种由图跟踪分配生命周期的渲染图资源。可能有引用它的子资源(例如视图)
|
|
|
|
|
- FRDGView
|
|
|
|
|
- FRDGBuffer、FRDGBufferSRV、FRDGBufferUAV
|
|
|
|
|
- FRDGViewableResource:一种由图跟踪分配生命周期的RPGResource。可能有引用它的子资源
|
|
|
|
|
- FRDGTexture
|
|
|
|
|
- FRDGView
|
|
|
|
|
- FRDGUnorderedAccessView、FRDGTextureUAV
|
|
|
|
|
- FRDGShaderResourceView、FRDGTextureSRV
|
|
|
|
|
- FRDGTextureDesc:创建渲染纹理的描述信息。
|
|
|
|
|
- FRDGPooledTexture:贴图池里的贴图资源。
|
|
|
|
|
- FRDGPooledBuffer:池化的缓冲区。
|
|
|
|
|
- FRHITransition:用于表示RHI中挂起的资源转换的**不透明表面材质**数据结构。
|
|
|
|
|
- FRDGBarrierBatch:RDG屏障批。
|
|
|
|
|
- FRDGBarrierBatchBegin
|
|
|
|
|
- FRDGBarrierBatchEnd
|
|
|
|
|
- FRDGPass
|
|
|
|
|
- TRDGLambdaPass
|
|
|
|
|
- FRDGSentinelPass:哨兵Pass,用于开始/结束。
|
|
|
|
|
- [[#FRDGBuilder]]
|
|
|
|
|
|
2024-02-05 14:28:02 +08:00
|
|
|
|
## RDG基础类型
|
|
|
|
|
```c++
|
|
|
|
|
enum class ERDGBuilderFlags
|
|
|
|
|
{
|
|
|
|
|
None = 0,
|
|
|
|
|
|
|
|
|
|
/** Allows the builder to parallelize execution of passes. Without this flag, all passes execute on the render thread. */
|
|
|
|
|
AllowParallelExecute = 1 << 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** Flags to annotate a pass with when calling AddPass. */
|
|
|
|
|
enum class ERDGPassFlags : uint16
|
|
|
|
|
{
|
|
|
|
|
/** 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 will never have its render pass merged with other passes. */
|
|
|
|
|
NeverMerge = 1 << 6,
|
|
|
|
|
|
|
|
|
|
/** Pass will never run off the render thread. */
|
|
|
|
|
NeverParallel = 1 << 7,
|
|
|
|
|
|
|
|
|
|
ParallelTranslate = 1 << 8,
|
|
|
|
|
|
|
|
|
|
/** Pass uses copy commands but writes to a staging resource. */
|
|
|
|
|
Readback = Copy | NeverCull
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** 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 is ignored by RDG tracking and will never be transitioned. Use the flag when registering a buffer with no writable GPU flags.
|
|
|
|
|
* Write access is not allowed for the duration of the graph. This flag is intended as an optimization to cull out tracking of read-only
|
|
|
|
|
* buffers that are used frequently throughout the graph. Note that it's the user's responsibility to ensure the resource is in the correct
|
|
|
|
|
* readable state for use with RDG passes, as RDG does not know the exact state of the resource.
|
|
|
|
|
*/
|
|
|
|
|
SkipTracking = 1 << 1,
|
|
|
|
|
|
|
|
|
|
/** When set, RDG will perform its first barrier without splitting. Practically, this means the resource is left in its initial state
|
|
|
|
|
* until the first pass it's used within the graph. Without this flag, the resource is split-transitioned at the start of the graph.
|
|
|
|
|
*/
|
|
|
|
|
ForceImmediateFirstBarrier = 1 << 2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** 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 buffer is ignored by RDG tracking and will never be transitioned. Use the flag when registering a buffer with no writable GPU flags.
|
|
|
|
|
* Write access is not allowed for the duration of the graph. This flag is intended as an optimization to cull out tracking of read-only
|
|
|
|
|
* buffers that are used frequently throughout the graph. Note that it's the user's responsibility to ensure the resource is in the correct
|
|
|
|
|
* readable state for use with RDG passes, as RDG does not know the exact state of the resource.
|
|
|
|
|
*/
|
|
|
|
|
SkipTracking = 1 << 1,
|
|
|
|
|
|
|
|
|
|
/** When set, RDG will perform its first barrier without splitting. Practically, this means the resource is left in its initial state
|
|
|
|
|
* until the first pass it's used within the graph. Without this flag, the resource is split-transitioned at the start of the graph.
|
|
|
|
|
*/
|
|
|
|
|
ForceImmediateFirstBarrier = 1 << 2,
|
|
|
|
|
|
|
|
|
|
/** Prevents metadata decompression on this texture. */
|
|
|
|
|
MaintainCompression = 1 << 3,
|
|
|
|
|
};
|
|
|
|
|
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 ERDGViewableResourceType : uint8
|
|
|
|
|
{
|
|
|
|
|
Texture,
|
|
|
|
|
Buffer,
|
|
|
|
|
MAX
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** The set of concrete view types. */
|
|
|
|
|
enum class ERDGViewType : uint8
|
|
|
|
|
{
|
|
|
|
|
TextureUAV,
|
|
|
|
|
TextureSRV,
|
|
|
|
|
BufferUAV,
|
|
|
|
|
BufferSRV,
|
|
|
|
|
MAX
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline ERDGViewableResourceType GetParentType(ERDGViewType ViewType)
|
|
|
|
|
{
|
|
|
|
|
switch (ViewType)
|
|
|
|
|
{
|
|
|
|
|
case ERDGViewType::TextureUAV:
|
|
|
|
|
case ERDGViewType::TextureSRV:
|
|
|
|
|
return ERDGViewableResourceType::Texture;
|
|
|
|
|
case ERDGViewType::BufferUAV:
|
|
|
|
|
case ERDGViewType::BufferSRV:
|
|
|
|
|
return ERDGViewableResourceType::Buffer;
|
|
|
|
|
}
|
|
|
|
|
checkNoEntry();
|
|
|
|
|
return ERDGViewableResourceType::MAX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum class ERDGResourceExtractionFlags : uint8
|
|
|
|
|
{
|
|
|
|
|
None = 0,
|
|
|
|
|
|
|
|
|
|
// Allows the resource to remain transient. Only use this flag if you intend to register the resource back
|
|
|
|
|
// into the graph and release the reference. This should not be used if the resource is cached for a long
|
|
|
|
|
// period of time.
|
|
|
|
|
AllowTransient = 1,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class ERDGInitialDataFlags : uint8
|
|
|
|
|
{
|
|
|
|
|
/** Specifies the default behavior, which is to make a copy of the initial data for replay when
|
|
|
|
|
* the graph is executed. The user does not need to preserve lifetime of the data pointer.
|
|
|
|
|
*/
|
|
|
|
|
None = 0,
|
|
|
|
|
|
|
|
|
|
/** Specifies that the user will maintain ownership of the data until the graph is executed. The
|
|
|
|
|
* upload pass will only use a reference to store the data. Use caution with this flag since graph
|
|
|
|
|
* execution is deferred! Useful to avoid the copy if the initial data lifetime is guaranteed to
|
|
|
|
|
* outlive the graph.
|
|
|
|
|
*/
|
|
|
|
|
NoCopy = 1 << 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class ERDGPooledBufferAlignment : uint8
|
|
|
|
|
{
|
|
|
|
|
// The buffer size is not aligned.
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
|
|
// The buffer size is aligned up to the next page size.
|
|
|
|
|
Page,
|
|
|
|
|
|
|
|
|
|
// The buffer size is aligned up to the next power of two.
|
|
|
|
|
PowerOfTwo
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** Returns the equivalent parent resource type for a view type. */
|
|
|
|
|
inline ERDGViewableResourceType GetViewableResourceType(ERDGViewType ViewType)
|
|
|
|
|
{
|
|
|
|
|
switch (ViewType)
|
|
|
|
|
{
|
|
|
|
|
case ERDGViewType::TextureUAV:
|
|
|
|
|
case ERDGViewType::TextureSRV:
|
|
|
|
|
return ERDGViewableResourceType::Texture;
|
|
|
|
|
case ERDGViewType::BufferUAV:
|
|
|
|
|
case ERDGViewType::BufferSRV:
|
|
|
|
|
return ERDGViewableResourceType::Buffer;
|
|
|
|
|
default:
|
|
|
|
|
checkNoEntry();
|
|
|
|
|
return ERDGViewableResourceType::MAX;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using ERDGTextureMetaDataAccess = ERHITextureMetaDataAccess;
|
|
|
|
|
|
|
|
|
|
/** 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
2024-02-05 17:20:01 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## FRDGBuilder
|
|
|
|
|
FRDGBuilder是RDG体系的心脏和发动机,也是个大管家,负责收集渲染Pass和参数,编译Pass、数据,处理资源依赖,裁剪和优化各类数据,还有提供执行接口。
|
|
|
|
|
|
|
|
|
|
重要函数:
|
|
|
|
|
- FindExternalTexture():查找外部纹理, 若找不到返回null.
|
|
|
|
|
- RegisterExternalTexture():注册外部池内RT到RDG, 以便RDG追踪之. 池内RT可能包含两种RHI纹理: MSAA和非MSAA。
|
|
|
|
|
- RegisterExternalBuffer():注册外部缓冲区到RDG, 以便RDG追踪之.
|
|
|
|
|
- 资源创建接口:
|
|
|
|
|
- CreateTexture()
|
|
|
|
|
- CreateBuffer()
|
|
|
|
|
- CreateUAV()
|
|
|
|
|
- CreateSRV()
|
|
|
|
|
- CreateUniformBuffer()
|
|
|
|
|
- 分配内存, 内存由RDG管理生命周期。
|
|
|
|
|
- Alloc()
|
|
|
|
|
- AllocPOD()
|
|
|
|
|
- AllocObject()
|
|
|
|
|
- AllocParameters()
|
|
|
|
|
- AddPass()
|
|
|
|
|
- FRDGPassRef AddPass(FRDGEventName&& Name, const ParameterStructType* ParameterStruct, ERDGPassFlags Flags, ExecuteLambdaType&& ExecuteLambda); :增加有参数的LambdaPass。
|
|
|
|
|
- FRDGPassRef AddPass(FRDGEventName&& Name, const FShaderParametersMetadata* ParametersMetadata, const void* ParameterStruct, ERDGPassFlags Flags, ExecuteLambdaType&& ExecuteLambda); :增加带有实时生成结构体的LambdaPass
|
|
|
|
|
- FRDGPassRef AddPass(FRDGEventName&& Name, ERDGPassFlags Flags, ExecuteLambdaType&& ExecuteLambda);:增加没有参数的LambdaPass
|
|
|
|
|
- QueueTextureExtraction():在Builder执行末期, 提取池内纹理到指定的指针. 对于RDG创建的资源, 这将延长GPU资源的生命周期,直到执行,指针被填充. 如果指定,纹理将转换为AccessFinal状态, 否则将转换为kDefaultAccessFinal状态。
|
|
|
|
|
- QueueBufferExtraction():在Builder执行末期, 提取缓冲区到指定的指针。
|
|
|
|
|
- PreallocateTexture()/PreallocateBuffer():预分配资源. 只对RDG创建的资源, 会强制立即分配底层池内资源, 有效地将其推广到外部资源. 这将增加内存压力,但允许使用GetPooled{Texture, Buffer}查询池中的资源. 主要用于增量地将代码移植到RDG.
|
|
|
|
|
- GetPooledTexture()/GetPooledBuffer():立即获取底层资源, 只允许用于注册或预分配的资源。
|
|
|
|
|
- SetTextureAccessFinal()/SetBufferAccessFinal():设置执行之后的状态。
|
|
|
|
|
- 变量
|
|
|
|
|
- RDG对象注册表
|
|
|
|
|
- FRDGPassRegistry Passes;
|
|
|
|
|
- FRDGTextureRegistry Textures;
|
|
|
|
|
- FRDGBufferRegistry Buffers;
|
|
|
|
|
- FRDGViewRegistry Views;
|
|
|
|
|
- FRDGUniformBufferRegistry UniformBuffers;
|
|
|
|
|
|
|
|
|
|
### FRDGBuilder::Compile
|
|
|
|
|
RDG编译期间的逻辑非常复杂,步骤繁多,先后经历构建生产者和消费者的依赖关系,确定Pass的裁剪等各类标记,调整资源的生命周期,裁剪Pass,处理Pass的资源转换和屏障,处理异步计算Pass的依赖和引用关系,查找并建立分叉和合并Pass节点,合并所有具体相同渲染目标的光栅化Pass等步骤。
|
|
|
|
|
|
|
|
|
|
# RDG开发
|