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

317 lines
13 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "PostProcess/PostProcessCompositePrimitivesCommon.h"
#if UE_ENABLE_DEBUG_DRAWING
#include "BasePassRendering.h"
#include "PixelShaderUtils.h"
#include "ScenePrivate.h"
#define MIN_DEPTHTEX_UPSCALE_FACTOR 1
#define MAX_DEPTHTEX_UPSCALE_FACTOR 4
TAutoConsoleVariable<int32> CVarCompositeTemporalUpsampleDepth(
TEXT("r.Composite.TemporalUpsampleDepth"), 2,
TEXT("Temporal upsample factor of the depth buffer for depth testing editor primitives against."),
ECVF_RenderThreadSafe);
const FViewInfo* CreateCompositePrimitiveView(const FViewInfo& ParentView, FIntRect ViewRect, uint32 NumMSAASamples)
{
FViewInfo* View = ParentView.CreateSnapshot();
// Patch view rect.
View->ViewRect = ViewRect;
// Override pre exposure to 1.0f, because rendering after tonemapper.
View->PreExposure = 1.0f;
// Kills material texture mipbias because after TAA.
View->MaterialTextureMipBias = 0.0f;
if (IsTemporalAccumulationBasedMethod(View->AntiAliasingMethod))
{
View->ViewMatrices.HackRemoveTemporalAAProjectionJitter();
}
View->InitRHIResources(NumMSAASamples);
return View;
}
FRDGTextureRef CreateCompositeDepthTexture(FRDGBuilder& GraphBuilder, FIntPoint Extent, uint32 NumMSAASamples)
{
const FRDGTextureDesc DepthDesc = FRDGTextureDesc::Create2D(
Extent,
PF_DepthStencil,
FClearValueBinding::DepthFar,
TexCreate_ShaderResource | TexCreate_DepthStencilTargetable,
1,
NumMSAASamples);
return GraphBuilder.CreateTexture(DepthDesc, TEXT("Composite.PrimitivesDepth"));
}
class FTemporalUpsampleDepthPS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FTemporalUpsampleDepthPS);
SHADER_USE_PARAMETER_STRUCT(FTemporalUpsampleDepthPS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, Depth)
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, PrevHistory)
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, History)
SHADER_PARAMETER(FVector2f, DepthTextureJitter)
SHADER_PARAMETER(int32, bCameraCut)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, DepthTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, DepthSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, VelocityTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, VelocitySampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, PrevHistoryTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, PrevHistorySampler)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
/**
* Compile for all platforms that support TAA minimum.
* Runtime only executes if a temporal upscale method is enabled.
*/
return SupportsGen4TAA(Parameters.Platform);
}
static const EPixelFormat OutputFormat = PF_R32_FLOAT;
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& InParameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(InParameters, OutEnvironment);
/*Explicitly match PS render target output format to the desc of the texture.*/
OutEnvironment.SetRenderTargetOutputFormat(0, OutputFormat);
}
};
class FPopulateCompositeDepthPS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FPopulateCompositeDepthPS);
SHADER_USE_PARAMETER_STRUCT(FPopulateCompositeDepthPS, FGlobalShader);
class FUseMSAADimension : SHADER_PERMUTATION_BOOL("USE_MSAA");
class FForceDebugDrawColorOutput : SHADER_PERMUTATION_BOOL("FORCE_DEBUG_DRAW_COLOR"); //Allow the option to draw out the scene color too to lower draw calls
class FUseMetalMSAAHDRDecodeDim : SHADER_PERMUTATION_BOOL("METAL_MSAA_HDR_DECODE");
using FPermutationDomain = TShaderPermutationDomain<FUseMSAADimension, FForceDebugDrawColorOutput, FUseMetalMSAAHDRDecodeDim>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, Color)
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, Depth)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, ColorTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, ColorSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, DepthTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, DepthSampler)
SHADER_PARAMETER(FVector2f, DepthTextureJitter)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& InParameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(InParameters, OutEnvironment);
FPermutationDomain PermutationVector(InParameters.PermutationId);
if (PermutationVector.Get<FForceDebugDrawColorOutput>() != 0)
{
OutEnvironment.SetDefine(TEXT("MIN_DEPTHTEX_UPSCALE_FACTOR"), MIN_DEPTHTEX_UPSCALE_FACTOR);
OutEnvironment.SetDefine(TEXT("MAX_DEPTHTEX_UPSCALE_FACTOR"), MAX_DEPTHTEX_UPSCALE_FACTOR);
}
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
const FPermutationDomain PermutationVector(Parameters.PermutationId);
const bool bUseMSAA = PermutationVector.Get<FUseMSAADimension>();
const bool bUseMetalMSAAHDRDecodeDim = PermutationVector.Get<FUseMetalMSAAHDRDecodeDim>();
if (bUseMSAA)
{
// Only SM5+ and Metal ES3.1 platforms support MSAA.
if (IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5))
{
return true;
}
else if (IsMetalMobilePlatform(Parameters.Platform) && bUseMetalMSAAHDRDecodeDim)
{
//Only compile with decode dim if using metal platform on 3.1 + color output
return PermutationVector.Get<FForceDebugDrawColorOutput>();
}
}
else
{
//Never compile Metal decode dim permutations for non-MSAA passes
return !bUseMetalMSAAHDRDecodeDim;
}
return false;
}
};
IMPLEMENT_GLOBAL_SHADER(FTemporalUpsampleDepthPS, "/Engine/Private/PostProcessCompositePrimitives.usf", "MainTemporalUpsampleDepthPS", SF_Pixel);
IMPLEMENT_GLOBAL_SHADER(FPopulateCompositeDepthPS, "/Engine/Private/PostProcessCompositePrimitives.usf", "MainPopulateSceneDepthPS", SF_Pixel);
void TemporalUpscaleDepthPass(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FScreenPassTexture& InSceneColor,
FScreenPassTexture& InOutSceneDepth,
FVector2f& SceneDepthJitter)
{
if (InSceneColor.ViewRect != InOutSceneDepth.ViewRect)
{
FIntPoint Extent = InSceneColor.Texture->Desc.Extent;
FIntRect ViewRect = InSceneColor.ViewRect;
// Upscale factor of the depth buffer that might be needed.
const float UpscaleFactor = float(View.ViewRect.Width()) / float(InOutSceneDepth.ViewRect.Width());
// Upscale factor shouldn't be higher than there is TAA samples, or that means there will be unrendered pixels.
const int32 ComputeMaxUpsampleFactorDueToTAA = FMath::FloorToInt(FMath::Sqrt(float(View.TemporalJitterSequenceLength) / (UpscaleFactor * UpscaleFactor)));
const int32 MaxRHIUpsampleFactor = FMath::Clamp(FMath::FloorToInt(float(GetMax2DTextureDimension()) / float(Extent.GetMax())), MIN_DEPTHTEX_UPSCALE_FACTOR, MAX_DEPTHTEX_UPSCALE_FACTOR);
const int32 ComputeMaxUpsampleFactor = FMath::Clamp(ComputeMaxUpsampleFactorDueToTAA, 0, MaxRHIUpsampleFactor);
const int32 DepthUpsampleFactor = FMath::Clamp(CVarCompositeTemporalUpsampleDepth.GetValueOnRenderThread(), 0, ComputeMaxUpsampleFactor);
// Upsample the depth at higher resolution to reduce depth intersection instability of editor primitives.
if (DepthUpsampleFactor > 0 && View.ViewState && IsTemporalAccumulationBasedMethod(View.AntiAliasingMethod))
{
FScreenPassTexture History;
const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(
Extent * DepthUpsampleFactor,
FTemporalUpsampleDepthPS::OutputFormat /* PF_R32_FLOAT */,
FClearValueBinding::None,
TexCreate_ShaderResource | TexCreate_RenderTargetable);
History.Texture = GraphBuilder.CreateTexture(Desc, TEXT("Composite.PrimitivesDepthHistory"));
History.ViewRect = ViewRect * DepthUpsampleFactor;
FTemporalUpsampleDepthPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FTemporalUpsampleDepthPS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
PassParameters->Depth = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(InOutSceneDepth));
PassParameters->History = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(History));
PassParameters->DepthTextureJitter = SceneDepthJitter;
PassParameters->DepthTexture = InOutSceneDepth.Texture;
PassParameters->DepthSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
// TODO
PassParameters->VelocityTexture = GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackDummy);
PassParameters->VelocitySampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
if (View.PrevViewInfo.CompositePrimitiveDepthHistory.IsValid())
{
PassParameters->PrevHistory = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(
View.PrevViewInfo.CompositePrimitiveDepthHistory.RT[0]->GetDesc().Extent, View.PrevViewInfo.CompositePrimitiveDepthHistory.ViewportRect));
PassParameters->PrevHistoryTexture = GraphBuilder.RegisterExternalTexture(View.PrevViewInfo.CompositePrimitiveDepthHistory.RT[0]);
PassParameters->PrevHistorySampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
PassParameters->bCameraCut = false;
}
else
{
PassParameters->PrevHistory = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(
FIntPoint(1, 1), FIntRect(FIntPoint(0, 0), FIntPoint(1, 1))));
PassParameters->PrevHistoryTexture = GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackDummy);
PassParameters->PrevHistorySampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
PassParameters->bCameraCut = true;
}
PassParameters->RenderTargets[0] = FRenderTargetBinding(History.Texture, ERenderTargetLoadAction::ENoAction);
TShaderMapRef<FTemporalUpsampleDepthPS> PixelShader(View.ShaderMap);
FPixelShaderUtils::AddFullscreenPass(
GraphBuilder,
View.ShaderMap,
RDG_EVENT_NAME("TemporalUpsampleDepth %dx%d -> %dx%d",
InOutSceneDepth.ViewRect.Width(),
InOutSceneDepth.ViewRect.Height(),
History.ViewRect.Width(),
History.ViewRect.Height()),
PixelShader,
PassParameters,
History.ViewRect);
if (!View.bStatePrevViewInfoIsReadOnly)
{
FTemporalAAHistory* OutputHistory = &View.ViewState->PrevFrameViewInfo.CompositePrimitiveDepthHistory;
OutputHistory->SafeRelease();
GraphBuilder.QueueTextureExtraction(History.Texture, &OutputHistory->RT[0]);
OutputHistory->ViewportRect = History.ViewRect;
OutputHistory->ReferenceBufferSize = History.Texture->Desc.Extent;
}
InOutSceneDepth = History;
SceneDepthJitter = FVector2f::ZeroVector;
}
}
}
// Populate the MSAA depth buffer from depth buffer or temporally upscaled depth buffer
void PopulateDepthPass(FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FScreenPassTexture& InSceneColor,
const FScreenPassTexture& InSceneDepth,
FRDGTextureRef OutPopColor,
FRDGTextureRef OutPopDepth,
const FVector2f& SceneDepthJitter,
uint32 NumMSAASamples,
bool bForceDrawColor,
bool bUseMetalPlatformHDRDecode)
{
FRHISamplerState* PointClampSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
FPopulateCompositeDepthPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FPopulateCompositeDepthPS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
if (bForceDrawColor)
{
PassParameters->ColorTexture = InSceneColor.Texture;
PassParameters->ColorSampler = PointClampSampler;
}
PassParameters->Color = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(InSceneColor));
PassParameters->Depth = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(InSceneDepth));
PassParameters->DepthTexture = InSceneDepth.Texture;
PassParameters->DepthSampler = PointClampSampler;
PassParameters->DepthTextureJitter = SceneDepthJitter;
const ERenderTargetLoadAction ColorLoadAction = View.IsPrimarySceneView() ? ERenderTargetLoadAction::ENoAction : ERenderTargetLoadAction::ELoad;
PassParameters->RenderTargets[0] = FRenderTargetBinding(OutPopColor, ColorLoadAction);
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(OutPopDepth, ERenderTargetLoadAction::EClear, ERenderTargetLoadAction::EClear, FExclusiveDepthStencil::DepthWrite_StencilWrite);
FPopulateCompositeDepthPS::FPermutationDomain PermutationVector;
PermutationVector.Set<FPopulateCompositeDepthPS::FUseMSAADimension>(NumMSAASamples > 1);
PermutationVector.Set< FPopulateCompositeDepthPS::FForceDebugDrawColorOutput>(bForceDrawColor);
PermutationVector.Set< FPopulateCompositeDepthPS::FUseMetalMSAAHDRDecodeDim>(bForceDrawColor && bUseMetalPlatformHDRDecode);
TShaderMapRef<FPopulateCompositeDepthPS> PixelShader(View.ShaderMap, PermutationVector);
FPixelShaderUtils::AddFullscreenPass(
GraphBuilder,
View.ShaderMap,
RDG_EVENT_NAME("PopulateDepth %dx%d%s",
View.ViewRect.Width(),
View.ViewRect.Height(),
NumMSAASamples > 1 ? TEXT(" MSAA") : TEXT("")),
PixelShader,
PassParameters,
View.ViewRect,
/* BlendState = */ nullptr,
/* RasterizerState = */ nullptr,
TStaticDepthStencilState<true, CF_Always>::GetRHI());
}
#endif //UE_ENABLE_DEBUG_DRAWING