--- title: Untitled date: 2024-09-26 18:41:24 excerpt: tags: rating: ⭐ --- # RenderBasePass() 传入RenderBasePass()的DepthStencil逻辑如下: ```c++ const FExclusiveDepthStencil::Type BasePassDepthStencilAccess = bAllowReadOnlyDepthBasePass ? FExclusiveDepthStencil::DepthRead_StencilWrite : FExclusiveDepthStencil::DepthWrite_StencilWrite; ``` FDeferredShadingSceneRenderer::RenderBasePass() => FDeferredShadingSceneRenderer::RenderBasePassInternal() => FBasePassMeshProcessor::TryAddMeshBatch => ## 大致流程 1. 创建MRT并绑定、取得深度缓存。 ```c++ const FExclusiveDepthStencil ExclusiveDepthStencil(BasePassDepthStencilAccess); TStaticArray BasePassTextures; uint32 BasePassTextureCount = SceneTextures.GetGBufferRenderTargets(BasePassTextures); Strata::AppendStrataMRTs(*this, BasePassTextureCount, BasePassTextures); TArrayView BasePassTexturesView = MakeArrayView(BasePassTextures.GetData(), BasePassTextureCount); FRDGTextureRef BasePassDepthTexture = SceneTextures.Depth.Target; ``` 2. GBuffer Clear ```c++ 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); } }); ``` 3. RenderTargetBindingSlots ```c++ // Render targets bindings should remain constant at this point. FRenderTargetBindingSlots BasePassRenderTargets = GetRenderTargetBindings(ERenderTargetLoadAction::ELoad, BasePassTexturesView); BasePassRenderTargets.DepthStencil = FDepthStencilBinding(BasePassDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, ExclusiveDepthStencil); ``` 4. RenderBasePassInternal() 5. RenderAnisotropyPass() # MeshDraw ## RenderBasePassInternal() RenderNaniteBasePass()为一个Lambda,最终调用**Nanite::DrawBasePass()** 渲染Nanite物体的BasePass。其他相关渲染代码如下: ```c++ 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(); 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(); 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(); 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(); 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() ```c++ 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(DrawRenderState, FeatureLevel); } else if (DrawRenderState.GetDepthStencilAccess() & FExclusiveDepthStencil::DepthWrite) { SetDepthStencilStateForBasePass_Internal(DrawRenderState, FeatureLevel); } else { SetDepthStencilStateForBasePass_Internal(DrawRenderState, FeatureLevel); } } else if (bMaskedInEarlyPass) { DrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); } if (bForceEnableStencilDitherState) { SetDepthStencilStateForBasePass_Internal(DrawRenderState, FeatureLevel); } } ``` ## AnisotropyPass Anisotropy的RT设置: - RenderTarget:SceneTextures.GBufferF。 - DepthStencil:SceneTextures.Depth.Target。**ERenderTargetLoadAction::ELoad**、**FExclusiveDepthStencil::DepthRead_StencilNop** ### 管线状态 在FAnisotropyMeshProcessor::CollectPSOInitializers()中: ```c++ ETextureCreateFlags GBufferFCreateFlags; EPixelFormat GBufferFPixelFormat = FSceneTextures::GetGBufferFFormatAndCreateFlags(GBufferFCreateFlags); AddRenderTargetInfo(GBufferFPixelFormat, GBufferFCreateFlags, RenderTargetsInfo); SetupDepthStencilInfo(PF_DepthStencil, SceneTexturesConfig.DepthCreateFlags, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilNop, RenderTargetsInfo); ``` ```c++ 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支持并行渲染,并行渲染的判断逻辑为 ```c++ const bool bEnableParallelBasePasses = GRHICommandList.UseParallelAlgorithms() && CVarParallelBasePass.GetValueOnRenderThread(); ``` 看得出判断条件是: 1. 显卡是否支持并行渲染。 2. CVar(r.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 ```c++ 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(); 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); }); } } } ```