Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingPost.cpp
jason hoerner d15b1426d0 Scene Capture Cube: fix for severe artifacts in volumetric cloud rendering, and possibly other artifacts. The artifacts are caused by the temporal volumetric cloud effect not having a separate history per cube map face.
* Each cube map face gets its own FSceneViewState.  The downside is that it potentially could add a lot of extra memory.  So some memory optimizations were made to compensate.
* Global distance field data is shared for all cube map faces.  This data is only dependent on the view origin, which is invariant for the cube map faces.  A mechanism was added to allow cross view state data sharing for shared origin views.  This saves 8.5 MB, and improves perf.
* Disabled distance field lighting temporal AO for cube map capture.  The AO history texture in the view state is dependent on the Scene texture extents, which is typically the front buffer size, which then gets multiplied by 6.  For a 1080p front buffer, this is 24 MB, while for a 4K front buffer, this is 96 MB, regardless of the resolution of the cube map capture itself.  A 256x256 cube map capture, including all the auxiliary state, is otherwise only around 9 MB, so this is an order of magnitude increase.  A comment in the function "DistanceFieldAOUseHistory" has more details on how this could be fixed, by using the view rect rather than Scene texture extents for the history texture -- for the 256x256 case, it would reduce the incremental memory cost to 768K.

With the memory savings from disabling distance field lighting temporal AO, this change is more or less memory neutral if the Scene texture extent (front buffer) is 1080p.  A net increase of 590K.  With a higher resolution front buffer, it's a subsantial memory win.

#jira UE-151717
#rnx
#rb tiago.costa daniel.wright
#preflight 629f6a27233ae0a8f8f99932

[CL 20614815 by jason hoerner in ue5-main branch]
2022-06-11 19:06:03 -04:00

645 lines
32 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
DistanceFieldLightingPost.cpp
=============================================================================*/
#include "DistanceFieldLightingPost.h"
#include "PostProcess/PostProcessing.h"
#include "PostProcess/SceneFilterRendering.h"
#include "DistanceFieldLightingShared.h"
#include "DistanceFieldAmbientOcclusion.h"
#include "CompositionLighting/PostProcessAmbientOcclusion.h"
#include "PipelineStateCache.h"
#if WITH_MGPU
DECLARE_GPU_STAT(AFRWaitForDistanceFieldAOHistory);
#endif
int32 GAOUseHistory = 1;
FAutoConsoleVariableRef CVarAOUseHistory(
TEXT("r.AOUseHistory"),
GAOUseHistory,
TEXT("Whether to apply a temporal filter to the distance field AO, which reduces flickering but also adds trails when occluders are moving."),
ECVF_RenderThreadSafe
);
int32 GAOClearHistory = 0;
FAutoConsoleVariableRef CVarAOClearHistory(
TEXT("r.AOClearHistory"),
GAOClearHistory,
TEXT(""),
ECVF_RenderThreadSafe
);
int32 GAOHistoryStabilityPass = 1;
FAutoConsoleVariableRef CVarAOHistoryStabilityPass(
TEXT("r.AOHistoryStabilityPass"),
GAOHistoryStabilityPass,
TEXT("Whether to gather stable results to fill in holes in the temporal reprojection. Adds some GPU cost but improves temporal stability with foliage."),
ECVF_RenderThreadSafe
);
float GAOHistoryWeight = .85f;
FAutoConsoleVariableRef CVarAOHistoryWeight(
TEXT("r.AOHistoryWeight"),
GAOHistoryWeight,
TEXT("Amount of last frame's AO to lerp into the final result. Higher values increase stability, lower values have less streaking under occluder movement."),
ECVF_RenderThreadSafe
);
float GAOHistoryDistanceThreshold = 30;
FAutoConsoleVariableRef CVarAOHistoryDistanceThreshold(
TEXT("r.AOHistoryDistanceThreshold"),
GAOHistoryDistanceThreshold,
TEXT("World space distance threshold needed to discard last frame's DFAO results. Lower values reduce ghosting from characters when near a wall but increase flickering artifacts."),
ECVF_RenderThreadSafe
);
float GAOViewFadeDistanceScale = .7f;
FAutoConsoleVariableRef CVarAOViewFadeDistanceScale(
TEXT("r.AOViewFadeDistanceScale"),
GAOViewFadeDistanceScale,
TEXT("Distance over which AO will fade out as it approaches r.AOMaxViewDistance, as a fraction of r.AOMaxViewDistance."),
ECVF_RenderThreadSafe
);
bool UseAOHistoryStabilityPass()
{
extern int32 GDistanceFieldAOQuality;
return GAOHistoryStabilityPass && GDistanceFieldAOQuality >= 2;
}
BEGIN_SHADER_PARAMETER_STRUCT(FGeometryAwareUpsampleParameters, )
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, DistanceFieldNormalTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, DistanceFieldNormalSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, BentNormalAOTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, BentNormalAOSampler)
SHADER_PARAMETER(FVector4f, BentNormalBufferAndTexelSize)
SHADER_PARAMETER(FVector2f, DistanceFieldGBufferTexelSize)
SHADER_PARAMETER(FVector2f, DistanceFieldGBufferJitterOffset)
SHADER_PARAMETER(FVector2f, JitterOffset)
SHADER_PARAMETER(float, MinDownsampleFactorToBaseLevel)
SHADER_PARAMETER(float, DistanceFadeScale)
END_SHADER_PARAMETER_STRUCT()
FGeometryAwareUpsampleParameters SetupGeometryAwareUpsampleParameters(const FViewInfo& View, FRDGTextureRef DistanceFieldNormal, FRDGTextureRef DistanceFieldAOBentNormal)
{
extern FVector2f GetJitterOffset(const FViewInfo& View);
FVector2f const JitterOffsetValue = GetJitterOffset(View);
const FIntPoint DownsampledBufferSize = GetBufferSizeForAO(View);
const FVector2f BaseLevelTexelSizeValue(1.0f / DownsampledBufferSize.X, 1.0f / DownsampledBufferSize.Y);
extern FIntPoint GetBufferSizeForConeTracing(const FViewInfo& View);
const FIntPoint ConeTracingBufferSize = GetBufferSizeForConeTracing(View);
const FVector4f BentNormalBufferAndTexelSizeValue(ConeTracingBufferSize.X, ConeTracingBufferSize.Y, 1.0f / ConeTracingBufferSize.X, 1.0f / ConeTracingBufferSize.Y);
extern int32 GConeTraceDownsampleFactor;
const float MinDownsampleFactor = GConeTraceDownsampleFactor;
extern float GAOViewFadeDistanceScale;
const float DistanceFadeScaleValue = 1.0f / ((1.0f - GAOViewFadeDistanceScale) * GetMaxAOViewDistance());
FGeometryAwareUpsampleParameters ShaderParameters;
ShaderParameters.DistanceFieldNormalTexture = DistanceFieldNormal;
ShaderParameters.DistanceFieldNormalSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
ShaderParameters.BentNormalAOTexture = DistanceFieldAOBentNormal;
ShaderParameters.BentNormalAOSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
ShaderParameters.BentNormalBufferAndTexelSize = BentNormalBufferAndTexelSizeValue;
ShaderParameters.DistanceFieldGBufferTexelSize = BaseLevelTexelSizeValue;
ShaderParameters.DistanceFieldGBufferJitterOffset = BaseLevelTexelSizeValue * JitterOffsetValue;
ShaderParameters.JitterOffset = JitterOffsetValue;
ShaderParameters.MinDownsampleFactorToBaseLevel = MinDownsampleFactor;
ShaderParameters.DistanceFadeScale = DistanceFadeScaleValue;
return ShaderParameters;
}
class FUpdateHistoryDepthRejectionPS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FUpdateHistoryDepthRejectionPS);
SHADER_USE_PARAMETER_STRUCT(FUpdateHistoryDepthRejectionPS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures)
SHADER_PARAMETER_STRUCT_INCLUDE(FAOParameters, AOParameters)
SHADER_PARAMETER_STRUCT_INCLUDE(FGeometryAwareUpsampleParameters, GeometryAwareUpsampleParameters)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, BentNormalHistoryTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, BentNormalHistorySampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, VelocityTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, VelocityTextureSampler)
SHADER_PARAMETER(FVector4f, HistoryScreenPositionScaleBias)
SHADER_PARAMETER(FVector4f, HistoryUVMinMax)
SHADER_PARAMETER(float, HistoryWeight)
SHADER_PARAMETER(float, HistoryDistanceThreshold)
SHADER_PARAMETER(float, UseHistoryFilter)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return ShouldCompileDistanceFieldShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor);
}
};
IMPLEMENT_GLOBAL_SHADER(FUpdateHistoryDepthRejectionPS, "/Engine/Private/DistanceFieldLightingPost.usf", "UpdateHistoryDepthRejectionPS", SF_Pixel);
class FFilterHistoryPS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FFilterHistoryPS);
SHADER_USE_PARAMETER_STRUCT(FFilterHistoryPS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, BentNormalAOTexture)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, DistanceFieldNormalTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, BentNormalAOSampler)
SHADER_PARAMETER_SAMPLER(SamplerState, DistanceFieldNormalSampler)
SHADER_PARAMETER(FVector2f, BentNormalAOTexelSize)
SHADER_PARAMETER(FVector2f, MaxSampleBufferUV)
SHADER_PARAMETER(float, HistoryWeight)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
class FManuallyClampUV : SHADER_PERMUTATION_BOOL("MANUALLY_CLAMP_UV");
using FPermutationDomain = TShaderPermutationDomain<FManuallyClampUV>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return ShouldCompileDistanceFieldShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor);
}
};
IMPLEMENT_GLOBAL_SHADER(FFilterHistoryPS, "/Engine/Private/DistanceFieldLightingPost.usf", "FilterHistoryPS", SF_Pixel);
class FGeometryAwareUpsamplePS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FGeometryAwareUpsamplePS);
SHADER_USE_PARAMETER_STRUCT(FGeometryAwareUpsamplePS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_STRUCT_INCLUDE(FAOParameters, AOParameters)
SHADER_PARAMETER_STRUCT_INCLUDE(FGeometryAwareUpsampleParameters, GeometryAwareUpsampleParameters)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return ShouldCompileDistanceFieldShaders(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor);
}
};
IMPLEMENT_SHADER_TYPE(,FGeometryAwareUpsamplePS, TEXT("/Engine/Private/DistanceFieldLightingPost.usf"), TEXT("GeometryAwareUpsamplePS"), SF_Pixel);
void AllocateOrReuseAORenderTarget(FRDGBuilder& GraphBuilder, const FViewInfo& View, FRDGTextureRef& Texture, const TCHAR* Name, EPixelFormat Format, ETextureCreateFlags Flags)
{
if (!Texture)
{
const FIntPoint BufferSize = GetBufferSizeForAO(View);
const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(BufferSize, Format, FClearValueBinding::None, Flags | TexCreate_ShaderResource | TexCreate_RenderTargetable | TexCreate_UAV);
Texture = GraphBuilder.CreateTexture(Desc, Name);
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(Texture), FLinearColor::Black);
}
}
void GeometryAwareUpsample(FRDGBuilder& GraphBuilder, const FViewInfo& View, FRDGTextureRef DistanceFieldAOBentNormal, FRDGTextureRef DistanceFieldNormal, FRDGTextureRef BentNormalInterpolation, const FDistanceFieldAOParameters& Parameters)
{
auto* PassParameters = GraphBuilder.AllocParameters<FGeometryAwareUpsamplePS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
PassParameters->AOParameters = DistanceField::SetupAOShaderParameters(Parameters);
PassParameters->GeometryAwareUpsampleParameters = SetupGeometryAwareUpsampleParameters(View, DistanceFieldNormal, BentNormalInterpolation);
PassParameters->RenderTargets[0] = FRenderTargetBinding(DistanceFieldAOBentNormal, ERenderTargetLoadAction::ELoad);
auto VertexShader = View.ShaderMap->GetShader<FPostProcessVS>();
auto PixelShader = View.ShaderMap->GetShader<FGeometryAwareUpsamplePS>();
ClearUnusedGraphResources(PixelShader, PassParameters);
GraphBuilder.AddPass(
RDG_EVENT_NAME("GeometryAwareUpsample"),
PassParameters,
ERDGPassFlags::Raster,
[PassParameters, VertexShader, PixelShader, &View](FRHICommandList& RHICmdList)
{
RHICmdList.SetViewport(0, 0, 0.0f, View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor, 1.0f);
FGraphicsPipelineStateInitializer GraphicsPSOInit;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
FIntPoint(View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor),
View.GetSceneTexturesConfig().Extent / FIntPoint(GAODownsampleFactor, GAODownsampleFactor),
VertexShader);
});
}
bool DistanceFieldAOUseHistory(const FViewInfo& View)
{
// Disable AO history for cube map captures to save memory. AO history (DistanceFieldAOHistoryRT) is sized to the scene texture extents, meaning
// the size is proportional to the front buffer resolution, regardless of the resolution of the cube map capture itself. This then gets multiplied
// by 6 for cube map faces. This totals around 25 MB at 1080p or 100 MB at 4K resolution.
//
// JHOERNER_TODO: Ideally, the code would be rewritten so DistanceFieldAOHistoryRT is sized to the view rectangle, rather than scene texture extents.
// The goal of scene texture extents is to reuse render target memory on platforms like PC, by making all scene renders use the same sized render
// targets for things like gbuffers. This advantage doesn't apply to temporal history buffers, since these persist across frames and are unique per
// scene view state, and never shared. As an example, temporal volumetric cloud buffers (VolumetricCloudRenderTarget) are scaled to the view rect,
// and so don't involve a similar memory waste.
//
// I did investigate fixing the memory waste myself, and started attempting it, but it's an involved process due to the number of places in the code
// you'd need to touch. I figured it would be better if someone that has worked with the code before did the changes, to make sure nothing relevant
// was missed, and hopefully they'd be able to visually tell if it was working correctly.
//
// At a basic level, you'd modify UpdateHistory below so instead of using "View.GetSceneTexturesConfig().Extent" to determine the history dimensions,
// you'd use the view rect (multiple places in that function). You'd eliminate "HistoryScreenPositionScaleBiasValue" and "HistoryUVMinMaxValue" scale
// and clamping factors when reading from the history in shaders. The input scene textures (VelocityTexture, etc) would still be in scene texture
// space, so there would be a mix of UV math going on, depending on what textures you were sampling from.
//
// If it was just the shaders in UpdateHistory, I'd give it a shot, but there are additional shaders referencing "BentNormalAOTexture", including from
// DistanceFieldAOShared.ush and DistanceFieldLightingPost.usf. You'd need to update all the shaders, and possibly add extra parameters to make
// information available about the resolution of the history (can't use View.BufferSizeAndInvSize). Any typos could cause artifacts which will only
// be visually obvious if you set up a synthetic test where the scene texture extents don't match the view rect (you should be able to accomplish
// this for debug purposes by modifying FSceneTextureExtentState::Compute to add some padding to the scene textures).
//
return GAOUseHistory && !View.bIsSceneCaptureCube;
}
void UpdateHistory(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const TCHAR* BentNormalHistoryRTName,
TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTexturesUniformBuffer,
FRDGTextureRef VelocityTexture,
FRDGTextureRef DistanceFieldNormal,
FRDGTextureRef BentNormalInterpolation,
/** Contains last frame's history, if non-NULL. This will be updated with the new frame's history. */
FIntRect* DistanceFieldAOHistoryViewRect,
TRefCountPtr<IPooledRenderTarget>* BentNormalHistoryState,
/** Output of Temporal Reprojection for the next step in the pipeline. */
FRDGTextureRef& BentNormalHistoryOutput,
const FDistanceFieldAOParameters& Parameters)
{
const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);
const FIntPoint SceneTextureExtent = View.GetSceneTexturesConfig().Extent;
if (BentNormalHistoryState && DistanceFieldAOUseHistory(View))
{
#if WITH_MGPU
RDG_GPU_STAT_SCOPE(GraphBuilder, AFRWaitForDistanceFieldAOHistory);
AddPass(GraphBuilder, RDG_EVENT_NAME("WaitForTemporalEffect"), [&View](FRHICommandList& RHICmdList)
{
static const FName NameForTemporalEffect("DistanceFieldAOHistory");
RHICmdList.WaitForTemporalEffect(FName(NameForTemporalEffect, View.ViewState->UniqueID));
});
#endif
FIntPoint BufferSize = GetBufferSizeForAO(View);
if (*BentNormalHistoryState
&& !View.bCameraCut
&& !View.bPrevTransformsReset
&& View.Family->bRealtimeUpdate
&& !GAOClearHistory
// If the scene render targets reallocate, toss the history so we don't read uninitialized data
&& (*BentNormalHistoryState)->GetDesc().Extent == BufferSize)
{
FRDGTextureRef BentNormalHistoryTexture = GraphBuilder.RegisterExternalTexture(*BentNormalHistoryState);
ETextureCreateFlags HistoryPassOutputFlags = ETextureCreateFlags(UseAOHistoryStabilityPass() ? GFastVRamConfig.DistanceFieldAOHistory : TexCreate_None);
// Reuse a render target from the pool with a consistent name, for vis purposes
FRDGTextureRef NewBentNormalHistory = nullptr;
AllocateOrReuseAORenderTarget(GraphBuilder, View, NewBentNormalHistory, BentNormalHistoryRTName, PF_FloatRGBA, HistoryPassOutputFlags);
{
FIntRect PrevHistoryViewRect = *DistanceFieldAOHistoryViewRect;
auto* PassParameters = GraphBuilder.AllocParameters<FUpdateHistoryDepthRejectionPS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
PassParameters->SceneTextures = SceneTexturesUniformBuffer;
PassParameters->AOParameters = DistanceField::SetupAOShaderParameters(Parameters);
PassParameters->GeometryAwareUpsampleParameters = SetupGeometryAwareUpsampleParameters(View, DistanceFieldNormal, BentNormalInterpolation);
PassParameters->BentNormalHistoryTexture = BentNormalHistoryTexture;
PassParameters->BentNormalHistorySampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
PassParameters->VelocityTexture = GetIfProduced(VelocityTexture, SystemTextures.Black);
PassParameters->VelocityTextureSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
PassParameters->HistoryWeight = GAOHistoryWeight;
PassParameters->HistoryDistanceThreshold = GAOHistoryDistanceThreshold;
PassParameters->UseHistoryFilter = UseAOHistoryStabilityPass() ? 1.0f : 0.0f;
{
FIntPoint HistoryBufferSize = View.GetSceneTexturesConfig().Extent / FIntPoint(GAODownsampleFactor, GAODownsampleFactor);
const float InvBufferSizeX = 1.0f / HistoryBufferSize.X;
const float InvBufferSizeY = 1.0f / HistoryBufferSize.Y;
const FVector4f HistoryScreenPositionScaleBiasValue(
PrevHistoryViewRect.Width() * InvBufferSizeX / +2.0f,
PrevHistoryViewRect.Height() * InvBufferSizeY / (-2.0f * GProjectionSignY),
(PrevHistoryViewRect.Height() / 2.0f + PrevHistoryViewRect.Min.Y) * InvBufferSizeY,
(PrevHistoryViewRect.Width() / 2.0f + PrevHistoryViewRect.Min.X) * InvBufferSizeX);
// Pull in the max UV to exclude the region which will read outside the viewport due to bilinear filtering
const FVector4f HistoryUVMinMaxValue(
(PrevHistoryViewRect.Min.X + 0.5f) * InvBufferSizeX,
(PrevHistoryViewRect.Min.Y + 0.5f) * InvBufferSizeY,
(PrevHistoryViewRect.Max.X - 0.5f) * InvBufferSizeX,
(PrevHistoryViewRect.Max.Y - 0.5f) * InvBufferSizeY);
PassParameters->HistoryScreenPositionScaleBias = HistoryScreenPositionScaleBiasValue;
PassParameters->HistoryUVMinMax = HistoryUVMinMaxValue;
}
PassParameters->RenderTargets[0] = FRenderTargetBinding(NewBentNormalHistory, ERenderTargetLoadAction::ELoad);
TShaderMapRef<FPostProcessVS> VertexShader(View.ShaderMap);
TShaderMapRef<FUpdateHistoryDepthRejectionPS> PixelShader(View.ShaderMap);
ClearUnusedGraphResources(PixelShader, PassParameters);
GraphBuilder.AddPass(
RDG_EVENT_NAME("UpdateHistory"),
PassParameters,
ERDGPassFlags::Raster,
[PassParameters, VertexShader, PixelShader, &View, SceneTextureExtent]
(FRHICommandList& RHICmdList)
{
RHICmdList.SetViewport(0, 0, 0.0f, View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor, 1.0f);
FGraphicsPipelineStateInitializer GraphicsPSOInit;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
View.ViewRect.Min.X / GAODownsampleFactor, View.ViewRect.Min.Y / GAODownsampleFactor,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
FIntPoint(View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor),
SceneTextureExtent / FIntPoint(GAODownsampleFactor, GAODownsampleFactor),
VertexShader);
});
}
if (UseAOHistoryStabilityPass())
{
const FRDGTextureDesc& HistoryDesc = BentNormalHistoryTexture->Desc;
// Reallocate history if buffer sizes have changed
if (HistoryDesc.Extent != SceneTextureExtent / FIntPoint(GAODownsampleFactor, GAODownsampleFactor))
{
GRenderTargetPool.FreeUnusedResource(*BentNormalHistoryState);
*BentNormalHistoryState = nullptr;
// Update the view state's render target reference with the new history
AllocateOrReuseAORenderTarget(GraphBuilder, View, BentNormalHistoryTexture, BentNormalHistoryRTName, PF_FloatRGBA);
}
const bool bManuallyClampUV = View.ViewRect.Min != FIntPoint::ZeroValue || View.ViewRect.Max != SceneTextureExtent;
FFilterHistoryPS::FPermutationDomain PermutationVector;
PermutationVector.Set<FFilterHistoryPS::FManuallyClampUV>(bManuallyClampUV);
auto VertexShader = View.ShaderMap->GetShader<FPostProcessVS>();
auto PixelShader = View.ShaderMap->GetShader<FFilterHistoryPS>(PermutationVector);
const FIntPoint DownsampledBufferSize(View.GetSceneTexturesConfig().Extent / FIntPoint(GAODownsampleFactor, GAODownsampleFactor));
FVector2f MaxSampleBufferUV(
(View.ViewRect.Width() / GAODownsampleFactor - 0.5f - GAODownsampleFactor) / DownsampledBufferSize.X,
(View.ViewRect.Height() / GAODownsampleFactor - 0.5f - GAODownsampleFactor) / DownsampledBufferSize.Y);
auto* PassParameters = GraphBuilder.AllocParameters<FFilterHistoryPS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
PassParameters->SceneTextures = SceneTexturesUniformBuffer;
PassParameters->DistanceFieldNormalTexture = DistanceFieldNormal;
PassParameters->BentNormalAOTexture = NewBentNormalHistory;
PassParameters->DistanceFieldNormalSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
PassParameters->BentNormalAOSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
PassParameters->BentNormalAOTexelSize = FVector2f(1.0f / DownsampledBufferSize.X, 1.0f / DownsampledBufferSize.Y);
PassParameters->MaxSampleBufferUV = MaxSampleBufferUV;
PassParameters->HistoryWeight = GAOHistoryWeight;
PassParameters->RenderTargets[0] = FRenderTargetBinding(BentNormalHistoryTexture, ERenderTargetLoadAction::ELoad);
ClearUnusedGraphResources(PixelShader, PassParameters);
GraphBuilder.AddPass(
RDG_EVENT_NAME("UpdateHistoryStability"),
PassParameters,
ERDGPassFlags::Raster,
[PassParameters, VertexShader, PixelShader, &View, SceneTextureExtent](FRHICommandList& RHICmdList)
{
RHICmdList.SetViewport(0, 0, 0.0f, View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor, 1.0f);
FGraphicsPipelineStateInitializer GraphicsPSOInit;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
0, 0,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
FIntPoint(View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor),
SceneTextureExtent / FIntPoint(GAODownsampleFactor, GAODownsampleFactor),
VertexShader);
});
GraphBuilder.QueueTextureExtraction(BentNormalHistoryTexture, BentNormalHistoryState);
BentNormalHistoryOutput = BentNormalHistoryTexture;
}
else
{
// Update the view state's render target reference with the new history
GraphBuilder.QueueTextureExtraction(NewBentNormalHistory, BentNormalHistoryState);
BentNormalHistoryOutput = NewBentNormalHistory;
}
}
else
{
// Use the current frame's upscaled mask for next frame's history
FRDGTextureRef DistanceFieldAOBentNormal = nullptr;
AllocateOrReuseAORenderTarget(GraphBuilder, View, DistanceFieldAOBentNormal, TEXT("DistanceFieldBentNormalAO"), PF_FloatRGBA, GFastVRamConfig.DistanceFieldAOBentNormal);
GeometryAwareUpsample(GraphBuilder, View, DistanceFieldAOBentNormal, DistanceFieldNormal, BentNormalInterpolation, Parameters);
GraphBuilder.QueueTextureExtraction(DistanceFieldAOBentNormal, BentNormalHistoryState);
BentNormalHistoryOutput = DistanceFieldAOBentNormal;
}
DistanceFieldAOHistoryViewRect->Min = FIntPoint::ZeroValue;
DistanceFieldAOHistoryViewRect->Max.X = View.ViewRect.Size().X / GAODownsampleFactor;
DistanceFieldAOHistoryViewRect->Max.Y = View.ViewRect.Size().Y / GAODownsampleFactor;
#if WITH_MGPU && 0 // TODO(RDG)
FRHITexture* TexturesToCopyForTemporalEffect[] = { BentNormalHistoryOutput->GetRHI() };
RHICmdList.BroadcastTemporalEffect(FName(NameForTemporalEffect, View.ViewState->UniqueID), TexturesToCopyForTemporalEffect);
#endif
}
else
{
// Temporal reprojection is disabled or there is no view state - just upscale
FRDGTextureRef DistanceFieldAOBentNormal = nullptr;
AllocateOrReuseAORenderTarget(GraphBuilder, View, DistanceFieldAOBentNormal, TEXT("DistanceFieldBentNormalAO"), PF_FloatRGBA, GFastVRamConfig.DistanceFieldAOBentNormal);
GeometryAwareUpsample(GraphBuilder, View, DistanceFieldAOBentNormal, DistanceFieldNormal, BentNormalInterpolation, Parameters);
BentNormalHistoryOutput = DistanceFieldAOBentNormal;
}
}
class FDistanceFieldAOUpsamplePS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FDistanceFieldAOUpsamplePS);
SHADER_USE_PARAMETER_STRUCT(FDistanceFieldAOUpsamplePS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures)
SHADER_PARAMETER_STRUCT_INCLUDE(FDFAOUpsampleParameters, DFAOUpsampleParameters)
SHADER_PARAMETER(float, MinIndirectDiffuseOcclusion)
RDG_TEXTURE_ACCESS(DistanceFieldAOBentNormal, ERHIAccess::SRVGraphics)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
class FModulateToSceneColorDim : SHADER_PERMUTATION_BOOL("MODULATE_SCENE_COLOR");
using FPermutationDomain = TShaderPermutationDomain<FModulateToSceneColorDim>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return ShouldCompileDistanceFieldShaders(Parameters.Platform);
}
};
IMPLEMENT_GLOBAL_SHADER(FDistanceFieldAOUpsamplePS, "/Engine/Private/DistanceFieldLightingPost.usf", "AOUpsamplePS", SF_Pixel);
void UpsampleBentNormalAO(
FRDGBuilder& GraphBuilder,
const TArray<FViewInfo>& Views,
TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTexturesUniformBuffer,
FRDGTextureRef SceneColorTexture,
FRDGTextureRef DistanceFieldAOBentNormal,
bool bModulateSceneColor)
{
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
FScene* Scene = (FScene*)View.Family->Scene;
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
auto* PassParameters = GraphBuilder.AllocParameters<FDistanceFieldAOUpsamplePS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
PassParameters->SceneTextures = SceneTexturesUniformBuffer;
PassParameters->DFAOUpsampleParameters = DistanceField::SetupAOUpsampleParameters(View, DistanceFieldAOBentNormal ? DistanceFieldAOBentNormal : GSystemTextures.GetWhiteDummy(GraphBuilder));
PassParameters->MinIndirectDiffuseOcclusion = Scene->SkyLight ? Scene->SkyLight->MinOcclusion : 0;
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture, ERenderTargetLoadAction::ELoad);
PassParameters->DistanceFieldAOBentNormal = DistanceFieldAOBentNormal;
TShaderMapRef<FPostProcessVS> VertexShader(View.ShaderMap);
FDistanceFieldAOUpsamplePS::FPermutationDomain PermutationVector;
PermutationVector.Set<FDistanceFieldAOUpsamplePS::FModulateToSceneColorDim>(bModulateSceneColor);
TShaderMapRef<FDistanceFieldAOUpsamplePS> PixelShader(View.ShaderMap, PermutationVector);
GraphBuilder.AddPass(
RDG_EVENT_NAME("UpsampleAO"),
PassParameters,
ERDGPassFlags::Raster,
[VertexShader, PixelShader, PassParameters, &View, DistanceFieldAOBentNormal, bModulateSceneColor](FRHICommandList& RHICmdList)
{
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
FGraphicsPipelineStateInitializer GraphicsPSOInit;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
if (bModulateSceneColor)
{
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGB, BO_Add, BF_DestColor, BF_Zero, BO_Add, BF_Zero, BF_One>::GetRHI();
}
else
{
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
}
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width(), View.ViewRect.Height(),
View.ViewRect.Min.X / GAODownsampleFactor, View.ViewRect.Min.Y / GAODownsampleFactor,
View.ViewRect.Width() / GAODownsampleFactor, View.ViewRect.Height() / GAODownsampleFactor,
FIntPoint(View.ViewRect.Width(), View.ViewRect.Height()),
GetBufferSizeForAO(View),
VertexShader);
});
}
}