Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/DepthRendering.cpp
2025-05-18 13:04:45 +08:00

1256 lines
50 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
DepthRendering.cpp: Depth rendering implementation.
=============================================================================*/
#include "DepthRendering.h"
#include "DataDrivenShaderPlatformInfo.h"
#include "Engine/Engine.h"
#include "RendererInterface.h"
#include "StaticBoundShaderState.h"
#include "SceneUtils.h"
#include "EngineGlobals.h"
#include "Materials/Material.h"
#include "PostProcess/SceneRenderTargets.h"
#include "GlobalShader.h"
#include "MaterialShaderType.h"
#include "MeshMaterialShaderType.h"
#include "MeshMaterialShader.h"
#include "SceneRendering.h"
#include "DeferredShadingRenderer.h"
#include "ScenePrivate.h"
#include "OneColorShader.h"
#include "IHeadMountedDisplay.h"
#include "IXRTrackingSystem.h"
#include "ScreenRendering.h"
#include "PostProcess/SceneFilterRendering.h"
#include "DynamicPrimitiveDrawing.h"
#include "PipelineStateCache.h"
#include "ClearQuad.h"
#include "MeshPassProcessor.inl"
#include "PixelShaderUtils.h"
#include "RenderGraphUtils.h"
#include "SceneRenderingUtils.h"
#include "DebugProbeRendering.h"
#include "RenderCore.h"
#include "SimpleMeshDrawCommandPass.h"
#include "UnrealEngine.h"
#include "DepthCopy.h"
static TAutoConsoleVariable<int32> CVarParallelPrePass(
TEXT("r.ParallelPrePass"),
1,
TEXT("Toggles parallel zprepass rendering. Parallel rendering must be enabled for this to have an effect."),
ECVF_RenderThreadSafe);
static int32 GEarlyZSortMasked = 1;
static FAutoConsoleVariableRef CVarSortPrepassMasked(
TEXT("r.EarlyZSortMasked"),
GEarlyZSortMasked,
TEXT("Sort EarlyZ masked draws to the end of the draw order.\n"),
ECVF_Default
);
static TAutoConsoleVariable<int32> CVarStencilLODDitherMode(
TEXT("r.StencilLODMode"),
2,
TEXT("Specifies the dither LOD stencil mode.\n")
TEXT(" 0: Graphics pass.\n")
TEXT(" 1: Compute pass (on supported platforms).\n")
TEXT(" 2: Compute async pass (on supported platforms)."),
ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarStencilForLODDither(
TEXT("r.StencilForLODDither"),
0,
TEXT("Whether to use stencil tests in the prepass, and depth-equal tests in the base pass to implement LOD dithering.\n")
TEXT("If disabled, LOD dithering will be done through clip() instructions in the prepass and base pass, which disables EarlyZ.\n")
TEXT("Forces a full prepass when enabled."),
ECVF_RenderThreadSafe | ECVF_ReadOnly);
static TAutoConsoleVariable<int32> CVarPSOPrecacheDitheredLODFadingOutMaskPass(
TEXT("r.PSOPrecache.DitheredLODFadingOutMaskPass"),
0,
TEXT("Precache PSOs for DitheredLODFadingOutMaskPass.\n") \
TEXT(" 0: No PSOs are compiled for this pass (default).\n") \
TEXT(" 1: PSOs are compiled for all primitives which render to depth pass.\n"),
ECVF_ReadOnly
);
static TAutoConsoleVariable<int32> CVarPSOPrecacheProjectedShadows(
TEXT("r.PSOPrecache.ProjectedShadows"),
1,
TEXT("Also Precache PSOs with for projected shadows.") \
TEXT(" 0: No PSOs are compiled for this pass.\n") \
TEXT(" 1: PSOs are compiled for all primitives which render to depth pass (default).\n"),
ECVF_ReadOnly
);
extern bool IsHMDHiddenAreaMaskActive();
FDepthPassInfo GetDepthPassInfo(const FScene* Scene)
{
FDepthPassInfo Info;
Info.EarlyZPassMode = Scene ? Scene->EarlyZPassMode : DDM_None;
Info.bEarlyZPassMovable = Scene ? Scene->bEarlyZPassMovable : false;
Info.bDitheredLODTransitionsUseStencil = CVarStencilForLODDither.GetValueOnAnyThread() > 0;
Info.StencilDitherPassFlags = ERDGPassFlags::Raster;
if (GRHISupportsDepthUAV && !IsHMDHiddenAreaMaskActive())
{
switch (CVarStencilLODDitherMode.GetValueOnAnyThread())
{
case 1:
Info.StencilDitherPassFlags = ERDGPassFlags::Compute;
break;
case 2:
Info.StencilDitherPassFlags = ERDGPassFlags::AsyncCompute;
break;
}
}
return Info;
}
BEGIN_SHADER_PARAMETER_STRUCT(FDepthPassParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
SHADER_PARAMETER_STRUCT_INCLUDE(FInstanceCullingDrawParams, InstanceCullingDrawParams)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
FDepthPassParameters* GetDepthPassParameters(FRDGBuilder& GraphBuilder, const FViewInfo& View, FRDGTextureRef DepthTexture)
{
auto* PassParameters = GraphBuilder.AllocParameters<FDepthPassParameters>();
PassParameters->View = View.GetShaderParameters();
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(DepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilWrite);
return PassParameters;
}
const TCHAR* GetDepthDrawingModeString(EDepthDrawingMode Mode)
{
switch (Mode)
{
case DDM_None:
return TEXT("DDM_None");
case DDM_NonMaskedOnly:
return TEXT("DDM_NonMaskedOnly");
case DDM_AllOccluders:
return TEXT("DDM_AllOccluders");
case DDM_AllOpaque:
return TEXT("DDM_AllOpaque");
case DDM_AllOpaqueNoVelocity:
return TEXT("DDM_AllOpaqueNoVelocity");
default:
check(0);
}
return TEXT("");
}
DECLARE_GPU_DRAWCALL_STAT(Prepass);
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TDepthOnlyVS<true>,TEXT("/Engine/Private/PositionOnlyDepthVertexShader.usf"),TEXT("Main"),SF_Vertex);
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TDepthOnlyVS<false>,TEXT("/Engine/Private/DepthOnlyVertexShader.usf"),TEXT("Main"),SF_Vertex);
IMPLEMENT_MATERIAL_SHADER_TYPE(,FDepthOnlyPS,TEXT("/Engine/Private/DepthOnlyPixelShader.usf"),TEXT("Main"),SF_Pixel);
IMPLEMENT_SHADERPIPELINE_TYPE_VS(DepthNoPixelPipeline, TDepthOnlyVS<false>, true);
IMPLEMENT_SHADERPIPELINE_TYPE_VS(DepthPosOnlyNoPixelPipeline, TDepthOnlyVS<true>, true);
IMPLEMENT_SHADERPIPELINE_TYPE_VSPS(DepthPipeline, TDepthOnlyVS<false>, FDepthOnlyPS, true);
template <bool bPositionOnly>
bool GetDepthPassShaders(
const FMaterial& Material,
const FVertexFactoryType* VertexFactoryType,
ERHIFeatureLevel::Type FeatureLevel,
bool bMaterialUsesPixelDepthOffset,
TShaderRef<TDepthOnlyVS<bPositionOnly>>& VertexShader,
TShaderRef<FDepthOnlyPS>& PixelShader,
FShaderPipelineRef& ShaderPipeline)
{
FMaterialShaderTypes ShaderTypes;
ShaderTypes.AddShaderType<TDepthOnlyVS<bPositionOnly>>();
if (bPositionOnly)
{
ShaderTypes.PipelineType = &DepthPosOnlyNoPixelPipeline;
/*ShaderPipeline = UseShaderPipelines(FeatureLevel) ? Material.GetShaderPipeline(&DepthPosOnlyNoPixelPipeline, VertexFactoryType) : FShaderPipelineRef();
VertexShader = ShaderPipeline.IsValid()
? ShaderPipeline.GetShader<TDepthOnlyVS<bPositionOnly> >()
: Material.GetShader<TDepthOnlyVS<bPositionOnly> >(VertexFactoryType, 0, false);
return VertexShader.IsValid();*/
}
else
{
const bool bVFTypeSupportsNullPixelShader = VertexFactoryType->SupportsNullPixelShader();
const bool bNeedsPixelShader = !Material.WritesEveryPixel(false, bVFTypeSupportsNullPixelShader) || bMaterialUsesPixelDepthOffset || Material.IsTranslucencyWritingCustomDepth();
if (bNeedsPixelShader)
{
ShaderTypes.AddShaderType<FDepthOnlyPS>();
ShaderTypes.PipelineType = &DepthPipeline;
}
else
{
ShaderTypes.PipelineType = &DepthNoPixelPipeline;
}
}
FMaterialShaders Shaders;
if (!Material.TryGetShaders(ShaderTypes, VertexFactoryType, Shaders))
{
return false;
}
Shaders.TryGetPipeline(ShaderPipeline);
Shaders.TryGetVertexShader(VertexShader);
Shaders.TryGetPixelShader(PixelShader);
return true;
}
#define IMPLEMENT_GetDepthPassShaders( bPositionOnly ) \
template bool GetDepthPassShaders< bPositionOnly >( \
const FMaterial& Material, \
const FVertexFactoryType* VertexFactoryType, \
ERHIFeatureLevel::Type FeatureLevel, \
bool bMaterialUsesPixelDepthOffset, \
TShaderRef<TDepthOnlyVS<bPositionOnly>>& VertexShader, \
TShaderRef<FDepthOnlyPS>& PixelShader, \
FShaderPipelineRef& ShaderPipeline \
);
IMPLEMENT_GetDepthPassShaders( true );
IMPLEMENT_GetDepthPassShaders( false );
FDepthStencilStateRHIRef GetDitheredLODTransitionDepthStencilState()
{
return TStaticDepthStencilState<true, CF_DepthNearOrEqual,
true, CF_Equal, SO_Keep, SO_Keep, SO_Keep,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
STENCIL_SANDBOX_MASK, STENCIL_SANDBOX_MASK
>::GetRHI();
}
void SetDepthPassDitheredLODTransitionState(const FSceneView* SceneView, const FMeshBatch& RESTRICT Mesh, int32 StaticMeshId, FMeshPassProcessorRenderState& DrawRenderState)
{
if (SceneView && StaticMeshId >= 0 && Mesh.bDitheredLODTransition)
{
checkSlow(SceneView->bIsViewInfo);
const FViewInfo* ViewInfo = (FViewInfo*)SceneView;
if (ViewInfo->bAllowStencilDither)
{
if (ViewInfo->StaticMeshFadeOutDitheredLODMap[StaticMeshId])
{
DrawRenderState.SetDepthStencilState(GetDitheredLODTransitionDepthStencilState());
DrawRenderState.SetStencilRef(STENCIL_SANDBOX_MASK);
}
else if (ViewInfo->StaticMeshFadeInDitheredLODMap[StaticMeshId])
{
DrawRenderState.SetDepthStencilState(GetDitheredLODTransitionDepthStencilState());
}
}
}
}
/** A pixel shader used to fill the stencil buffer with the current dithered transition mask. */
class FDitheredTransitionStencilPS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FDitheredTransitionStencilPS);
SHADER_USE_PARAMETER_STRUCT(FDitheredTransitionStencilPS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER(float, DitheredTransitionFactor)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
};
IMPLEMENT_GLOBAL_SHADER(FDitheredTransitionStencilPS, "/Engine/Private/DitheredTransitionStencil.usf", "Main", SF_Pixel);
/** A compute shader used to fill the stencil buffer with the current dithered transition mask. */
class FDitheredTransitionStencilCS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FDitheredTransitionStencilCS);
SHADER_USE_PARAMETER_STRUCT(FDitheredTransitionStencilCS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<uint>, StencilOutput)
SHADER_PARAMETER(float, DitheredTransitionFactor)
SHADER_PARAMETER(FIntVector4, StencilOffsetAndValues)
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
};
IMPLEMENT_GLOBAL_SHADER(FDitheredTransitionStencilCS, "/Engine/Private/DitheredTransitionStencil.usf", "MainCS", SF_Compute);
void AddDitheredStencilFillPass(FRDGBuilder& GraphBuilder, TConstArrayView<FViewInfo> Views, FRDGTextureRef DepthTexture, const FDepthPassInfo& DepthPass)
{
RDG_EVENT_SCOPE(GraphBuilder, "DitheredStencilPrePass");
checkf(EnumHasAnyFlags(DepthPass.StencilDitherPassFlags, ERDGPassFlags::Raster | ERDGPassFlags::Compute | ERDGPassFlags::AsyncCompute), TEXT("Stencil dither fill pass flags are invalid."));
if (DepthPass.StencilDitherPassFlags == ERDGPassFlags::Raster)
{
FRHIDepthStencilState* DepthStencilState = TStaticDepthStencilState<false, CF_Always,
true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
STENCIL_SANDBOX_MASK, STENCIL_SANDBOX_MASK>::GetRHI();
const uint32 StencilRef = STENCIL_SANDBOX_MASK;
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
const FViewInfo& View = Views[ViewIndex];
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
TShaderMapRef<FDitheredTransitionStencilPS> PixelShader(View.ShaderMap);
auto* PassParameters = GraphBuilder.AllocParameters<FDitheredTransitionStencilPS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
PassParameters->DitheredTransitionFactor = View.GetTemporalLODTransition();
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(DepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilWrite);
FPixelShaderUtils::AddFullscreenPass(GraphBuilder, View.ShaderMap, {}, PixelShader, PassParameters, View.ViewRect, nullptr, nullptr, DepthStencilState, StencilRef);
}
}
else
{
const int32 MaskedValue = (STENCIL_SANDBOX_MASK & 0xFF);
const int32 ClearedValue = 0;
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
const FViewInfo& View = Views[ViewIndex];
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
TShaderMapRef<FDitheredTransitionStencilCS> ComputeShader(View.ShaderMap);
auto* PassParameters = GraphBuilder.AllocParameters<FDitheredTransitionStencilCS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
PassParameters->StencilOutput = GraphBuilder.CreateUAV(FRDGTextureUAVDesc::CreateForMetaData(DepthTexture, ERDGTextureMetaDataAccess::Stencil));
PassParameters->DitheredTransitionFactor = View.GetTemporalLODTransition();
PassParameters->StencilOffsetAndValues = FIntVector4(View.ViewRect.Min.X, View.ViewRect.Min.Y, MaskedValue, ClearedValue);
const FIntPoint SubExtent(
FMath::Min(DepthTexture->Desc.Extent.X, View.ViewRect.Width()),
FMath::Min(DepthTexture->Desc.Extent.Y, View.ViewRect.Height()));
check(SubExtent.X > 0 && SubExtent.Y > 0);
FComputeShaderUtils::AddPass(
GraphBuilder,
{},
DepthPass.StencilDitherPassFlags,
ComputeShader,
PassParameters,
FComputeShaderUtils::GetGroupCount(SubExtent, FComputeShaderUtils::kGolden2DGroupSize));
}
}
}
// GPUCULL_TODO: Move to Utils file and make templated on params and mesh pass processor
static void AddViewMeshElementsPass(const TIndirectArray<FMeshBatch>& MeshElements, FRDGBuilder& GraphBuilder, FDepthPassParameters* PassParameters, const FScene* Scene, const FViewInfo& View, const FMeshPassProcessorRenderState& DrawRenderState, bool bRespectUseAsOccluderFlag, EDepthDrawingMode DepthDrawingMode, FInstanceCullingManager& InstanceCullingManager)
{
AddSimpleMeshPass(GraphBuilder, PassParameters, Scene, View, &InstanceCullingManager, RDG_EVENT_NAME("ViewMeshElementsPass"), View.ViewRect,
[&View, Scene, DrawRenderState, &MeshElements, bRespectUseAsOccluderFlag, DepthDrawingMode](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
{
FDepthPassMeshProcessor PassMeshProcessor(
EMeshPass::DepthPass,
View.Family->Scene->GetRenderScene(),
View.GetFeatureLevel(),
&View,
DrawRenderState,
bRespectUseAsOccluderFlag,
DepthDrawingMode,
false,
false,
DynamicMeshPassContext);
const uint64 DefaultBatchElementMask = ~0ull;
for (const FMeshBatch& MeshBatch : MeshElements)
{
PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);
}
}
);
}
static void RenderPrePassEditorPrimitives(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
FDepthPassParameters* PassParameters,
const FMeshPassProcessorRenderState& DrawRenderState,
EDepthDrawingMode DepthDrawingMode)
{
GraphBuilder.AddPass(
RDG_EVENT_NAME("EditorPrimitives"),
PassParameters,
ERDGPassFlags::Raster,
[&View, DrawRenderState, DepthDrawingMode](FRHICommandList& RHICmdList)
{
const bool bRespectUseAsOccluderFlag = true;
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, EBlendModeFilter::OpaqueAndMasked, SDPG_World);
View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, EBlendModeFilter::OpaqueAndMasked, SDPG_Foreground);
if (!View.Family->EngineShowFlags.CompositeEditorPrimitives)
{
DrawDynamicMeshPass(View, RHICmdList, [&](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
{
FDepthPassMeshProcessor PassMeshProcessor(
EMeshPass::DepthPass,
View.Family->Scene->GetRenderScene(),
View.GetFeatureLevel(),
&View,
DrawRenderState,
bRespectUseAsOccluderFlag,
DepthDrawingMode,
false,
false,
DynamicMeshPassContext);
const uint64 DefaultBatchElementMask = ~0ull;
for (int32 MeshIndex = 0; MeshIndex < View.ViewMeshElements.Num(); MeshIndex++)
{
const FMeshBatch& MeshBatch = View.ViewMeshElements[MeshIndex];
PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);
}
});
// Draw the view's batched simple elements(lines, sprites, etc).
View.BatchedViewElements.Draw(RHICmdList, DrawRenderState, View.FeatureLevel, View, false);
DrawDynamicMeshPass(View, RHICmdList, [&](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
{
FDepthPassMeshProcessor PassMeshProcessor(
EMeshPass::DepthPass,
View.Family->Scene->GetRenderScene(),
View.GetFeatureLevel(),
&View,
DrawRenderState,
bRespectUseAsOccluderFlag,
DepthDrawingMode,
false,
false,
DynamicMeshPassContext);
const uint64 DefaultBatchElementMask = ~0ull;
for (int32 MeshIndex = 0; MeshIndex < View.TopViewMeshElements.Num(); MeshIndex++)
{
const FMeshBatch& MeshBatch = View.TopViewMeshElements[MeshIndex];
PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);
}
});
// Draw the view's batched simple elements(lines, sprites, etc).
View.TopBatchedViewElements.Draw(RHICmdList, DrawRenderState, View.FeatureLevel, View, false);
}
});
}
void SetupDepthPassState(FMeshPassProcessorRenderState& DrawRenderState)
{
// Disable color writes, enable depth tests and writes.
DrawRenderState.SetBlendState(TStaticBlendState<CW_NONE>::GetRHI());
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<true, CF_DepthNearOrEqual>::GetRHI());
}
extern const TCHAR* GetDepthPassReason(bool bDitheredLODTransitionsUseStencil, EShaderPlatform ShaderPlatform);
void FDeferredShadingSceneRenderer::RenderPrePass(FRDGBuilder& GraphBuilder, TArrayView<FViewInfo> InViews, FRDGTextureRef SceneDepthTexture, FInstanceCullingManager& InstanceCullingManager, FRDGTextureRef* FirstStageDepthBuffer)
{
RDG_EVENT_SCOPE_STAT(GraphBuilder, Prepass, "PrePass %s %s", GetDepthDrawingModeString(DepthPass.EarlyZPassMode), GetDepthPassReason(DepthPass.bDitheredLODTransitionsUseStencil, ShaderPlatform));
RDG_GPU_STAT_SCOPE(GraphBuilder, Prepass);
RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, RenderPrePass);
SCOPED_NAMED_EVENT(FDeferredShadingSceneRenderer_RenderPrePass, FColor::Emerald);
SCOPE_CYCLE_COUNTER(STAT_DepthDrawTime);
const bool bParallelDepthPass = GRHICommandList.UseParallelAlgorithms() && CVarParallelPrePass.GetValueOnRenderThread();
RenderPrePassHMD(GraphBuilder, InViews, SceneDepthTexture);
if (DepthPass.IsRasterStencilDitherEnabled())
{
AddDitheredStencilFillPass(GraphBuilder, InViews, SceneDepthTexture, DepthPass);
}
auto RenderDepthPass = [&](uint8 DepthMeshPass)
{
check(DepthMeshPass == EMeshPass::DepthPass || DepthMeshPass == EMeshPass::SecondStageDepthPass);
const bool bSecondStageDepthPass = DepthMeshPass == EMeshPass::SecondStageDepthPass;
if (bParallelDepthPass)
{
for (int32 ViewIndex = 0; ViewIndex < InViews.Num(); ++ViewIndex)
{
FViewInfo& View = InViews[ViewIndex];
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, InViews.Num() > 1, "View%d", ViewIndex);
FMeshPassProcessorRenderState DrawRenderState;
SetupDepthPassState(DrawRenderState);
const bool bShouldRenderView = View.ShouldRenderView() && (bSecondStageDepthPass ? View.bUsesSecondStageDepthPass : true);
if (bShouldRenderView)
{
View.BeginRenderView();
FDepthPassParameters* PassParameters = GetDepthPassParameters(GraphBuilder, View, SceneDepthTexture);
if (auto* Pass = View.ParallelMeshDrawCommandPasses[DepthMeshPass])
{
Pass->BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams);
GraphBuilder.AddDispatchPass(
bSecondStageDepthPass ? RDG_EVENT_NAME("SecondStageDepthPassParallel") : RDG_EVENT_NAME("DepthPassParallel"),
PassParameters,
ERDGPassFlags::Raster,
[Pass, PassParameters, DepthMeshPass](FRDGDispatchPassBuilder& DispatchPassBuilder)
{
Pass->Dispatch(DispatchPassBuilder, &PassParameters->InstanceCullingDrawParams);
});
}
else
{
InstanceCullingManager.SetDummyCullingParams(GraphBuilder, PassParameters->InstanceCullingDrawParams);
}
RenderPrePassEditorPrimitives(GraphBuilder, View, PassParameters, DrawRenderState, DepthPass.EarlyZPassMode);
}
}
}
else
{
for (int32 ViewIndex = 0; ViewIndex < InViews.Num(); ++ViewIndex)
{
FViewInfo& View = InViews[ViewIndex];
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, InViews.Num() > 1, "View%d", ViewIndex);
FMeshPassProcessorRenderState DrawRenderState;
SetupDepthPassState(DrawRenderState);
const bool bShouldRenderView = View.ShouldRenderView() && (bSecondStageDepthPass ? View.bUsesSecondStageDepthPass : true);
if (bShouldRenderView)
{
View.BeginRenderView();
FDepthPassParameters* PassParameters = GetDepthPassParameters(GraphBuilder, View, SceneDepthTexture);
if (auto* Pass = View.ParallelMeshDrawCommandPasses[DepthMeshPass])
{
Pass->BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams);
GraphBuilder.AddPass(
bSecondStageDepthPass ? RDG_EVENT_NAME("SecondStageDepthPass") : RDG_EVENT_NAME("DepthPass"),
PassParameters,
ERDGPassFlags::Raster,
[&View, Pass, PassParameters, DepthMeshPass](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
SetStereoViewport(RHICmdList, View, 1.0f);
Pass->Draw(RHICmdList, &PassParameters->InstanceCullingDrawParams);
});
}
else
{
InstanceCullingManager.SetDummyCullingParams(GraphBuilder, PassParameters->InstanceCullingDrawParams);
}
RenderPrePassEditorPrimitives(GraphBuilder, View, PassParameters, DrawRenderState, DepthPass.EarlyZPassMode);
}
}
}
};
// Draw a depth pass to avoid overdraw in the other passes.
if (DepthPass.EarlyZPassMode != DDM_None)
{
// Render primary depth pass.
RenderDepthPass(EMeshPass::DepthPass);
// Evaluate if any second stage depth buffer processing is required
bool bUsesSecondStageDepthPass = false;
for (int32 ViewIndex = 0; ViewIndex < InViews.Num(); ++ViewIndex)
{
FViewInfo& View = InViews[ViewIndex];
bUsesSecondStageDepthPass |= View.bUsesSecondStageDepthPass;
}
// Copy depth buffer and render secondary depth pass if needed.
if(bUsesSecondStageDepthPass)
{
FRDGTextureDesc FirstStageDepthBufferDesc = FRDGTextureDesc::Create2D(SceneDepthTexture->Desc.Extent, PF_DepthStencil, FClearValueBinding::DepthFar, TexCreate_DepthStencilTargetable | TexCreate_ShaderResource);
*FirstStageDepthBuffer = GraphBuilder.CreateTexture(FirstStageDepthBufferDesc, TEXT("FirstStageDepthBuffer"));
for (int32 ViewIndex = 0; ViewIndex < InViews.Num(); ++ViewIndex)
{
FViewInfo& View = InViews[ViewIndex];
if (View.bUsesSecondStageDepthPass)
{
DepthCopy::AddViewDepthCopyPSPass(GraphBuilder, View, SceneDepthTexture, *FirstStageDepthBuffer);
}
}
// Dispatch and render the meshes
RenderDepthPass(EMeshPass::SecondStageDepthPass);
}
}
// Dithered transition stencil mask clear, accounting for all active viewports
if (DepthPass.bDitheredLODTransitionsUseStencil)
{
auto* PassParameters = GraphBuilder.AllocParameters<FRenderTargetParameters>();
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(SceneDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilWrite);
GraphBuilder.AddPass(
RDG_EVENT_NAME("DitherStencilClear"),
PassParameters,
ERDGPassFlags::Raster,
[this, InViews](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
if (InViews.Num() > 1)
{
FIntRect FullViewRect = InViews[0].ViewRect;
for (int32 ViewIndex = 1; ViewIndex < InViews.Num(); ++ViewIndex)
{
FullViewRect.Union(InViews[ViewIndex].ViewRect);
}
RHICmdList.SetViewport(FullViewRect.Min.X, FullViewRect.Min.Y, 0, FullViewRect.Max.X, FullViewRect.Max.Y, 1);
}
DrawClearQuad(RHICmdList, false, FLinearColor::Transparent, false, 0, true, 0);
});
}
#if !(UE_BUILD_SHIPPING)
const bool bForwardShadingEnabled = IsForwardShadingEnabled(ShaderPlatform);
if (!bForwardShadingEnabled)
{
StampDeferredDebugProbeDepthPS(GraphBuilder, InViews, SceneDepthTexture);
}
#endif
}
bool FMobileSceneRenderer::ShouldRenderPrePass() const
{
// Draw a depth pass to avoid overdraw in the other passes.
return Scene->EarlyZPassMode == DDM_MaskedOnly || Scene->EarlyZPassMode == DDM_AllOpaque || Scene->EarlyZPassMode == DDM_AllOpaqueNoVelocity;
}
void FMobileSceneRenderer::RenderPrePass(FRHICommandList& RHICmdList, const FViewInfo& View, const FInstanceCullingDrawParams* InstanceCullingDrawParams)
{
if (auto* Pass = View.ParallelMeshDrawCommandPasses[EMeshPass::DepthPass])
{
checkSlow(RHICmdList.IsInsideRenderPass());
SCOPED_NAMED_EVENT(FMobileSceneRenderer_RenderPrePass, FColor::Emerald);
RHI_BREADCRUMB_EVENT_STAT(RHICmdList, Prepass, "MobileRenderPrePass");
SCOPED_GPU_STAT(RHICmdList, Prepass);
SCOPE_CYCLE_COUNTER(STAT_DepthDrawTime);
CSV_SCOPED_TIMING_STAT_EXCLUSIVE(RenderPrePass);
SetStereoViewport(RHICmdList, View);
Pass->Draw(RHICmdList, InstanceCullingDrawParams);
}
}
void FDeferredShadingSceneRenderer::RenderPrePassHMD(FRDGBuilder& GraphBuilder, TArrayView<FViewInfo> InViews, FRDGTextureRef DepthTexture)
{
// Early out before we change any state if there's not a mask to render
if (!IsHMDHiddenAreaMaskActive())
{
return;
}
auto* HMDDevice = GEngine->XRSystem->GetHMDDevice();
if (!HMDDevice)
{
return;
}
for (const FViewInfo& View : InViews)
{
// Don't draw the hidden area mesh in scene captures as they are not displayed
// through the HMD lenses.
const bool bIsCapture = View.bIsSceneCapture || View.bIsPlanarReflection;
if (IStereoRendering::IsStereoEyeView(View) && !bIsCapture)
{
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
FDepthPassParameters* PassParameters = GetDepthPassParameters(GraphBuilder, View, DepthTexture);
GraphBuilder.AddPass(
RDG_EVENT_NAME("HiddenAreaMask"),
PassParameters,
ERDGPassFlags::Raster,
[this, &View, HMDDevice](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
extern TGlobalResource<FFilterVertexDeclaration, FRenderResource::EInitPhase::Pre> GFilterVertexDeclaration;
TShaderMapRef<TOneColorVS<true>> VertexShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
FGraphicsPipelineStateInitializer GraphicsPSOInit;
GraphicsPSOInit.BlendState = TStaticBlendState<CW_NONE>::GetRHI();
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<true, CF_DepthNearOrEqual>::GetRHI();
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
SetShaderParametersLegacyVS(RHICmdList, VertexShader, 1.0f);
HMDDevice->DrawHiddenAreaMesh(RHICmdList, View.StereoViewIndex);
});
}
}
}
FMeshDrawCommandSortKey CalculateDepthPassMeshStaticSortKey(bool bIsMasked, const FMeshMaterialShader* VertexShader, const FMeshMaterialShader* PixelShader)
{
FMeshDrawCommandSortKey SortKey;
if (GEarlyZSortMasked)
{
SortKey.BasePass.VertexShaderHash = (VertexShader ? VertexShader->GetSortKey() : 0) & 0xFFFF;
SortKey.BasePass.PixelShaderHash = PixelShader ? PixelShader->GetSortKey() : 0;
SortKey.BasePass.Masked = bIsMasked ? 1 : 0;
}
else
{
SortKey.Generic.VertexShaderHash = VertexShader ? VertexShader->GetSortKey() : 0;
SortKey.Generic.PixelShaderHash = PixelShader ? PixelShader->GetSortKey() : 0;
}
return SortKey;
}
template<bool bPositionOnly>
bool FDepthPassMeshProcessor::Process(
const FMeshBatch& RESTRICT MeshBatch,
uint64 BatchElementMask,
int32 StaticMeshId,
const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy,
const FMaterialRenderProxy& RESTRICT MaterialRenderProxy,
const FMaterial& RESTRICT MaterialResource,
ERasterizerFillMode MeshFillMode,
ERasterizerCullMode MeshCullMode)
{
const FVertexFactory* VertexFactory = MeshBatch.VertexFactory;
TMeshProcessorShaders<
TDepthOnlyVS<bPositionOnly>,
FDepthOnlyPS> DepthPassShaders;
FShaderPipelineRef ShaderPipeline;
if (!GetDepthPassShaders<bPositionOnly>(
MaterialResource,
VertexFactory->GetType(),
FeatureLevel,
MaterialResource.MaterialUsesPixelDepthOffset_RenderThread(),
DepthPassShaders.VertexShader,
DepthPassShaders.PixelShader,
ShaderPipeline))
{
return false;
}
FMeshPassProcessorRenderState DrawRenderState(PassDrawRenderState);
if (!bDitheredLODFadingOutMaskPass && !bShadowProjection)
{
SetDepthPassDitheredLODTransitionState(ViewIfDynamicMeshCommand, MeshBatch, StaticMeshId, DrawRenderState);
}
// Use StencilMask for DecalOutput on mobile
if (FeatureLevel == ERHIFeatureLevel::ES3_1 && !bShadowProjection)
{
extern void SetMobileBasePassDepthState(FMeshPassProcessorRenderState& DrawRenderState, const FPrimitiveSceneProxy* PrimitiveSceneProxy, const FMaterial& Material, FMaterialShadingModelField ShadingModels, bool bUsesDeferredShading);
// *Don't* get shading models from MaterialResource since it's for a default material
FMaterialShadingModelField ShadingModels = MeshBatch.MaterialRenderProxy->GetIncompleteMaterialWithFallback(ERHIFeatureLevel::ES3_1).GetShadingModels();
bool bUsesDeferredShading = IsMobileDeferredShadingEnabled(GetFeatureLevelShaderPlatform(FeatureLevel));
SetMobileBasePassDepthState(DrawRenderState, PrimitiveSceneProxy, MaterialResource, ShadingModels, bUsesDeferredShading);
}
FMeshMaterialShaderElementData ShaderElementData;
ShaderElementData.InitializeMeshMaterialData(ViewIfDynamicMeshCommand, PrimitiveSceneProxy, MeshBatch, StaticMeshId, true);
const bool bIsMasked = IsMaskedBlendMode(MaterialResource);
const FMeshDrawCommandSortKey SortKey = CalculateDepthPassMeshStaticSortKey(bIsMasked, DepthPassShaders.VertexShader.GetShader(), DepthPassShaders.PixelShader.GetShader());
BuildMeshDrawCommands(
MeshBatch,
BatchElementMask,
PrimitiveSceneProxy,
MaterialRenderProxy,
MaterialResource,
DrawRenderState,
DepthPassShaders,
MeshFillMode,
MeshCullMode,
SortKey,
bPositionOnly ? EMeshPassFeatures::PositionOnly : EMeshPassFeatures::Default,
ShaderElementData);
return true;
}
template<bool bPositionOnly>
void FDepthPassMeshProcessor::CollectPSOInitializersInternal(
const FSceneTexturesConfig& SceneTexturesConfig,
const FPSOPrecacheVertexFactoryData& VertexFactoryData,
const FMaterial& RESTRICT MaterialResource,
ERasterizerFillMode MeshFillMode,
ERasterizerCullMode MeshCullMode,
bool bDitheredLODTransition,
EPrimitiveType PrimitiveType,
TArray<FPSOPrecacheData>& PSOInitializers)
{
TMeshProcessorShaders<
TDepthOnlyVS<bPositionOnly>,
FDepthOnlyPS> DepthPassShaders;
FShaderPipelineRef ShaderPipeline;
if (!GetDepthPassShaders<bPositionOnly>(
MaterialResource,
VertexFactoryData.VertexFactoryType,
FeatureLevel,
MaterialResource.MaterialUsesPixelDepthOffset_GameThread(),
DepthPassShaders.VertexShader,
DepthPassShaders.PixelShader,
ShaderPipeline))
{
return;
}
FMeshPassProcessorRenderState DrawRenderState(PassDrawRenderState);
// If bDitheredLODTransition option is set, then swap to that depth stencil state (see logic in SetDepthPassDitheredLODTransitionState())
if (!bDitheredLODFadingOutMaskPass && !bShadowProjection && bDitheredLODTransition)
{
DrawRenderState.SetDepthStencilState(GetDitheredLODTransitionDepthStencilState());
}
FGraphicsPipelineRenderTargetsInfo RenderTargetsInfo;
RenderTargetsInfo.NumSamples = 1;
ETextureCreateFlags DepthStencilCreateFlags = SceneTexturesConfig.DepthCreateFlags;
SetupDepthStencilInfo(PF_DepthStencil, DepthStencilCreateFlags, ERenderTargetLoadAction::ELoad,
ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilWrite, RenderTargetsInfo);
AddGraphicsPipelineStateInitializer(
VertexFactoryData,
MaterialResource,
DrawRenderState,
RenderTargetsInfo,
DepthPassShaders,
MeshFillMode,
MeshCullMode,
PrimitiveType,
bPositionOnly ? EMeshPassFeatures::PositionOnly : EMeshPassFeatures::Default,
true /*bRequired*/,
PSOInitializers);
// Also cache with project shadow depth stencil state (see FProjectedShadowInfo::SetupMeshDrawCommandsForProjectionStenciling)
if (CVarPSOPrecacheProjectedShadows.GetValueOnAnyThread() > 0)
{
// Set stencil to one.
DrawRenderState.SetDepthStencilState(
TStaticDepthStencilState<
false, CF_DepthNearOrEqual,
true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
0xff, 0xff
>::GetRHI());
AddRenderTargetInfo(PF_B8G8R8A8, TexCreate_RenderTargetable | TexCreate_ShaderResource, RenderTargetsInfo);
AddGraphicsPipelineStateInitializer(
VertexFactoryData,
MaterialResource,
DrawRenderState,
RenderTargetsInfo,
DepthPassShaders,
MeshFillMode,
MeshCullMode,
PrimitiveType,
bPositionOnly ? EMeshPassFeatures::PositionOnly : EMeshPassFeatures::Default,
true /*bRequired*/,
PSOInitializers);
}
}
bool FDepthPassMeshProcessor::ShouldRender(const FMaterial& Material, bool bMaterialModifiesMeshPosition, bool bSupportPositionOnlyStream, bool bVFTypeSupportsNullPixelShader, bool& bUseDefaultMaterial, bool& bPositionOnly)
{
bool bShouldRender = false;
bUseDefaultMaterial = false;
bPositionOnly = false;
if (FeatureLevel == ERHIFeatureLevel::ES3_1 && EarlyZPassMode == DDM_None)
{
// Do not cache MDC and do not pre-cache PSOs for a depth pass if it's never going to be used on mobile platforms
return false;
}
if (IsOpaqueBlendMode(Material)
&& EarlyZPassMode != DDM_MaskedOnly
&& bSupportPositionOnlyStream
&& !bMaterialModifiesMeshPosition
&& Material.WritesEveryPixel(false, bVFTypeSupportsNullPixelShader))
{
bShouldRender = true;
bUseDefaultMaterial = true;
bPositionOnly = true;
}
else
{
// still possible to use default material
const bool bMaterialMasked = !Material.WritesEveryPixel(false, bVFTypeSupportsNullPixelShader) || Material.IsTranslucencyWritingCustomDepth();
if ((!bMaterialMasked && EarlyZPassMode != DDM_MaskedOnly) || (bMaterialMasked && EarlyZPassMode != DDM_NonMaskedOnly))
{
bShouldRender = true;
if (!bMaterialMasked && !bMaterialModifiesMeshPosition)
{
bUseDefaultMaterial = true;
bPositionOnly = false;
}
}
}
return bShouldRender;
}
bool FDepthPassMeshProcessor::TryAddMeshBatch(const FMeshBatch& RESTRICT MeshBatch, uint64 BatchElementMask, const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy, int32 StaticMeshId, const FMaterialRenderProxy& MaterialRenderProxy, const FMaterial& Material)
{
const bool bIsTranslucent = IsTranslucentBlendMode(Material);
bool ShouldRenderInDepthPass = (!PrimitiveSceneProxy || PrimitiveSceneProxy->ShouldRenderInDepthPass());
bool bResult = true;
if (!bIsTranslucent
&& ShouldRenderInDepthPass
&& ShouldIncludeDomainInMeshPass(Material.GetMaterialDomain())
&& ShouldIncludeMaterialInDefaultOpaquePass(Material))
{
const bool bSupportPositionOnlyStream = MeshBatch.VertexFactory->SupportsPositionOnlyStream();
const bool bVFTypeSupportsNullPixelShader = MeshBatch.VertexFactory->SupportsNullPixelShader();
const bool bModifiesMeshPosition = DoMaterialAndPrimitiveModifyMeshPosition(Material, PrimitiveSceneProxy);
bool bPositionOnly = false;
bool bUseDefaultMaterial = false;
if (ShouldRender(Material, bModifiesMeshPosition, bSupportPositionOnlyStream, bVFTypeSupportsNullPixelShader, bUseDefaultMaterial, bPositionOnly))
{
const FMaterialRenderProxy* EffectiveMaterialRenderProxy = &MaterialRenderProxy;
const FMaterial* EffectiveMaterial = &Material;
if (bUseDefaultMaterial)
{
// Override with the default material
EffectiveMaterialRenderProxy = UMaterial::GetDefaultMaterial(MD_Surface)->GetRenderProxy();
EffectiveMaterial = EffectiveMaterialRenderProxy->GetMaterialNoFallback(FeatureLevel);
check(EffectiveMaterial);
}
const FMeshDrawingPolicyOverrideSettings OverrideSettings = ComputeMeshOverrideSettings(MeshBatch);
const ERasterizerFillMode MeshFillMode = ComputeMeshFillMode(Material, OverrideSettings);
const ERasterizerCullMode MeshCullMode = ComputeMeshCullMode(Material, OverrideSettings);
if (bPositionOnly)
{
bResult = Process<true>(MeshBatch, BatchElementMask, StaticMeshId, PrimitiveSceneProxy, *EffectiveMaterialRenderProxy, *EffectiveMaterial, MeshFillMode, MeshCullMode);
}
else
{
bResult = Process<false>(MeshBatch, BatchElementMask, StaticMeshId, PrimitiveSceneProxy, *EffectiveMaterialRenderProxy, *EffectiveMaterial, MeshFillMode, MeshCullMode);
}
}
}
return bResult;
}
void FDepthPassMeshProcessor::AddMeshBatch(const FMeshBatch& RESTRICT MeshBatch, uint64 BatchElementMask, const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy, int32 StaticMeshId)
{
bool bDraw = MeshBatch.bUseForDepthPass;
// Filter by occluder flags and settings if required.
if (bDraw && bRespectUseAsOccluderFlag && !MeshBatch.bUseAsOccluder && EarlyZPassMode < DDM_AllOpaque)
{
if (PrimitiveSceneProxy)
{
// Only render primitives marked as occluders.
bDraw = PrimitiveSceneProxy->ShouldUseAsOccluder()
// Only render static objects unless movable are requested.
&& (!PrimitiveSceneProxy->IsMovable() || bEarlyZPassMovable);
// Filter dynamic mesh commands by screen size.
if (ViewIfDynamicMeshCommand)
{
extern float GMinScreenRadiusForDepthPrepass;
const float LODFactorDistanceSquared = (PrimitiveSceneProxy->GetBounds().Origin - ViewIfDynamicMeshCommand->ViewMatrices.GetViewOrigin()).SizeSquared() * FMath::Square(ViewIfDynamicMeshCommand->LODDistanceFactor);
bDraw = bDraw && FMath::Square(PrimitiveSceneProxy->GetBounds().SphereRadius) > GMinScreenRadiusForDepthPrepass * GMinScreenRadiusForDepthPrepass * LODFactorDistanceSquared;
}
}
else
{
bDraw = false;
}
}
// When using DDM_AllOpaqueNoVelocity we skip objects that will write depth+velocity in the subsequent velocity pass.
if (EarlyZPassMode == DDM_AllOpaqueNoVelocity && PrimitiveSceneProxy)
{
// We should ideally check to see if we this primitive is using the FOpaqueVelocityMeshProcessor or FTranslucentVelocityMeshProcessor.
// But for the object to get here, it would already be culled if it was translucent, so we can assume FOpaqueVelocityMeshProcessor.
// This logic needs to match the logic in FOpaqueVelocityMeshProcessor::AddMeshBatch()
// todo: Move that logic to a single place.
const EShaderPlatform ShaderPlatform = GetFeatureLevelShaderPlatform(FeatureLevel);
if (FOpaqueVelocityMeshProcessor::PrimitiveCanHaveVelocity(ShaderPlatform, PrimitiveSceneProxy))
{
if (ViewIfDynamicMeshCommand)
{
if (FOpaqueVelocityMeshProcessor::PrimitiveHasVelocityForFrame(PrimitiveSceneProxy))
{
checkSlow(ViewIfDynamicMeshCommand->bIsViewInfo);
FViewInfo* ViewInfo = (FViewInfo*)ViewIfDynamicMeshCommand;
if (FOpaqueVelocityMeshProcessor::PrimitiveHasVelocityForView(*ViewInfo, PrimitiveSceneProxy))
{
bDraw = false;
}
}
}
}
}
if (bDraw)
{
// Determine the mesh's material and blend mode.
const FMaterialRenderProxy* MaterialRenderProxy = MeshBatch.MaterialRenderProxy;
while (MaterialRenderProxy)
{
const FMaterial* Material = MaterialRenderProxy->GetMaterialNoFallback(FeatureLevel);
if (Material && Material->GetRenderingThreadShaderMap())
{
if (TryAddMeshBatch(MeshBatch, BatchElementMask, PrimitiveSceneProxy, StaticMeshId, *MaterialRenderProxy, *Material))
{
break;
}
}
MaterialRenderProxy = MaterialRenderProxy->GetFallback(FeatureLevel);
}
}
}
void FDepthPassMeshProcessor::CollectPSOInitializers(const FSceneTexturesConfig& SceneTexturesConfig, const FMaterial& Material, const FPSOPrecacheVertexFactoryData& VertexFactoryData, const FPSOPrecacheParams& PreCacheParams, TArray<FPSOPrecacheData>& PSOInitializers)
{
// Are we currently collecting PSO's for the default material
if (PreCacheParams.bDefaultMaterial)
{
CollectDefaultMaterialPSOInitializers(SceneTexturesConfig, Material, VertexFactoryData, PSOInitializers);
return;
}
// PSO precaching enabled for DitheredLODFadingOutMaskPass
if (MeshPassType == EMeshPass::DitheredLODFadingOutMaskPass && CVarPSOPrecacheDitheredLODFadingOutMaskPass.GetValueOnAnyThread() == 0)
{
return;
}
const bool bIsTranslucent = IsTranslucentBlendMode(Material);
// Early out if translucent or material shouldn't be used during this pass
if (bIsTranslucent ||
!PreCacheParams.bRenderInDepthPass ||
!ShouldIncludeDomainInMeshPass(Material.GetMaterialDomain()) ||
!ShouldIncludeMaterialInDefaultOpaquePass(Material))
{
return;
}
// assume we can always do this when collecting PSO's for now (vertex factory instance might actually not support it)
const bool bSupportPositionOnlyStream = VertexFactoryData.VertexFactoryType->SupportsPositionOnly();
const bool bVFTypeSupportsNullPixelShader = VertexFactoryData.VertexFactoryType->SupportsNullPixelShader();
bool bPositionOnly = false;
bool bUseDefaultMaterial = false;
if (ShouldRender(Material, Material.MaterialModifiesMeshPosition_GameThread(), bSupportPositionOnlyStream, bVFTypeSupportsNullPixelShader, bUseDefaultMaterial, bPositionOnly))
{
bool bCollectPSOs = !bUseDefaultMaterial;
// Collect PSOs for default material if there is a custom vertex declaration
const FMaterial* EffectiveMaterial = &Material;
if (bUseDefaultMaterial && !bSupportPositionOnlyStream && VertexFactoryData.CustomDefaultVertexDeclaration)
{
EMaterialQualityLevel::Type ActiveQualityLevel = GetCachedScalabilityCVars().MaterialQualityLevel;
EffectiveMaterial = UMaterial::GetDefaultMaterial(MD_Surface)->GetMaterialResource(FeatureLevel, ActiveQualityLevel);
bCollectPSOs = true;
}
if (bCollectPSOs)
{
check(!bPositionOnly);
const FMeshDrawingPolicyOverrideSettings OverrideSettings = ComputeMeshOverrideSettings(PreCacheParams);
const ERasterizerFillMode MeshFillMode = ComputeMeshFillMode(Material, OverrideSettings);
const ERasterizerCullMode MeshCullMode = ComputeMeshCullMode(Material, OverrideSettings);
bool bIsMoveable = PreCacheParams.IsMoveable();
const bool bAllowDitheredLODTransition = !bIsMoveable && Material.IsDitheredLODTransition();
bool bDitheredLODTransition = false;
CollectPSOInitializersInternal<false>(SceneTexturesConfig, VertexFactoryData, *EffectiveMaterial, MeshFillMode, MeshCullMode, bDitheredLODTransition, (EPrimitiveType)PreCacheParams.PrimitiveType, PSOInitializers);
if (bAllowDitheredLODTransition)
{
bDitheredLODTransition = true;
CollectPSOInitializersInternal<false>(SceneTexturesConfig, VertexFactoryData, *EffectiveMaterial, MeshFillMode, MeshCullMode, bDitheredLODTransition, (EPrimitiveType)PreCacheParams.PrimitiveType, PSOInitializers);
}
}
}
}
void FDepthPassMeshProcessor::CollectDefaultMaterialPSOInitializers(
const FSceneTexturesConfig& SceneTexturesConfig,
const FMaterial& Material,
const FPSOPrecacheVertexFactoryData& VertexFactoryData,
TArray<FPSOPrecacheData>& PSOInitializers)
{
const ERasterizerFillMode MeshFillMode = FM_Solid;
// Collect PSOs for all possible default material combinations
{
ERasterizerCullMode MeshCullMode = CM_None;
bool bDitheredLODTransition = false;
CollectPSOInitializersInternal<true>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
CollectPSOInitializersInternal<false>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
bDitheredLODTransition = true;
CollectPSOInitializersInternal<true>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
CollectPSOInitializersInternal<false>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
}
{
ERasterizerCullMode MeshCullMode = CM_CW;
bool bDitheredLODTransition = false;
CollectPSOInitializersInternal<true>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
CollectPSOInitializersInternal<false>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
bDitheredLODTransition = true;
CollectPSOInitializersInternal<true>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
CollectPSOInitializersInternal<false>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
}
{
ERasterizerCullMode MeshCullMode = CM_CCW;
bool bDitheredLODTransition = false;
CollectPSOInitializersInternal<true>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
CollectPSOInitializersInternal<false>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
bDitheredLODTransition = true;
CollectPSOInitializersInternal<true>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
CollectPSOInitializersInternal<false>(SceneTexturesConfig, VertexFactoryData, Material, MeshFillMode, MeshCullMode, bDitheredLODTransition, PT_TriangleList, PSOInitializers);
}
}
FDepthPassMeshProcessor::FDepthPassMeshProcessor(
EMeshPass::Type InMeshPassType,
const FScene* Scene,
ERHIFeatureLevel::Type FeatureLevel,
const FSceneView* InViewIfDynamicMeshCommand,
const FMeshPassProcessorRenderState& InPassDrawRenderState,
const bool InbRespectUseAsOccluderFlag,
const EDepthDrawingMode InEarlyZPassMode,
const bool InbEarlyZPassMovable,
const bool bDitheredLODFadingOutMaskPass,
FMeshPassDrawListContext* InDrawListContext,
const bool bInShadowProjection,
const bool bInSecondStageDepthPass)
: FMeshPassProcessor(InMeshPassType, Scene, FeatureLevel, InViewIfDynamicMeshCommand, InDrawListContext)
, bRespectUseAsOccluderFlag(InbRespectUseAsOccluderFlag)
, EarlyZPassMode(InEarlyZPassMode)
, bEarlyZPassMovable(InbEarlyZPassMovable)
, bDitheredLODFadingOutMaskPass(bDitheredLODFadingOutMaskPass)
, bShadowProjection(bInShadowProjection)
, bSecondStageDepthPass(bInSecondStageDepthPass)
{
PassDrawRenderState = InPassDrawRenderState;
}
FMeshPassProcessor* CreateDepthPassProcessor(ERHIFeatureLevel::Type FeatureLevel, const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
{
EDepthDrawingMode EarlyZPassMode;
bool bEarlyZPassMovable;
FScene::GetEarlyZPassMode(FeatureLevel, EarlyZPassMode, bEarlyZPassMovable);
FMeshPassProcessorRenderState DepthPassState;
SetupDepthPassState(DepthPassState);
return new FDepthPassMeshProcessor(EMeshPass::DepthPass, Scene, FeatureLevel, InViewIfDynamicMeshCommand, DepthPassState, true, EarlyZPassMode, bEarlyZPassMovable, false, InDrawListContext);
}
REGISTER_MESHPASSPROCESSOR_AND_PSOCOLLECTOR(DepthPass, CreateDepthPassProcessor, EShadingPath::Deferred, EMeshPass::DepthPass, EMeshPassFlags::CachedMeshCommands | EMeshPassFlags::MainView);
REGISTER_MESHPASSPROCESSOR_AND_PSOCOLLECTOR(MobileDepthPass, CreateDepthPassProcessor, EShadingPath::Mobile, EMeshPass::DepthPass, EMeshPassFlags::CachedMeshCommands | EMeshPassFlags::MainView);
FMeshPassProcessor* CreateSecondStageDepthPassProcessor(ERHIFeatureLevel::Type FeatureLevel, const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
{
EDepthDrawingMode EarlyZPassMode;
bool bEarlyZPassMovable;
FScene::GetEarlyZPassMode(FeatureLevel, EarlyZPassMode, bEarlyZPassMovable);
FMeshPassProcessorRenderState DepthPassState;
SetupDepthPassState(DepthPassState);
return new FDepthPassMeshProcessor(EMeshPass::SecondStageDepthPass, Scene, FeatureLevel, InViewIfDynamicMeshCommand, DepthPassState, true, EarlyZPassMode, bEarlyZPassMovable, false, InDrawListContext, false , true);
}
REGISTER_MESHPASSPROCESSOR_AND_PSOCOLLECTOR(SecondStageDepthPass, CreateSecondStageDepthPassProcessor, EShadingPath::Deferred, EMeshPass::SecondStageDepthPass, EMeshPassFlags::CachedMeshCommands | EMeshPassFlags::MainView);
//Secondary depth pass is not implemented on mobile so far (see SceneVisibility.cpp)
//FRegisterPassProcessorCreateFunction RegisterMobileDepthPass(&CreateSecondStageDepthPassProcessor, EShadingPath::Mobile, EMeshPass::SecondStageDepthPass, EMeshPassFlags::CachedMeshCommands | EMeshPassFlags::MainView);
FMeshPassProcessor* CreateDitheredLODFadingOutMaskPassProcessor(ERHIFeatureLevel::Type FeatureLevel, const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
{
EDepthDrawingMode EarlyZPassMode;
bool bEarlyZPassMovable;
FScene::GetEarlyZPassMode(FeatureLevel, EarlyZPassMode, bEarlyZPassMovable);
FMeshPassProcessorRenderState DrawRenderState;
DrawRenderState.SetBlendState(TStaticBlendState<CW_NONE>::GetRHI());
DrawRenderState.SetDepthStencilState(
TStaticDepthStencilState<true, CF_Equal,
true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
STENCIL_SANDBOX_MASK, STENCIL_SANDBOX_MASK
>::GetRHI());
DrawRenderState.SetStencilRef(STENCIL_SANDBOX_MASK);
return new FDepthPassMeshProcessor(EMeshPass::DitheredLODFadingOutMaskPass, Scene, FeatureLevel, InViewIfDynamicMeshCommand, DrawRenderState, true, EarlyZPassMode, bEarlyZPassMovable, true, InDrawListContext);
}
REGISTER_MESHPASSPROCESSOR_AND_PSOCOLLECTOR(DitheredLODFadingOutMaskPass, CreateDitheredLODFadingOutMaskPassProcessor, EShadingPath::Deferred, EMeshPass::DitheredLODFadingOutMaskPass, EMeshPassFlags::MainView);