17 KiB
Raw Blame History

title, date, excerpt, tags, rating
title date excerpt tags rating
Untitled 2024-09-26 18:41:24

RenderBasePass()

传入RenderBasePass()的DepthStencil逻辑如下

const FExclusiveDepthStencil::Type BasePassDepthStencilAccess =  
    bAllowReadOnlyDepthBasePass  
    ? FExclusiveDepthStencil::DepthRead_StencilWrite  
    : FExclusiveDepthStencil::DepthWrite_StencilWrite;

FDeferredShadingSceneRenderer::RenderBasePass() => FDeferredShadingSceneRenderer::RenderBasePassInternal() =>

FBasePassMeshProcessor::TryAddMeshBatch =>

大致流程

  1. 创建MRT并绑定、取得深度缓存。
const FExclusiveDepthStencil ExclusiveDepthStencil(BasePassDepthStencilAccess);  
  
TStaticArray<FTextureRenderTargetBinding, MaxSimultaneousRenderTargets> BasePassTextures;  
uint32 BasePassTextureCount = SceneTextures.GetGBufferRenderTargets(BasePassTextures);  
Strata::AppendStrataMRTs(*this, BasePassTextureCount, BasePassTextures);  
TArrayView<FTextureRenderTargetBinding> BasePassTexturesView = MakeArrayView(BasePassTextures.GetData(), BasePassTextureCount);  
FRDGTextureRef BasePassDepthTexture = SceneTextures.Depth.Target;
  1. GBuffer Clear
GraphBuilder.AddPass(RDG_EVENT_NAME("GBufferClear"), PassParameters, ERDGPassFlags::Raster,
			[PassParameters, ColorLoadAction, SceneColorClearValue](FRHICommandList& RHICmdList)
		{
			// If no fast-clear action was used, we need to do an MRT shader clear.
			if (ColorLoadAction == ERenderTargetLoadAction::ENoAction)
			{
				const FRenderTargetBindingSlots& RenderTargets = PassParameters->RenderTargets;
				FLinearColor ClearColors[MaxSimultaneousRenderTargets];
				FRHITexture* Textures[MaxSimultaneousRenderTargets];
				int32 TextureIndex = 0;

				RenderTargets.Enumerate([&](const FRenderTargetBinding& RenderTarget)
				{
					FRHITexture* TextureRHI = RenderTarget.GetTexture()->GetRHI();
					ClearColors[TextureIndex] = TextureIndex == 0 ? SceneColorClearValue : TextureRHI->GetClearColor();
					Textures[TextureIndex] = TextureRHI;
					++TextureIndex;
				});

				// Clear color only; depth-stencil is fast cleared.
				DrawClearQuadMRT(RHICmdList, true, TextureIndex, ClearColors, false, 0, false, 0);
			}
		});
  1. RenderTargetBindingSlots
// Render targets bindings should remain constant at this point.  
FRenderTargetBindingSlots BasePassRenderTargets = GetRenderTargetBindings(ERenderTargetLoadAction::ELoad, BasePassTexturesView);  
BasePassRenderTargets.DepthStencil = FDepthStencilBinding(BasePassDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, ExclusiveDepthStencil);
  1. RenderBasePassInternal()
  2. RenderAnisotropyPass()

MeshDraw

RenderBasePassInternal()

RenderNaniteBasePass()为一个Lambda最终调用Nanite::DrawBasePass() 渲染Nanite物体的BasePass。其他相关渲染代码如下

SCOPE_CYCLE_COUNTER(STAT_BasePassDrawTime);
		RDG_EVENT_SCOPE(GraphBuilder, "BasePass");
		RDG_GPU_STAT_SCOPE(GraphBuilder, Basepass);

		const bool bDrawSceneViewsInOneNanitePass = Views.Num() > 1 && Nanite::ShouldDrawSceneViewsInOneNanitePass(Views[0]);
		if (bParallelBasePass)//并行渲染模式
		{
			RDG_WAIT_FOR_TASKS_CONDITIONAL(GraphBuilder, IsBasePassWaitForTasksEnabled());

			for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
			{
				FViewInfo& View = Views[ViewIndex];
				RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
				RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
				View.BeginRenderView();

				const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen;

				FMeshPassProcessorRenderState DrawRenderState;
				SetupBasePassState(BasePassDepthStencilAccess, ViewFamily.EngineShowFlags.ShaderComplexity, DrawRenderState);

				FOpaqueBasePassParameters* PassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
				PassParameters->View = View.GetShaderParameters();
				PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
				PassParameters->BasePass = CreateOpaqueBasePassUniformBuffer(GraphBuilder, View, ViewIndex, ForwardBasePassTextures, DBufferTextures, bLumenGIEnabled);
				PassParameters->RenderTargets = BasePassRenderTargets;
				PassParameters->RenderTargets.ShadingRateTexture = GVRSImageManager.GetVariableRateShadingImage(GraphBuilder, View, FVariableRateShadingImageManager::EVRSPassType::BasePass);

				const bool bShouldRenderView = View.ShouldRenderView();
				if (bShouldRenderView)
				{
					View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams);

					GraphBuilder.AddPass(
						RDG_EVENT_NAME("BasePassParallel"),
						PassParameters,
						ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass,
						[this, &View, PassParameters](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList)
					{
						FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_BasePass), View, FParallelCommandListBindings(PassParameters));
						View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].DispatchDraw(&ParallelCommandListSet, RHICmdList, &PassParameters->InstanceCullingDrawParams);
					});
				}

				const bool bShouldRenderViewForNanite = bNaniteEnabled && (!bDrawSceneViewsInOneNanitePass || ViewIndex == 0); // when bDrawSceneViewsInOneNanitePass, the first view should cover all the other atlased ones
				if (bShouldRenderViewForNanite)
				{
					// Should always have a full Z prepass with Nanite
					check(ShouldRenderPrePass());
					//渲染Nanite物体BasePass
					RenderNaniteBasePass(View, ViewIndex);
				}

				//渲染编辑器相关的图元物体
				RenderEditorPrimitives(GraphBuilder, PassParameters, View, DrawRenderState, InstanceCullingManager);

				//渲染大气
				if (bShouldRenderView && View.Family->EngineShowFlags.Atmosphere)
				{
					FOpaqueBasePassParameters* SkyPassPassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
					SkyPassPassParameters->BasePass = PassParameters->BasePass;
					SkyPassPassParameters->RenderTargets = BasePassRenderTargets;
					SkyPassPassParameters->View = View.GetShaderParameters();
					SkyPassPassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;

					View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, SkyPassPassParameters->InstanceCullingDrawParams);

					GraphBuilder.AddPass(
						RDG_EVENT_NAME("SkyPassParallel"),
						SkyPassPassParameters,
						ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass,
						[this, &View, SkyPassPassParameters](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList)
					{
						FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_BasePass), View, FParallelCommandListBindings(SkyPassPassParameters));
						View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].DispatchDraw(&ParallelCommandListSet, RHICmdList, &SkyPassPassParameters->InstanceCullingDrawParams);
					});
				}
			}
		}
		else
		{
			for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
			{
				FViewInfo& View = Views[ViewIndex];
				RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
				RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
				View.BeginRenderView();

				const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen;

				FMeshPassProcessorRenderState DrawRenderState;
				SetupBasePassState(BasePassDepthStencilAccess, ViewFamily.EngineShowFlags.ShaderComplexity, DrawRenderState);

				FOpaqueBasePassParameters* PassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
				PassParameters->View = View.GetShaderParameters();
				PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
				PassParameters->BasePass = CreateOpaqueBasePassUniformBuffer(GraphBuilder, View, ViewIndex, ForwardBasePassTextures, DBufferTextures, bLumenGIEnabled);
				PassParameters->RenderTargets = BasePassRenderTargets;
				PassParameters->RenderTargets.ShadingRateTexture = GVRSImageManager.GetVariableRateShadingImage(GraphBuilder, View, FVariableRateShadingImageManager::EVRSPassType::BasePass);

				const bool bShouldRenderView = View.ShouldRenderView();
				if (bShouldRenderView)
				{
					View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams);

					GraphBuilder.AddPass(
						RDG_EVENT_NAME("BasePass"),
						PassParameters,
						ERDGPassFlags::Raster,
						[this, &View, PassParameters](FRHICommandList& RHICmdList)
						{
							SetStereoViewport(RHICmdList, View, 1.0f);
							View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].DispatchDraw(nullptr, RHICmdList, &PassParameters->InstanceCullingDrawParams);
						}
					);
				}

				const bool bShouldRenderViewForNanite = bNaniteEnabled && (!bDrawSceneViewsInOneNanitePass || ViewIndex == 0); // when bDrawSceneViewsInOneNanitePass, the first view should cover all the other atlased ones
				if (bShouldRenderViewForNanite)
				{
					// Should always have a full Z prepass with Nanite
					check(ShouldRenderPrePass());

					RenderNaniteBasePass(View, ViewIndex);
				}

				RenderEditorPrimitives(GraphBuilder, PassParameters, View, DrawRenderState, InstanceCullingManager);

				if (bShouldRenderView && View.Family->EngineShowFlags.Atmosphere)
				{
					FOpaqueBasePassParameters* SkyPassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
					SkyPassParameters->BasePass = PassParameters->BasePass;
					SkyPassParameters->RenderTargets = BasePassRenderTargets;
					SkyPassParameters->View = View.GetShaderParameters();
					SkyPassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;

					View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, SkyPassParameters->InstanceCullingDrawParams);

					GraphBuilder.AddPass(
						RDG_EVENT_NAME("SkyPass"),
						SkyPassParameters,
						ERDGPassFlags::Raster,
						[this, &View, SkyPassParameters](FRHICommandList& RHICmdList)
						{
							SetStereoViewport(RHICmdList, View, 1.0f);
							View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].DispatchDraw(nullptr, RHICmdList, &SkyPassParameters->InstanceCullingDrawParams);
						}
					);
				}
			}
		}

SetDepthStencilStateForBasePass()

void SetDepthStencilStateForBasePass(
	FMeshPassProcessorRenderState& DrawRenderState,
	ERHIFeatureLevel::Type FeatureLevel,
	bool bDitheredLODTransition,
	const FMaterial& MaterialResource,
	bool bEnableReceiveDecalOutput,
	bool bForceEnableStencilDitherState)
{
	const bool bMaskedInEarlyPass = (MaterialResource.IsMasked() || bDitheredLODTransition) && MaskedInEarlyPass(GShaderPlatformForFeatureLevel[FeatureLevel]);
	if (bEnableReceiveDecalOutput)
	{
		if (bMaskedInEarlyPass)
		{
			SetDepthStencilStateForBasePass_Internal<false, CF_Equal>(DrawRenderState, FeatureLevel);
		}
		else if (DrawRenderState.GetDepthStencilAccess() & FExclusiveDepthStencil::DepthWrite)
		{
			SetDepthStencilStateForBasePass_Internal<true, CF_GreaterEqual>(DrawRenderState, FeatureLevel);
		}
		else
		{
			SetDepthStencilStateForBasePass_Internal<false, CF_GreaterEqual>(DrawRenderState, FeatureLevel);
		}
	}
	else if (bMaskedInEarlyPass)
	{
		DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_Equal>::GetRHI());
	}

	if (bForceEnableStencilDitherState)
	{
		SetDepthStencilStateForBasePass_Internal<false, CF_Equal>(DrawRenderState, FeatureLevel);
	}
}

AnisotropyPass

Anisotropy的RT设置

  • RenderTargetSceneTextures.GBufferF。
  • DepthStencilSceneTextures.Depth.Target。ERenderTargetLoadAction::ELoadFExclusiveDepthStencil::DepthRead_StencilNop

管线状态

在FAnisotropyMeshProcessor::CollectPSOInitializers()中:

ETextureCreateFlags GBufferFCreateFlags;  
EPixelFormat GBufferFPixelFormat = FSceneTextures::GetGBufferFFormatAndCreateFlags(GBufferFCreateFlags);  
AddRenderTargetInfo(GBufferFPixelFormat, GBufferFCreateFlags, RenderTargetsInfo);  
SetupDepthStencilInfo(PF_DepthStencil, SceneTexturesConfig.DepthCreateFlags, ERenderTargetLoadAction::ELoad,  
    ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilNop, RenderTargetsInfo);
void SetupDepthStencilInfo(  
	EPixelFormat DepthStencilFormat,  
	ETextureCreateFlags DepthStencilCreateFlags,  
	ERenderTargetLoadAction DepthTargetLoadAction,  
	ERenderTargetLoadAction StencilTargetLoadAction,  
	FExclusiveDepthStencil DepthStencilAccess,  
	FGraphicsPipelineRenderTargetsInfo& RenderTargetsInfo)  
{  
    // Setup depth stencil state  
    RenderTargetsInfo.DepthStencilTargetFormat = DepthStencilFormat;  
    RenderTargetsInfo.DepthStencilTargetFlag = DepthStencilCreateFlags;  
    
    RenderTargetsInfo.DepthTargetLoadAction = DepthTargetLoadAction;  
    RenderTargetsInfo.StencilTargetLoadAction = StencilTargetLoadAction;  
    RenderTargetsInfo.DepthStencilAccess = DepthStencilAccess;  
    
    const ERenderTargetStoreAction StoreAction = EnumHasAnyFlags(RenderTargetsInfo.DepthStencilTargetFlag, TexCreate_Memoryless) ? ERenderTargetStoreAction::ENoAction : ERenderTargetStoreAction::EStore;  
    RenderTargetsInfo.DepthTargetStoreAction = RenderTargetsInfo.DepthStencilAccess.IsUsingDepth() ? StoreAction : ERenderTargetStoreAction::ENoAction;  
    RenderTargetsInfo.StencilTargetStoreAction = RenderTargetsInfo.DepthStencilAccess.IsUsingStencil() ? StoreAction : ERenderTargetStoreAction::ENoAction;  
}

ParallelRendering

AnisotropyPass支持并行渲染并行渲染的判断逻辑为

const bool bEnableParallelBasePasses = GRHICommandList.UseParallelAlgorithms() && CVarParallelBasePass.GetValueOnRenderThread();

看得出判断条件是:

  1. 显卡是否支持并行渲染。
  2. CVarr.ParallelBasePass是否开启并行渲染。

从AnisotropyPass可以看得出并行渲染与一般渲染的差别在于

  1. FRenderTargetBinding绑定时的ERenderTargetLoadAction不同并行为ELoad普通渲染为EClear
  2. 调用AddPass添加了ERDGPassFlags::SkipRenderPass标记。
  3. 并行渲染会在AddPass中构建FRDGParallelCommandListSet ParallelCommandListSet,并作为传入DispatchDraw普通渲染传递nullptr。
  4. 普通渲染会额外调用SetStereoViewport(RHICmdList, View);本质是调用RHICmdList.SetViewport来设置View。

Code

RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, RenderAnisotropyPass);
SCOPED_NAMED_EVENT(FDeferredShadingSceneRenderer_RenderAnisotropyPass, FColor::Emerald);
SCOPE_CYCLE_COUNTER(STAT_AnisotropyPassDrawTime);
RDG_GPU_STAT_SCOPE(GraphBuilder, RenderAnisotropyPass);

for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
	FViewInfo& View = Views[ViewIndex];

	if (View.ShouldRenderView())
	{
		FParallelMeshDrawCommandPass& ParallelMeshPass = View.ParallelMeshDrawCommandPasses[EMeshPass::AnisotropyPass];

		if (!ParallelMeshPass.HasAnyDraw())
		{
			continue;
		}

		View.BeginRenderView();

		auto* PassParameters = GraphBuilder.AllocParameters<FAnisotropyPassParameters>();
		PassParameters->View = View.GetShaderParameters();
		PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(SceneTextures.Depth.Target, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilNop);

		ParallelMeshPass.BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams);
		if (bDoParallelPass)
		{
			AddClearRenderTargetPass(GraphBuilder, SceneTextures.GBufferF);

			PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneTextures.GBufferF, ERenderTargetLoadAction::ELoad);

			GraphBuilder.AddPass(
				RDG_EVENT_NAME("AnisotropyPassParallel"),
				PassParameters,
				ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass,
				[this, &View, &ParallelMeshPass, PassParameters](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList)
			{
				FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_AnisotropyPass), View, FParallelCommandListBindings(PassParameters));

				ParallelMeshPass.DispatchDraw(&ParallelCommandListSet, RHICmdList, &PassParameters->InstanceCullingDrawParams);
			});
		}
		else
		{
			PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneTextures.GBufferF, ERenderTargetLoadAction::EClear);

			GraphBuilder.AddPass(
				RDG_EVENT_NAME("AnisotropyPass"),
				PassParameters,
				ERDGPassFlags::Raster,
				[this, &View, &ParallelMeshPass, PassParameters](FRHICommandList& RHICmdList)
			{
				SetStereoViewport(RHICmdList, View);

				ParallelMeshPass.DispatchDraw(nullptr, RHICmdList, &PassParameters->InstanceCullingDrawParams);
			});
		}
	}
}