Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCompositeDebugPrimitives.cpp
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

338 lines
15 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "PostProcess/PostProcessCompositeDebugPrimitives.h"
#if UE_ENABLE_DEBUG_DRAWING
#include "ScenePrivate.h"
#include "PixelShaderUtils.h"
#include "PostProcess/PostProcessing.h"
#include "InstanceCulling/InstanceCullingOcclusionQuery.h"
#include "VirtualShadowMaps/VirtualShadowMapArray.h"
BEGIN_SHADER_PARAMETER_STRUCT(FDebugPrimitivesPassParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
struct FDebugPrimitivesDrawingContext
{
const FViewInfo* DebugView = nullptr;
FRDGTextureRef DebugPrimitiveColor = nullptr;
FRDGTextureRef DebugPrimitiveDepth = nullptr;
FRDGTextureRef UpscaledSceneDepth = nullptr;
FScreenPassTexture SceneColor {};
FScreenPassTexture SceneDepth {};
FScreenPassRenderTarget OutputRT {};
FScreenPassRenderTarget OutputDepthRT {};
};
static FDebugPrimitivesDrawingContext InitializeDebugPrimitiveTextures(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FCompositePrimitiveInputs& Inputs,
const FScreenPassRenderTarget& Output)
{
// Setup view
const FIntRect ViewRect = Output.ViewRect;
FIntPoint OutputExtent = Output.Texture->Desc.Extent;
FIntPoint SceneColorExtent = Inputs.SceneColor.Texture->Desc.Extent;
FViewFamilyInfo* ViewFamily = (FViewFamilyInfo*)View.Family;
int NumMSAASamples = 1;
#if WITH_EDITOR
NumMSAASamples = ViewFamily->SceneTexturesConfig.EditorPrimitiveNumSamples;
#endif
const FViewInfo* DebugView = CreateCompositePrimitiveView(View, ViewRect, NumMSAASamples);
// Setup textures
const FRDGTextureDesc ColorDesc(FRDGTextureDesc::Create2D(OutputExtent, PF_B8G8R8A8, FClearValueBinding::Transparent, TexCreate_ShaderResource | TexCreate_RenderTargetable, 1, NumMSAASamples));
FRDGTextureRef DebugPrimitiveColor = GraphBuilder.CreateTexture(ColorDesc, TEXT("Debug.PrimitivesColor"));
const FRDGTextureDesc DepthDesc(FRDGTextureDesc::Create2D(OutputExtent, PF_DepthStencil, FClearValueBinding::DepthFar, TexCreate_ShaderResource | TexCreate_DepthStencilTargetable, 1, NumMSAASamples));
FRDGTextureRef DebugPrimitiveDepth = GraphBuilder.CreateTexture(DepthDesc, TEXT("Debug.PrimitivesDepth"));
AddClearRenderTargetPass(GraphBuilder, DebugPrimitiveColor);
AddClearDepthStencilPass(GraphBuilder, DebugPrimitiveDepth);
const FRDGTextureDesc UpscaledSceneDepthDesc(FRDGTextureDesc::Create2D(SceneColorExtent, PF_DepthStencil, FClearValueBinding::DepthFar, TexCreate_ShaderResource | TexCreate_DepthStencilTargetable, 1, Inputs.SceneColor.Texture->Desc.NumSamples));
FRDGTextureRef UpscaledSceneDepth = GraphBuilder.CreateTexture(UpscaledSceneDepthDesc, TEXT("Debug.UpscaledWorldDepth"));
// Debug primitives with SDPG_World are depth tested against the scene depth, and immediately composed on SceneColor.
// SceneDepth is upscaled, to match the size of post-TSR SceneColor.
// Other debug primitives are only depth tested amongst themselves, and drawn to PrimitivesColor/PrimitivesDepth.
// Finally, PrimitivesColor is drawn to SceneColor, with occluded lines (tested against SceneDepth) drawn in a dithered style.
{
FScreenPassTexture UpsampledDepth = Inputs.SceneDepth;
FVector2f SceneDepthJitter = FVector2f(View.TemporalJitterPixels);
if (IsTemporalAccumulationBasedMethod(View.AntiAliasingMethod))
{
TemporalUpscaleDepthPass(GraphBuilder,
*DebugView,
Inputs.SceneColor,
UpsampledDepth,
SceneDepthJitter);
}
//Simple element pixel shaders do not output background color for composite,
//so this allows the background to be drawn to the RT at the same time as depth without adding extra draw calls
PopulateDepthPass(GraphBuilder,
*DebugView,
Inputs.SceneColor,
UpsampledDepth,
nullptr,
UpscaledSceneDepth,
SceneDepthJitter,
UpscaledSceneDepth->Desc.NumSamples,
false,
Inputs.bUseMetalMSAAHDRDecode);
}
FDebugPrimitivesDrawingContext Result {};
Result.DebugView = DebugView;
Result.DebugPrimitiveColor = DebugPrimitiveColor;
Result.DebugPrimitiveDepth = DebugPrimitiveDepth;
Result.UpscaledSceneDepth = UpscaledSceneDepth;
Result.SceneColor = Inputs.SceneColor;
Result.SceneDepth = Inputs.SceneDepth;
Result.OutputRT = Output;
Result.OutputDepthRT = Inputs.OverrideDepthOutput;
return Result;
}
static bool DrawDebugPDE(
FRDGBuilder& GraphBuilder,
FDebugPrimitivesDrawingContext& Context,
const FScreenPassTextureViewport& OutputViewport)
{
if (!Context.DebugView->DebugSimpleElementCollector.HasAnyPrimitives())
{
return false;
}
// Draw SDPG_World elements, depth tested with SceneColor
if (Context.DebugView->DebugSimpleElementCollector.HasPrimitives(SDPG_World))
{
FDebugPrimitivesPassParameters* PassParameters = GraphBuilder.AllocParameters<FDebugPrimitivesPassParameters>();
PassParameters->View = Context.DebugView->GetShaderParameters();
PassParameters->RenderTargets[0] = FRenderTargetBinding(Context.SceneColor.Texture, ERenderTargetLoadAction::ELoad);
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(Context.UpscaledSceneDepth, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilWrite);
GraphBuilder.AddPass(
RDG_EVENT_NAME("DrawDebugPrimitives(SDPG_World)"),
PassParameters,
ERDGPassFlags::Raster,
[PassParameters, DebugView=Context.DebugView, OutputViewport](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
RHICmdList.SetViewport(OutputViewport.Rect.Min.X, OutputViewport.Rect.Min.Y, 0.0f, OutputViewport.Rect.Max.X, OutputViewport.Rect.Max.Y, 1.0f);
FMeshPassProcessorRenderState DrawRenderState;
DrawRenderState.SetDepthStencilAccess(FExclusiveDepthStencil::DepthWrite_StencilWrite);
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One>::GetRHI());
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<true, CF_DepthNearOrEqual>::GetRHI());
DebugView->DebugSimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, *DebugView, EBlendModeFilter::OpaqueAndMasked, SDPG_World);
});
}
// Draw SDPG_Foreground elements, depth tested only with other debug primitives
if (Context.DebugView->DebugSimpleElementCollector.HasPrimitives(SDPG_Foreground))
{
FDebugPrimitivesPassParameters* PassParameters = GraphBuilder.AllocParameters<FDebugPrimitivesPassParameters>();
PassParameters->View = Context.DebugView->GetShaderParameters();
PassParameters->RenderTargets[0] = FRenderTargetBinding(Context.DebugPrimitiveColor, ERenderTargetLoadAction::EClear);
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(Context.DebugPrimitiveDepth, ERenderTargetLoadAction::EClear, ERenderTargetLoadAction::EClear, FExclusiveDepthStencil::DepthWrite_StencilWrite);
GraphBuilder.AddPass(
RDG_EVENT_NAME("DrawDebugPrimitives(SDPG_Foreground)"),
PassParameters,
ERDGPassFlags::Raster,
[PassParameters, DebugView=Context.DebugView, OutputViewport](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
RHICmdList.SetViewport(OutputViewport.Rect.Min.X, OutputViewport.Rect.Min.Y, 0.0f, OutputViewport.Rect.Max.X, OutputViewport.Rect.Max.Y, 1.0f);
FMeshPassProcessorRenderState DrawRenderState;
DrawRenderState.SetDepthStencilAccess(FExclusiveDepthStencil::DepthWrite_StencilWrite);
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One>::GetRHI());
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<true, CF_Always>::GetRHI());
DebugView->DebugSimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, *DebugView, EBlendModeFilter::OpaqueAndMasked, SDPG_Foreground);
});
}
return true;
}
static void ComposeDebugPrimitives(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FCompositePrimitiveInputs& Inputs,
FDebugPrimitivesDrawingContext& Context)
{
const FScreenPassRenderTarget& DepthOutput = Context.OutputDepthRT;
int NumMSAASamples = Context.DebugPrimitiveColor->Desc.NumSamples;
const FScreenPassTexture& SceneDepth = Context.SceneDepth;
FVector2f SceneDepthJitter = FVector2f(View.TemporalJitterPixels);
const FScreenPassTextureViewport DebugPrimitivesViewport(Context.DebugPrimitiveColor, Context.DebugView->ViewRect);
bool bCompositeAnyNonNullDepth = false;
FRHISamplerState* PointClampSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
const bool bOpaqueEditorGizmo = View.Family->EngineShowFlags.OpaqueCompositeEditorPrimitives || View.Family->EngineShowFlags.Wireframe;
FCompositePostProcessPrimitivesPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FCompositePostProcessPrimitivesPS::FParameters>();
PassParameters->RenderTargets[0] = Context.OutputRT.GetRenderTargetBinding();
bool bOutputIsMSAA = Context.OutputRT.Texture->Desc.NumSamples > 1;
if (DepthOutput.IsValid())
{
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(DepthOutput.Texture, ERenderTargetLoadAction::EClear, ERenderTargetLoadAction::ENoAction, FExclusiveDepthStencil::DepthWrite);
verify(Context.OutputRT.Texture->Desc.NumSamples == DepthOutput.Texture->Desc.NumSamples);
}
PassParameters->View = View.ViewUniformBuffer;
PassParameters->Color = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(Context.SceneColor));
PassParameters->Depth = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(SceneDepth));
PassParameters->EditorPrimitives = GetScreenPassTextureViewportParameters(DebugPrimitivesViewport);
PassParameters->UndistortingDisplacementTexture = GSystemTextures.GetBlackDummy(GraphBuilder);
PassParameters->UndistortingDisplacementSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
if (Inputs.LensDistortionLUT.IsEnabled())
{
PassParameters->UndistortingDisplacementTexture = Inputs.LensDistortionLUT.UndistortingDisplacementTexture;
}
PassParameters->ColorTexture = Context.SceneColor.Texture;
PassParameters->ColorSampler = PointClampSampler;
PassParameters->DepthTexture = SceneDepth.Texture;
PassParameters->DepthSampler = PointClampSampler;
PassParameters->EditorPrimitivesDepth = Context.DebugPrimitiveDepth;
PassParameters->EditorPrimitivesColor = Context.DebugPrimitiveColor;
PassParameters->PassSvPositionToViewportUV = FScreenTransform::SvPositionToViewportUV(Context.OutputRT.ViewRect);
PassParameters->ViewportUVToColorUV = FScreenTransform::ChangeTextureBasisFromTo(
FScreenPassTextureViewport(Context.SceneColor), FScreenTransform::ETextureBasis::ViewportUV, FScreenTransform::ETextureBasis::TextureUV);
PassParameters->ViewportUVToDepthUV = FScreenTransform::ChangeTextureBasisFromTo(
FScreenPassTextureViewport(SceneDepth), FScreenTransform::ETextureBasis::ViewportUV, FScreenTransform::ETextureBasis::TextureUV);
PassParameters->ViewportUVToEditorPrimitivesUV = FScreenTransform::ChangeTextureBasisFromTo(
DebugPrimitivesViewport, FScreenTransform::ETextureBasis::ViewportUV, FScreenTransform::ETextureBasis::TextureUV);
PassParameters->bOpaqueEditorGizmo = bOpaqueEditorGizmo;
PassParameters->bCompositeAnyNonNullDepth = bCompositeAnyNonNullDepth;
PassParameters->DepthTextureJitter = SceneDepthJitter;
PassParameters->bProcessAlpha = IsPostProcessingWithAlphaChannelSupported();
PassParameters->OccludedDithering = 0.0f;
PassParameters->OccludedBrightness = 1.0f;
for (int32 i = 0; i < int32(NumMSAASamples); i++)
{
PassParameters->SampleOffsetArray[i].X = GetMSAASampleOffsets(NumMSAASamples, i).X;
PassParameters->SampleOffsetArray[i].Y = GetMSAASampleOffsets(NumMSAASamples, i).Y;
}
FCompositePostProcessPrimitivesPS::FPermutationDomain PermutationVector;
PermutationVector.Set<FCompositePostProcessPrimitivesPS::FSampleCountDimension>(NumMSAASamples);
PermutationVector.Set<FCompositePostProcessPrimitivesPS::FMSAADontResolve>(bOutputIsMSAA);
PermutationVector.Set<FCompositePostProcessPrimitivesPS::FWriteDepth>(DepthOutput.IsValid());
TShaderMapRef<FCompositePostProcessPrimitivesPS> PixelShader(View.ShaderMap, PermutationVector);
FRHIDepthStencilState* DepthStencilState = nullptr;
if (DepthOutput.IsValid())
{
DepthStencilState = TStaticDepthStencilState<true, CF_Always>::GetRHI();
}
FPixelShaderUtils::AddFullscreenPass(
GraphBuilder,
View.ShaderMap,
RDG_EVENT_NAME("Composite %dx%d MSAA=%d", Context.OutputRT.ViewRect.Width(), Context.OutputRT.ViewRect.Height(), NumMSAASamples),
PixelShader,
PassParameters,
Context.OutputRT.ViewRect,
nullptr,
nullptr,
DepthStencilState);
}
FScreenPassTexture AddDebugPrimitivePass(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
int32 ViewIndex,
FSceneUniformBuffer& SceneUniformBuffer,
FVirtualShadowMapArray* VirtualShadowMapArray,
const FCompositePrimitiveInputs& Inputs)
{
check(Inputs.SceneColor.IsValid());
check(Inputs.SceneDepth.IsValid());
RDG_EVENT_SCOPE(GraphBuilder, "CompositeDebugPrimitives");
FScreenPassRenderTarget Output = Inputs.OverrideOutput;
if (!Output.IsValid())
{
Output = FScreenPassRenderTarget::CreateFromInput(GraphBuilder, Inputs.SceneColor, View.GetOverwriteLoadAction(), TEXT("Debug.DrawPrimitivesColor"));
}
const FScreenPassTextureViewport OutputViewport(Output);
FDebugPrimitivesDrawingContext Context = InitializeDebugPrimitiveTextures(GraphBuilder, View, Inputs, Output);
bool bHasDrawn = DrawDebugPDE(GraphBuilder, Context, OutputViewport);
{
const EDebugViewShaderMode DebugViewMode = View.Family->GetDebugViewShaderMode();
FScene* Scene = (FScene*)View.Family->Scene;
if (View.Family->EngineShowFlags.VisualizeInstanceOcclusionQueries && Scene && Scene->InstanceCullingOcclusionQueryRenderer)
{
Scene->InstanceCullingOcclusionQueryRenderer->RenderDebug(GraphBuilder, Scene->GPUScene, *Context.DebugView, OutputViewport.Rect, Context.DebugPrimitiveColor, Context.DebugPrimitiveDepth);
bHasDrawn = true;
}
if (VirtualShadowMapArray && DebugViewMode == DVSM_ShadowCasters)
{
#if VSM_ENABLE_VISUALIZATION
VirtualShadowMapArray->RenderShadowCasterBounds(GraphBuilder, *Context.DebugView, ViewIndex, SceneUniformBuffer, OutputViewport.Rect, Context.DebugPrimitiveColor, Context.DebugPrimitiveDepth, Context.UpscaledSceneDepth);
bHasDrawn = true;
#endif
}
}
if (bHasDrawn)
{
ComposeDebugPrimitives(GraphBuilder, View, Inputs, Context);
}
else
{
AddDrawTexturePass(GraphBuilder, View, Inputs.SceneColor, Output);
}
return MoveTemp(Output);
}
#endif // UE_ENABLE_DEBUG_DRAWING
bool IsDebugPrimitivePassEnabled(const FViewInfo& View)
{
#if UE_ENABLE_DEBUG_DRAWING
static bool bIsForceDisabled = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ForceDebugViewModes"))->GetValueOnAnyThread() == 2;
if (bIsForceDisabled || !View.Family->EngineShowFlags.CompositeDebugPrimitives)
{
return false;
}
bool bHasDebugPDEPrimitives = View.DebugSimpleElementCollector.HasAnyPrimitives();
bool bVisualizeInstanceOcclusionCulling = View.Family->EngineShowFlags.VisualizeInstanceOcclusionQueries;
bool bVisualizeShadowCasters = View.Family->EngineShowFlags.VisualizeShadowCasters;
return bHasDebugPDEPrimitives || bVisualizeInstanceOcclusionCulling || bVisualizeShadowCasters;
#else
return false;
#endif
}