11 KiB
Raw Blame History

title, date, excerpt, tags, rating
title date excerpt tags rating
剖析虚幻渲染体系11- RDG 2024-02-04 21:42:54

前言

https://www.cnblogs.com/timlly/p/15217090.html

概念

  • 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。
  • FRDGResourceRDG资源并不是直接用RHI资源而是包裹了RHI资源引用然后针对不同类型的资源各自封装且增加了额外的信息。
    • FRDGUniformBuffer、TRDGUniformBuffer
    • FRDGParentResource一种由图跟踪分配生命周期的渲染图资源。可能有引用它的子资源(例如视图)
    • FRDGView
    • FRDGBuffer、FRDGBufferSRV、FRDGBufferUAV
    • FRDGViewableResource一种由图跟踪分配生命周期的RPGResource。可能有引用它的子资源
      • FRDGTexture
    • FRDGView
      • FRDGUnorderedAccessView、FRDGTextureUAV
      • FRDGShaderResourceView、FRDGTextureSRV
  • FRDGTextureDesc创建渲染纹理的描述信息。
  • FRDGPooledTexture贴图池里的贴图资源。
  • FRDGPooledBuffer池化的缓冲区。
  • FRHITransition用于表示RHI中挂起的资源转换的不透明表面材质数据结构。
  • FRDGBarrierBatchRDG屏障批。
    • FRDGBarrierBatchBegin
    • FRDGBarrierBatchEnd
  • FRDGPass
    • TRDGLambdaPass
    • FRDGSentinelPass哨兵Pass用于开始/结束。
  • #FRDGBuilder

RDG基础类型

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;
	}
}

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开发