Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp
guillaume abadie 4e42a66ca9 Allows TSR to upscale separate translucency independently from input resolution
This also implements r.Translucency.ScreenPercentage.Basis to experiment controling the translucency resolution independently from the primary screen percentage

#rb none
#jira UE-152560
#preflight 6294fbc4e61254772f5834a6

#ROBOMERGE-AUTHOR: guillaume.abadie
#ROBOMERGE-SOURCE: CL 20432059 via CL 20432067 via CL 20432069
#ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v949-20362246)

[CL 20434142 by guillaume abadie in ue5-main branch]
2022-05-31 01:21:02 -04:00

1543 lines
65 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "TranslucentRendering.h"
#include "DeferredShadingRenderer.h"
#include "BasePassRendering.h"
#include "DynamicPrimitiveDrawing.h"
#include "RendererModule.h"
#include "ScenePrivate.h"
#include "SceneTextureParameters.h"
#include "ScreenRendering.h"
#include "ScreenPass.h"
#include "MeshPassProcessor.inl"
#include "VolumetricRenderTarget.h"
#include "VariableRateShadingImageManager.h"
#include "Lumen/LumenTranslucencyVolumeLighting.h"
#include "VirtualShadowMaps/VirtualShadowMapArray.h"
#include "Strata/Strata.h"
#include "HairStrands/HairStrandsUtils.h"
#include "PixelShaderUtils.h"
#include "OIT/OIT.h"
#include "OIT/OITParameters.h"
#include "DynamicResolutionState.h"
#include "TemporalAA.h"
DECLARE_CYCLE_STAT(TEXT("TranslucencyTimestampQueryFence Wait"), STAT_TranslucencyTimestampQueryFence_Wait, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("TranslucencyTimestampQuery Wait"), STAT_TranslucencyTimestampQuery_Wait, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("Translucency"), STAT_CLP_Translucency, STATGROUP_ParallelCommandListMarkers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Translucency GPU Time (MS)"), STAT_TranslucencyGPU, STATGROUP_SceneRendering);
DEFINE_GPU_DRAWCALL_STAT(Translucency);
static TAutoConsoleVariable<float> CVarSeparateTranslucencyScreenPercentage(
TEXT("r.SeparateTranslucencyScreenPercentage"),
100.0f,
TEXT("Render separate translucency at this percentage of the full resolution.\n")
TEXT("in percent, >0 and <=100, larger numbers are possible (supersampling).")
TEXT("<0 is treated like 100."),
ECVF_Scalability | ECVF_Default);
static TAutoConsoleVariable<int32> CVarTranslucencyScreenPercentageBasis(
TEXT("r.Translucency.ScreenPercentage.Basis"), 0,
TEXT("Basis of the translucency's screen percentage (Experimental).\n")
TEXT(" 0: Uses the primary view's resolution (notably scaling with r.ScreenPercentage and r.DynamicRes.*)\n")
TEXT(" 1: Uses the secondary view's resolution (temporal upscale's output resolution)"),
ECVF_Scalability | ECVF_Default);
static TAutoConsoleVariable<float> CVarTranslucencyMinScreenPercentage(
TEXT("r.Translucency.DynamicRes.MinScreenPercentage"),
DynamicRenderScaling::FractionToPercentage(DynamicRenderScaling::FHeuristicSettings::kDefaultMinResolutionFraction),
TEXT("Minimal screen percentage for translucency."),
ECVF_RenderThreadSafe | ECVF_Default);
static TAutoConsoleVariable<float> CVarTranslucencyTimeBudget(
TEXT("r.Translucency.DynamicRes.TimeBudget"),
DynamicRenderScaling::FHeuristicSettings::kBudgetMsDisabled,
TEXT("Frame's time budget for translucency rendering in milliseconds."),
ECVF_RenderThreadSafe | ECVF_Default);
static TAutoConsoleVariable<float> CVarTranslucencyTargetedHeadRoomPercentage(
TEXT("r.Translucency.DynamicRes.TargetedHeadRoomPercentage"),
DynamicRenderScaling::FractionToPercentage(DynamicRenderScaling::FHeuristicSettings::kDefaultTargetedHeadRoom),
TEXT("Targeted GPU headroom for translucency (in percent from r.DynamicRes.DynamicRes.TimeBudget)."),
ECVF_RenderThreadSafe | ECVF_Default);
static TAutoConsoleVariable<float> CVarTranslucencyChangeThreshold(
TEXT("r.Translucency.DynamicRes.ChangePercentageThreshold"),
DynamicRenderScaling::FractionToPercentage(DynamicRenderScaling::FHeuristicSettings::kDefaultChangeThreshold),
TEXT("Minimal increase percentage threshold to alow when changing resolution of translucency."),
ECVF_RenderThreadSafe | ECVF_Default);
int32 GSeparateTranslucencyUpsampleMode = 1;
static FAutoConsoleVariableRef CVarSeparateTranslucencyUpsampleMode(
TEXT("r.SeparateTranslucencyUpsampleMode"),
GSeparateTranslucencyUpsampleMode,
TEXT("Upsample method to use on separate translucency. These are only used when r.SeparateTranslucencyScreenPercentage is less than 100.\n")
TEXT("0: bilinear 1: Nearest-Depth Neighbor (only when r.SeparateTranslucencyScreenPercentage is 50)"),
ECVF_Scalability | ECVF_Default);
static TAutoConsoleVariable<int32> CVarRHICmdFlushRenderThreadTasksTranslucentPass(
TEXT("r.RHICmdFlushRenderThreadTasksTranslucentPass"),
0,
TEXT("Wait for completion of parallel render thread tasks at the end of the translucent pass. A more granular version of r.RHICmdFlushRenderThreadTasks. If either r.RHICmdFlushRenderThreadTasks or r.RHICmdFlushRenderThreadTasksTranslucentPass is > 0 we will flush."));
static TAutoConsoleVariable<int32> CVarParallelTranslucency(
TEXT("r.ParallelTranslucency"),
1,
TEXT("Toggles parallel translucency rendering. Parallel rendering must be enabled for this to have an effect."),
ECVF_RenderThreadSafe);
DynamicRenderScaling::FHeuristicSettings GetDynamicTranslucencyResolutionSettings()
{
DynamicRenderScaling::FHeuristicSettings BucketSetting;
BucketSetting.Model = DynamicRenderScaling::EHeuristicModel::Quadratic;
BucketSetting.bModelScalesWithPrimaryScreenPercentage = CVarTranslucencyScreenPercentageBasis.GetValueOnAnyThread() != 1;
BucketSetting.MinResolutionFraction = DynamicRenderScaling::GetPercentageCVarToFraction(CVarTranslucencyMinScreenPercentage);
BucketSetting.BudgetMs = CVarTranslucencyTimeBudget.GetValueOnAnyThread();
BucketSetting.ChangeThreshold = DynamicRenderScaling::GetPercentageCVarToFraction(CVarTranslucencyChangeThreshold);
BucketSetting.TargetedHeadRoom = DynamicRenderScaling::GetPercentageCVarToFraction(CVarTranslucencyTargetedHeadRoomPercentage);
return BucketSetting;
}
DynamicRenderScaling::FBudget GDynamicTranslucencyResolution(TEXT("DynamicTranslucencyResolution"), &GetDynamicTranslucencyResolutionSettings);
static const TCHAR* kTranslucencyPassName[] = {
TEXT("BeforeDistortion"),
TEXT("AfterDOF"),
TEXT("AfterDOFModulate"),
TEXT("AfterMotionBlur"),
TEXT("All"),
};
static_assert(UE_ARRAY_COUNT(kTranslucencyPassName) == int32(ETranslucencyPass::TPT_MAX), "Fix me");
static const TCHAR* kTranslucencyColorTextureName[] = {
TEXT("Translucency.BeforeDistortion.Color"),
TEXT("Translucency.AfterDOF.Color"),
TEXT("Translucency.AfterDOF.Modulate"),
TEXT("Translucency.AfterMotionBlur.Color"),
TEXT("Translucency.All.Color"),
};
static_assert(UE_ARRAY_COUNT(kTranslucencyColorTextureName) == int32(ETranslucencyPass::TPT_MAX), "Fix me");
static const TCHAR* TranslucencyPassToString(ETranslucencyPass::Type TranslucencyPass)
{
return kTranslucencyPassName[TranslucencyPass];
}
EMeshPass::Type TranslucencyPassToMeshPass(ETranslucencyPass::Type TranslucencyPass)
{
EMeshPass::Type TranslucencyMeshPass = EMeshPass::Num;
switch (TranslucencyPass)
{
case ETranslucencyPass::TPT_StandardTranslucency: TranslucencyMeshPass = EMeshPass::TranslucencyStandard; break;
case ETranslucencyPass::TPT_TranslucencyAfterDOF: TranslucencyMeshPass = EMeshPass::TranslucencyAfterDOF; break;
case ETranslucencyPass::TPT_TranslucencyAfterDOFModulate: TranslucencyMeshPass = EMeshPass::TranslucencyAfterDOFModulate; break;
case ETranslucencyPass::TPT_TranslucencyAfterMotionBlur: TranslucencyMeshPass = EMeshPass::TranslucencyAfterMotionBlur; break;
case ETranslucencyPass::TPT_AllTranslucency: TranslucencyMeshPass = EMeshPass::TranslucencyAll; break;
}
check(TranslucencyMeshPass != EMeshPass::Num);
return TranslucencyMeshPass;
}
ETranslucencyView GetTranslucencyView(const FViewInfo& View)
{
#if RHI_RAYTRACING
if (ShouldRenderRayTracingTranslucency(View))
{
return ETranslucencyView::RayTracing;
}
#endif
return View.IsUnderwater() ? ETranslucencyView::UnderWater : ETranslucencyView::AboveWater;
}
ETranslucencyView GetTranslucencyViews(TArrayView<const FViewInfo> Views)
{
ETranslucencyView TranslucencyViews = ETranslucencyView::None;
for (const FViewInfo& View : Views)
{
TranslucencyViews |= GetTranslucencyView(View);
}
return TranslucencyViews;
}
/** Mostly used to know if debug rendering should be drawn in this pass */
static bool IsMainTranslucencyPass(ETranslucencyPass::Type TranslucencyPass)
{
return TranslucencyPass == ETranslucencyPass::TPT_AllTranslucency || TranslucencyPass == ETranslucencyPass::TPT_StandardTranslucency;
}
static bool IsParallelTranslucencyEnabled()
{
return GRHICommandList.UseParallelAlgorithms() && CVarParallelTranslucency.GetValueOnRenderThread();
}
static bool IsTranslucencyWaitForTasksEnabled()
{
return IsParallelTranslucencyEnabled() && (CVarRHICmdFlushRenderThreadTasksTranslucentPass.GetValueOnRenderThread() > 0 || CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() > 0);
}
static bool IsSeparateTranslucencyEnabled(ETranslucencyPass::Type TranslucencyPass, float DownsampleScale)
{
// Currently AfterDOF is rendered earlier in the frame and must be rendered in a separate texture.
if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOF
|| TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate
|| TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur
)
{
return true;
}
// Otherwise it only gets rendered in the separate buffer if it is downsampled.
if (DownsampleScale < 1.0f)
{
return true;
}
return false;
}
static int GetSSRQuality()
{
static IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.SSR.Quality"));
int SSRQuality = CVar ? (CVar->GetInt()) : 0;
return SSRQuality;
}
static bool ShouldRenderTranslucencyScreenSpaceReflections(const FViewInfo& View)
{
// The screenspace reflection of translucency is not controlled by the postprocessing setting
// or the raytracing overlay setting. It needs to be turned on/off dynamically to support
// diffuse only
if (!View.Family->EngineShowFlags.ScreenSpaceReflections)
{
return false;
}
int SSRQuality = GetSSRQuality();
if (SSRQuality <= 0)
{
return false;
}
return true;
}
FSeparateTranslucencyDimensions UpdateSeparateTranslucencyDimensions(const FViewFamilyInfo& ActiveViewFamily)
{
float TranslucencyResolutionFraction = FMath::Clamp(CVarSeparateTranslucencyScreenPercentage.GetValueOnRenderThread() / 100.0f, 0.0f, 1.0f);
float MaxTranslucencyResolutionFraction = TranslucencyResolutionFraction;
if (GDynamicTranslucencyResolution.GetSettings().IsEnabled())
{
TranslucencyResolutionFraction = ActiveViewFamily.DynamicResolutionFractions[GDynamicTranslucencyResolution];
MaxTranslucencyResolutionFraction = ActiveViewFamily.DynamicResolutionUpperBounds[GDynamicTranslucencyResolution];
}
if (CVarTranslucencyScreenPercentageBasis.GetValueOnRenderThread() == 1)
{
TranslucencyResolutionFraction /= ActiveViewFamily.DynamicResolutionFractions[GDynamicPrimaryResolutionFraction];
MaxTranslucencyResolutionFraction /= ActiveViewFamily.DynamicResolutionUpperBounds[GDynamicPrimaryResolutionFraction];
}
FSeparateTranslucencyDimensions Dimensions;
// TODO: this should be MaxTranslucencyResolutionFraction instead of TranslucencyResolutionFraction to keep the size of render target stable, but the SvPositionToBuffer() is broken in material.
Dimensions.Extent = GetScaledExtent(ActiveViewFamily.SceneTexturesConfig.Extent, TranslucencyResolutionFraction);
Dimensions.NumSamples = ActiveViewFamily.SceneTexturesConfig.NumSamples;
Dimensions.Scale = TranslucencyResolutionFraction;
return Dimensions;
}
FTranslucencyPassResourcesMap::FTranslucencyPassResourcesMap(int32 NumViews)
{
Array.SetNum(NumViews);
for (int32 ViewIndex = 0; ViewIndex < NumViews; ViewIndex++)
{
for (int32 i = 0; i < int32(ETranslucencyPass::TPT_MAX); i++)
{
Array[ViewIndex][i].Pass = ETranslucencyPass::Type(i);
}
}
}
/** Pixel shader used to copy scene color into another texture so that materials can read from scene color with a node. */
class FCopySceneColorPS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FCopySceneColorPS);
SHADER_USE_PARAMETER_STRUCT(FCopySceneColorPS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SceneColorTexture)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
};
IMPLEMENT_GLOBAL_SHADER(FCopySceneColorPS, "/Engine/Private/TranslucentLightingShaders.usf", "CopySceneColorMain", SF_Pixel);
static FRDGTextureRef AddCopySceneColorPass(FRDGBuilder& GraphBuilder, TArrayView<const FViewInfo> Views, FRDGTextureMSAA SceneColor)
{
FRDGTextureRef SceneColorCopyTexture = nullptr;
ERenderTargetLoadAction LoadAction = ERenderTargetLoadAction::ENoAction;
RDG_EVENT_SCOPE(GraphBuilder, "CopySceneColor");
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
const FViewInfo& View = Views[ViewIndex];
if (View.IsUnderwater())
{
continue;
}
bool bNeedsResolve = false;
for (int32 TranslucencyPass = 0; TranslucencyPass < ETranslucencyPass::TPT_MAX; ++TranslucencyPass)
{
if (View.TranslucentPrimCount.UseSceneColorCopy((ETranslucencyPass::Type)TranslucencyPass))
{
bNeedsResolve = true;
break;
}
}
if (bNeedsResolve)
{
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
AddResolveSceneColorPass(GraphBuilder, View, SceneColor);
const FIntPoint SceneColorExtent = SceneColor.Target->Desc.Extent;
if (!SceneColorCopyTexture)
{
SceneColorCopyTexture = GraphBuilder.CreateTexture(FRDGTextureDesc::Create2D(SceneColorExtent, PF_B8G8R8A8, FClearValueBinding::White, TexCreate_ShaderResource | TexCreate_RenderTargetable), TEXT("SceneColorCopy"));
}
const FScreenPassTextureViewport Viewport(SceneColorCopyTexture, View.ViewRect);
TShaderMapRef<FScreenVS> VertexShader(View.ShaderMap);
TShaderMapRef<FCopySceneColorPS> PixelShader(View.ShaderMap);
auto* PassParameters = GraphBuilder.AllocParameters<FCopySceneColorPS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
PassParameters->SceneColorTexture = SceneColor.Resolve;
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorCopyTexture, LoadAction);
if (!View.Family->bMultiGPUForkAndJoin)
{
LoadAction = ERenderTargetLoadAction::ELoad;
}
AddDrawScreenPass(GraphBuilder, {}, View, Viewport, Viewport, VertexShader, PixelShader, PassParameters);
}
}
return SceneColorCopyTexture;
}
class FComposeSeparateTranslucencyPS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FComposeSeparateTranslucencyPS);
SHADER_USE_PARAMETER_STRUCT(FComposeSeparateTranslucencyPS, FGlobalShader);
class FNearestDepthNeighborUpsampling : SHADER_PERMUTATION_BOOL("PERMUTATION_NEARESTDEPTHNEIGHBOR");
using FPermutationDomain = TShaderPermutationDomain<FNearestDepthNeighborUpsampling>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(FScreenTransform, ScreenPosToSceneColorUV)
SHADER_PARAMETER(FScreenTransform, ScreenPosToSeparateTranslucencyUV)
SHADER_PARAMETER(FVector2f, SeparateTranslucencyUVMin)
SHADER_PARAMETER(FVector2f, SeparateTranslucencyUVMax)
SHADER_PARAMETER(FVector2f, SeparateTranslucencyExtentInverse)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SceneColorTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, SceneColorSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SeparateTranslucencyPointTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, SeparateTranslucencyPointSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SeparateModulationPointTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, SeparateModulationPointSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SeparateTranslucencyBilinearTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, SeparateTranslucencyBilinearSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SeparateModulationBilinearTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, SeparateModulationBilinearSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, LowResDepthTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, LowResDepthSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, FullResDepthTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, FullResDepthSampler)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
};
class FTranslucencyUpsampleResponsiveAAPS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FTranslucencyUpsampleResponsiveAAPS);
SHADER_USE_PARAMETER_STRUCT(FTranslucencyUpsampleResponsiveAAPS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(FIntPoint, StencilPixelPosMin)
SHADER_PARAMETER(FIntPoint, StencilPixelPosMax)
SHADER_PARAMETER(FScreenTransform, SvPositionToStencilPixelCoord)
SHADER_PARAMETER(int32, StencilMask)
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, StencilTexture)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
};
IMPLEMENT_GLOBAL_SHADER(FComposeSeparateTranslucencyPS, "/Engine/Private/ComposeSeparateTranslucency.usf", "MainPS", SF_Pixel);
IMPLEMENT_GLOBAL_SHADER(FTranslucencyUpsampleResponsiveAAPS, "/Engine/Private/TranslucencyUpsampling.usf", "UpsampleResponsiveAAPS", SF_Pixel);
FScreenPassTexture FTranslucencyComposition::AddPass(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FTranslucencyPassResources& TranslucencyTextures) const
{
// if nothing is rendered into the separate translucency, then just return the existing Scenecolor
ensure(TranslucencyTextures.IsValid());
if (!TranslucencyTextures.IsValid())
{
return SceneColor;
}
FRDGTextureRef SeparateModulationTexture = TranslucencyTextures.GetColorModulateForRead(GraphBuilder);
FRDGTextureRef SeparateTranslucencyTexture = TranslucencyTextures.GetColorForRead(GraphBuilder);
FScreenPassTextureViewport SceneColorViewport(FIntPoint(1, 1), FIntRect(0, 0, 1, 1));
if (SceneColor.IsValid())
{
SceneColorViewport = FScreenPassTextureViewport(SceneColor);
}
FScreenPassTextureViewport TranslucencyViewport(FIntPoint(1, 1), FIntRect(0, 0, 1, 1));
if (TranslucencyTextures.ColorTexture.IsValid())
{
TranslucencyViewport = FScreenPassTextureViewport(TranslucencyTextures.ColorTexture.Resolve, TranslucencyTextures.ViewRect);
}
else if (TranslucencyTextures.ColorModulateTexture.IsValid())
{
TranslucencyViewport = FScreenPassTextureViewport(TranslucencyTextures.ColorModulateTexture.Resolve, TranslucencyTextures.ViewRect);
}
bool bPostMotionBlur = TranslucencyTextures.Pass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur;
if (bPostMotionBlur)
{
check(!bApplyModulateOnly);
}
else if (bApplyModulateOnly)
{
if (!TranslucencyTextures.ColorModulateTexture.IsValid())
{
return SceneColor;
}
SeparateTranslucencyTexture = GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackAlphaOneDummy);
}
RDG_GPU_STAT_SCOPE(GraphBuilder, Translucency);
DynamicRenderScaling::FRDGScope DynamicTranslucencyResolutionScope(GraphBuilder, GDynamicTranslucencyResolution);
const TCHAR* OpName = nullptr;
FRHIBlendState* BlendState = nullptr;
FRDGTextureRef NewSceneColor = nullptr;
if (Operation == EOperation::UpscaleOnly)
{
check(!SceneColor.IsValid());
ensure(!TranslucencyTextures.ColorModulateTexture.IsValid());
OpName = TEXT("UpscaleTranslucency");
FRDGTextureDesc OutputDesc = FRDGTextureDesc::Create2D(
OutputViewport.Extent,
PF_FloatRGBA,
FClearValueBinding::Black,
TexCreate_RenderTargetable | TexCreate_ShaderResource);
NewSceneColor = GraphBuilder.CreateTexture(
OutputDesc,
bPostMotionBlur ? TEXT("PostMotionBlurTranslucency.SceneColor") : TEXT("PostDOFTranslucency.SceneColor"));
}
else if (Operation == EOperation::ComposeToExistingSceneColor)
{
check(SceneColor.IsValid());
ensure(!TranslucencyTextures.ColorModulateTexture.IsValid());
OpName = TEXT("ComposeTranslucencyToExistingColor");
BlendState = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_SourceAlpha>::GetRHI();
ensure(SceneColor.Texture->Desc.Flags & TexCreate_RenderTargetable);
NewSceneColor = SceneColor.Texture;
}
else if (Operation == EOperation::ComposeToNewSceneColor)
{
check(SceneColor.IsValid());
OpName = TEXT("ComposeTranslucencyToNewSceneColor");
FRDGTextureDesc OutputDesc = FRDGTextureDesc::Create2D(
OutputViewport.Extent,
OutputPixelFormat != PF_Unknown ? OutputPixelFormat : SceneColor.Texture->Desc.Format,
FClearValueBinding::Black,
TexCreate_RenderTargetable | TexCreate_ShaderResource);
NewSceneColor = GraphBuilder.CreateTexture(
OutputDesc,
bPostMotionBlur ? TEXT("PostMotionBlurTranslucency.SceneColor") : TEXT("PostDOFTranslucency.SceneColor"));
}
else
{
unimplemented();
}
const FVector2f SeparateTranslucencyExtentInv = FVector2f(1.0f, 1.0f) / FVector2f(TranslucencyViewport.Extent);
const bool bScaleSeparateTranslucency = OutputViewport.Rect.Size() != TranslucencyTextures.ViewRect.Size();
const float DownsampleScale = float(TranslucencyTextures.ViewRect.Width()) / float(OutputViewport.Rect.Width());
const bool DepthUpscampling = (
bScaleSeparateTranslucency &&
TranslucencyTextures.DepthTexture.IsValid() &&
SceneDepth.IsValid() &&
FMath::IsNearlyEqual(DownsampleScale, 0.5f) &&
GSeparateTranslucencyUpsampleMode > 0);
FScreenTransform SvPositionToViewportUV = FScreenTransform::SvPositionToViewportUV(OutputViewport.Rect);
FComposeSeparateTranslucencyPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FComposeSeparateTranslucencyPS::FParameters>();
PassParameters->ScreenPosToSceneColorUV = SvPositionToViewportUV * FScreenTransform::ChangeTextureBasisFromTo(
SceneColorViewport, FScreenTransform::ETextureBasis::ViewportUV, FScreenTransform::ETextureBasis::TextureUV);
PassParameters->ScreenPosToSeparateTranslucencyUV = SvPositionToViewportUV * FScreenTransform::ChangeTextureBasisFromTo(
TranslucencyViewport, FScreenTransform::ETextureBasis::ViewportUV, FScreenTransform::ETextureBasis::TextureUV);
PassParameters->SeparateTranslucencyUVMin = (FVector2f(TranslucencyViewport.Rect.Min) + FVector2f(0.5f, 0.5f)) * SeparateTranslucencyExtentInv;
PassParameters->SeparateTranslucencyUVMax = (FVector2f(TranslucencyViewport.Rect.Max) - FVector2f(0.5f, 0.5f)) * SeparateTranslucencyExtentInv;
PassParameters->SeparateTranslucencyExtentInverse = SeparateTranslucencyExtentInv;
PassParameters->SceneColorTexture = Operation == EOperation::ComposeToNewSceneColor
? SceneColor.Texture
: GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackAlphaOneDummy);
PassParameters->SceneColorSampler = TStaticSamplerState<SF_Point>::GetRHI();
PassParameters->SeparateTranslucencyPointTexture = SeparateTranslucencyTexture;
PassParameters->SeparateTranslucencyPointSampler = TStaticSamplerState<SF_Point>::GetRHI();
PassParameters->SeparateModulationPointTexture = SeparateModulationTexture;
PassParameters->SeparateModulationPointSampler = TStaticSamplerState<SF_Point>::GetRHI();
PassParameters->SeparateTranslucencyBilinearTexture = SeparateTranslucencyTexture;
PassParameters->SeparateTranslucencyBilinearSampler = TStaticSamplerState<SF_Bilinear>::GetRHI();
PassParameters->SeparateModulationBilinearTexture = SeparateModulationTexture;
PassParameters->SeparateModulationBilinearSampler = TStaticSamplerState<SF_Bilinear>::GetRHI();
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
if (Operation == EOperation::ComposeToExistingSceneColor)
{
PassParameters->RenderTargets[0] = FRenderTargetBinding(NewSceneColor, ERenderTargetLoadAction::ELoad);
}
else
{
PassParameters->RenderTargets[0] = FRenderTargetBinding(NewSceneColor, ERenderTargetLoadAction::ENoAction);
}
if (DepthUpscampling)
{
PassParameters->LowResDepthTexture = TranslucencyTextures.GetDepthForRead(GraphBuilder);
PassParameters->LowResDepthSampler = TStaticSamplerState<SF_Point>::GetRHI();
PassParameters->FullResDepthTexture = SceneDepth.Texture;
PassParameters->FullResDepthSampler = TStaticSamplerState<SF_Point>::GetRHI();
}
FComposeSeparateTranslucencyPS::FPermutationDomain PermutationVector;
PermutationVector.Set<FComposeSeparateTranslucencyPS::FNearestDepthNeighborUpsampling>(DepthUpscampling);
TShaderMapRef<FComposeSeparateTranslucencyPS> PixelShader(View.ShaderMap, PermutationVector);
FPixelShaderUtils::AddFullscreenPass(
GraphBuilder,
View.ShaderMap,
RDG_EVENT_NAME(
"%s(%s%s%s) %dx%d -> %dx%d",
OpName,
kTranslucencyPassName[int32(TranslucencyTextures.Pass)],
bApplyModulateOnly ? TEXT(" ModulateOnly") : TEXT(""),
DepthUpscampling ? TEXT(" DepthUpscampling") : TEXT(""),
TranslucencyTextures.ViewRect.Width(), TranslucencyTextures.ViewRect.Height(),
OutputViewport.Rect.Width(), OutputViewport.Rect.Height()),
PixelShader,
PassParameters,
OutputViewport.Rect,
BlendState);
return FScreenPassTexture(NewSceneColor, OutputViewport.Rect);
}
static void AddUpsampleResponsiveAAPass(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
FScreenPassTexture DownsampledTranslucencyDepth,
FRDGTextureRef OutputDepthTexture)
{
FTranslucencyUpsampleResponsiveAAPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FTranslucencyUpsampleResponsiveAAPS::FParameters>();
PassParameters->StencilPixelPosMin = DownsampledTranslucencyDepth.ViewRect.Min;
PassParameters->StencilPixelPosMax = DownsampledTranslucencyDepth.ViewRect.Max - 1;
PassParameters->SvPositionToStencilPixelCoord = (FScreenTransform::Identity - View.ViewRect.Min) * (FVector2f(DownsampledTranslucencyDepth.ViewRect.Size()) / FVector2f(View.ViewRect.Size())) + DownsampledTranslucencyDepth.ViewRect.Min;
PassParameters->StencilMask = STENCIL_TEMPORAL_RESPONSIVE_AA_MASK;
PassParameters->StencilTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateWithPixelFormat(DownsampledTranslucencyDepth.Texture, PF_X24_G8));
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(OutputDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthNop_StencilWrite);
TShaderMapRef<FScreenVS> VertexShader(View.ShaderMap);
TShaderMapRef<FTranslucencyUpsampleResponsiveAAPS> PixelShader(View.ShaderMap);
FRHIDepthStencilState* DepthStencilState = TStaticDepthStencilState<false, CF_Always,
true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
0x00, STENCIL_TEMPORAL_RESPONSIVE_AA_MASK>::GetRHI();
FRHIBlendState* BlendState = TStaticBlendState<CW_NONE>::GetRHI();
const FScreenPassPipelineState PipelineState(VertexShader, PixelShader, BlendState, DepthStencilState, /* StencilRef = */ STENCIL_TEMPORAL_RESPONSIVE_AA_MASK);
ClearUnusedGraphResources(PixelShader, PassParameters);
GraphBuilder.AddPass(
RDG_EVENT_NAME("UpsampleResponsiveAA %dx%d -> %dx%d",
DownsampledTranslucencyDepth.ViewRect.Width(), DownsampledTranslucencyDepth.ViewRect.Height(),
View.ViewRect.Width(), View.ViewRect.Height()),
PassParameters,
ERDGPassFlags::Raster,
[&View, PipelineState, PixelShader, PassParameters](FRHICommandList& RHICmdList)
{
FScreenPassTextureViewport OutputViewport(PassParameters->RenderTargets.DepthStencil.GetTexture()->Desc.Extent, View.ViewRect);
DrawScreenPass(RHICmdList, View, OutputViewport, OutputViewport, PipelineState, EScreenPassDrawFlags::None, [&](FRHICommandList&)
{
SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
});
});
}
bool FSceneRenderer::ShouldRenderTranslucency() const
{
return ActiveViewFamily->EngineShowFlags.Translucency
&& !ActiveViewFamily->EngineShowFlags.VisualizeLightCulling
&& !ActiveViewFamily->UseDebugViewPS();
}
bool FSceneRenderer::ShouldRenderTranslucency(ETranslucencyPass::Type TranslucencyPass) const
{
extern int32 GLightShaftRenderAfterDOF;
// Change this condition to control where simple elements should be rendered.
if (IsMainTranslucencyPass(TranslucencyPass))
{
for (const FViewInfo& View : Views)
{
if (View.bHasTranslucentViewMeshElements || View.SimpleElementCollector.BatchedElements.HasPrimsToDraw())
{
return true;
}
}
}
// If lightshafts are rendered in low res, we must reset the offscreen buffer in case is was also used in TPT_StandardTranslucency.
if (GLightShaftRenderAfterDOF && TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOF)
{
return true;
}
for (const FViewInfo& View : Views)
{
if (View.TranslucentPrimCount.Num(TranslucencyPass) > 0)
{
return true;
}
}
return false;
}
FScreenPassTextureViewport FSeparateTranslucencyDimensions::GetInstancedStereoViewport(const FViewInfo& View) const
{
FIntRect ViewRect = View.ViewRect;
if (View.IsInstancedStereoPass() && !View.bIsMultiViewEnabled)
{
ViewRect.Max.X = ViewRect.Min.X + View.InstancedStereoWidth;
}
ViewRect = GetScaledRect(ViewRect, Scale);
return FScreenPassTextureViewport(Extent, ViewRect);
}
void SetupPostMotionBlurTranslucencyViewParameters(const FViewInfo& View, FViewUniformShaderParameters& Parameters)
{
// post-motionblur pass without down-sampling requires no Temporal AA jitter
FBox VolumeBounds[TVC_MAX];
FViewMatrices ModifiedViewMatrices = View.ViewMatrices;
ModifiedViewMatrices.HackRemoveTemporalAAProjectionJitter();
Parameters = *View.CachedViewUniformShaderParameters;
View.SetupUniformBufferParameters(ModifiedViewMatrices, ModifiedViewMatrices, VolumeBounds, TVC_MAX, Parameters);
}
FRDGTextureMSAA CreatePostDOFTranslucentTexture(
FRDGBuilder& GraphBuilder,
ETranslucencyPass::Type TranslucencyPass,
FSeparateTranslucencyDimensions& SeparateTranslucencyDimensions,
bool bIsModulate,
EShaderPlatform ShaderPlatform)
{
const bool bNeedUAV = SeparateTranslucencyDimensions.NumSamples == 1 && OIT::IsEnabled(EOITSortingType::SortedPixels, ShaderPlatform);
const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(
SeparateTranslucencyDimensions.Extent,
bIsModulate ? PF_FloatR11G11B10 : PF_FloatRGBA,
bIsModulate ? FClearValueBinding::White : FClearValueBinding::Black,
TexCreate_RenderTargetable | TexCreate_ShaderResource | (bNeedUAV ? TexCreate_UAV : TexCreate_None),
1,
SeparateTranslucencyDimensions.NumSamples);
return CreateTextureMSAA(
GraphBuilder, Desc,
kTranslucencyColorTextureName[int32(TranslucencyPass)],
bIsModulate ? GFastVRamConfig.SeparateTranslucencyModulate : GFastVRamConfig.SeparateTranslucency);
}
void SetupDownsampledTranslucencyViewParameters(
const FViewInfo& View,
FIntPoint TextureExtent,
FIntRect ViewRect,
ETranslucencyPass::Type TranslucencyPass,
FViewUniformShaderParameters& DownsampledTranslucencyViewParameters)
{
DownsampledTranslucencyViewParameters = *View.CachedViewUniformShaderParameters;
FViewMatrices ViewMatrices = View.ViewMatrices;
FViewMatrices PrevViewMatrices = View.PrevViewInfo.ViewMatrices;
if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur)
{
// Remove jitter from this pass
ViewMatrices.HackRemoveTemporalAAProjectionJitter();
PrevViewMatrices.HackRemoveTemporalAAProjectionJitter();
}
// Update the parts of DownsampledTranslucencyParameters which are dependent on the buffer size and view rect
View.SetupViewRectUniformBufferParameters(
DownsampledTranslucencyViewParameters,
TextureExtent,
ViewRect,
ViewMatrices,
PrevViewMatrices);
// instead of using the expected ratio, use the actual dimensions to avoid rounding errors
float ActualDownsampleX = float(ViewRect.Width()) / float(View.ViewRect.Width());
float ActualDownsampleY = float(ViewRect.Height()) / float(View.ViewRect.Height());
DownsampledTranslucencyViewParameters.LightProbeSizeRatioAndInvSizeRatio = FVector4f(ActualDownsampleX, ActualDownsampleY, 1.0f / ActualDownsampleX, 1.0f / ActualDownsampleY);
DownsampledTranslucencyViewParameters.BufferToSceneTextureScale = FVector2f(1.0f / ActualDownsampleX, 1.0f / ActualDownsampleY);
}
TRDGUniformBufferRef<FTranslucentBasePassUniformParameters> CreateTranslucentBasePassUniformBuffer(
FRDGBuilder& GraphBuilder,
const FScene* Scene,
const FViewInfo& View,
const int32 ViewIndex,
const FTranslucencyLightingVolumeTextures& TranslucencyLightingVolumeTextures,
FRDGTextureRef SceneColorCopyTexture,
const ESceneTextureSetupMode SceneTextureSetupMode,
bool bLumenGIEnabled,
const FOITData& OITData)
{
FTranslucentBasePassUniformParameters& BasePassParameters = *GraphBuilder.AllocParameters<FTranslucentBasePassUniformParameters>();
const auto GetRDG = [&](const TRefCountPtr<IPooledRenderTarget>& PooledRenderTarget, ERDGTextureFlags Flags = ERDGTextureFlags::None)
{
return GraphBuilder.RegisterExternalTexture(PooledRenderTarget, Flags);
};
SetupSharedBasePassParameters(GraphBuilder, View, bLumenGIEnabled, BasePassParameters.Shared);
SetupSceneTextureUniformParameters(GraphBuilder, View.GetSceneTexturesChecked(), View.FeatureLevel, SceneTextureSetupMode, BasePassParameters.SceneTextures);
Strata::BindStrataForwardPasslUniformParameters(GraphBuilder, View, BasePassParameters.Strata);
const FLightSceneProxy* SelectedForwardDirectionalLightProxy = View.ForwardLightingResources.SelectedForwardDirectionalLightProxy;
SetupLightCloudTransmittanceParameters(GraphBuilder, Scene, View, SelectedForwardDirectionalLightProxy ? SelectedForwardDirectionalLightProxy->GetLightSceneInfo() : nullptr, BasePassParameters.ForwardDirLightCloudShadow);
const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);
// Material SSR
{
float PrevSceneColorPreExposureInvValue = 1.0f / View.PreExposure;
if (View.HZB)
{
BasePassParameters.HZBTexture = View.HZB;
BasePassParameters.HZBSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
FRDGTextureRef PrevSceneColorTexture = SystemTextures.Black;
FIntRect PrevSceneColorViewRect = FIntRect(0, 0, 1, 1);
if (View.PrevViewInfo.CustomSSRInput.IsValid())
{
PrevSceneColorTexture = GetRDG(View.PrevViewInfo.CustomSSRInput.RT[0]);
PrevSceneColorViewRect = View.PrevViewInfo.CustomSSRInput.ViewportRect;
PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure;
}
else if (View.PrevViewInfo.TemporalAAHistory.IsValid())
{
PrevSceneColorTexture = GetRDG(View.PrevViewInfo.TemporalAAHistory.RT[0]);
PrevSceneColorViewRect = View.PrevViewInfo.TemporalAAHistory.ViewportRect;
PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure;
}
else if (View.PrevViewInfo.ScreenSpaceRayTracingInput.IsValid())
{
PrevSceneColorTexture = GetRDG(View.PrevViewInfo.ScreenSpaceRayTracingInput);
PrevSceneColorViewRect = View.PrevViewInfo.ViewRect;
PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure;
}
BasePassParameters.PrevSceneColor = PrevSceneColorTexture;
BasePassParameters.PrevSceneColorSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
FScreenPassTextureViewportParameters PrevSceneColorParameters = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(PrevSceneColorTexture, PrevSceneColorViewRect));
BasePassParameters.PrevSceneColorBilinearUVMin = PrevSceneColorParameters.UVViewportBilinearMin;
BasePassParameters.PrevSceneColorBilinearUVMax = PrevSceneColorParameters.UVViewportBilinearMax;
const FVector2f HZBUvFactor(
float(View.ViewRect.Width()) / float(2 * View.HZBMipmap0Size.X),
float(View.ViewRect.Height()) / float(2 * View.HZBMipmap0Size.Y)
);
const FVector4f HZBUvFactorAndInvFactorValue(
HZBUvFactor.X,
HZBUvFactor.Y,
1.0f / HZBUvFactor.X,
1.0f / HZBUvFactor.Y
);
BasePassParameters.HZBUvFactorAndInvFactor = HZBUvFactorAndInvFactorValue;
}
else
{
BasePassParameters.HZBTexture = SystemTextures.Black;
BasePassParameters.HZBSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
BasePassParameters.PrevSceneColor = SystemTextures.Black;
BasePassParameters.PrevSceneColorSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
BasePassParameters.PrevSceneColorBilinearUVMin = FVector2f(0.0f, 0.0f);
BasePassParameters.PrevSceneColorBilinearUVMax = FVector2f(1.0f, 1.0f);
}
BasePassParameters.ApplyVolumetricCloudOnTransparent = 0.0f;
BasePassParameters.VolumetricCloudColor = nullptr;
BasePassParameters.VolumetricCloudDepth = nullptr;
BasePassParameters.VolumetricCloudColorSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
BasePassParameters.VolumetricCloudDepthSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
if (IsVolumetricRenderTargetEnabled() && View.ViewState)
{
TRefCountPtr<IPooledRenderTarget> VolumetricReconstructRT = View.ViewState->VolumetricCloudRenderTarget.GetDstVolumetricReconstructRT();
if (VolumetricReconstructRT.IsValid())
{
TRefCountPtr<IPooledRenderTarget> VolumetricReconstructRTDepth = View.ViewState->VolumetricCloudRenderTarget.GetDstVolumetricReconstructRTDepth();
BasePassParameters.VolumetricCloudColor = VolumetricReconstructRT->GetRHI();
BasePassParameters.VolumetricCloudDepth = VolumetricReconstructRTDepth->GetRHI();
BasePassParameters.ApplyVolumetricCloudOnTransparent = 1.0f;
}
}
if (BasePassParameters.VolumetricCloudColor == nullptr)
{
BasePassParameters.VolumetricCloudColor = GSystemTextures.BlackAlphaOneDummy->GetRHI();
BasePassParameters.VolumetricCloudDepth = GSystemTextures.BlackDummy->GetRHI();
}
FIntPoint ViewportOffset = View.ViewRect.Min;
FIntPoint ViewportExtent = View.ViewRect.Size();
// Scene render targets might not exist yet; avoids NaNs.
FIntPoint EffectiveBufferSize = View.GetSceneTexturesConfig().Extent;
EffectiveBufferSize.X = FMath::Max(EffectiveBufferSize.X, 1);
EffectiveBufferSize.Y = FMath::Max(EffectiveBufferSize.Y, 1);
if (View.PrevViewInfo.CustomSSRInput.IsValid())
{
ViewportOffset = View.PrevViewInfo.CustomSSRInput.ViewportRect.Min;
ViewportExtent = View.PrevViewInfo.CustomSSRInput.ViewportRect.Size();
EffectiveBufferSize = View.PrevViewInfo.CustomSSRInput.RT[0]->GetDesc().Extent;
}
else if (View.PrevViewInfo.TemporalAAHistory.IsValid())
{
ViewportOffset = View.PrevViewInfo.TemporalAAHistory.ViewportRect.Min;
ViewportExtent = View.PrevViewInfo.TemporalAAHistory.ViewportRect.Size();
EffectiveBufferSize = View.PrevViewInfo.TemporalAAHistory.RT[0]->GetDesc().Extent;
}
else if (View.PrevViewInfo.ScreenSpaceRayTracingInput.IsValid())
{
ViewportOffset = View.PrevViewInfo.ViewRect.Min;
ViewportExtent = View.PrevViewInfo.ViewRect.Size();
EffectiveBufferSize = View.PrevViewInfo.ScreenSpaceRayTracingInput->GetDesc().Extent;
}
FVector2f InvBufferSize(1.0f / float(EffectiveBufferSize.X), 1.0f / float(EffectiveBufferSize.Y));
FVector4f ScreenPosToPixelValue(
ViewportExtent.X * 0.5f * InvBufferSize.X,
-ViewportExtent.Y * 0.5f * InvBufferSize.Y,
(ViewportExtent.X * 0.5f + ViewportOffset.X) * InvBufferSize.X,
(ViewportExtent.Y * 0.5f + ViewportOffset.Y) * InvBufferSize.Y);
BasePassParameters.PrevScreenPositionScaleBias = ScreenPosToPixelValue;
BasePassParameters.PrevSceneColorPreExposureInv = PrevSceneColorPreExposureInvValue;
BasePassParameters.SSRQuality = ShouldRenderTranslucencyScreenSpaceReflections(View) ? GetSSRQuality() : 0;
}
// Translucency Lighting Volume
BasePassParameters.TranslucencyLightingVolume = GetTranslucencyLightingVolumeParameters(GraphBuilder, TranslucencyLightingVolumeTextures, View);
BasePassParameters.LumenParameters = GetLumenTranslucencyLightingParameters(GraphBuilder, View.LumenTranslucencyGIVolume, View.LumenFrontLayerTranslucency);
const bool bLumenGIHandlingSkylight = bLumenGIEnabled
&& BasePassParameters.LumenParameters.TranslucencyGIGridSize.Z > 0;
BasePassParameters.Shared.UseBasePassSkylight = bLumenGIHandlingSkylight ? 0 : 1;
BasePassParameters.SceneColorCopyTexture = SystemTextures.Black;
BasePassParameters.SceneColorCopySampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
if (SceneColorCopyTexture)
{
BasePassParameters.SceneColorCopyTexture = SceneColorCopyTexture;
}
BasePassParameters.EyeAdaptationTexture = GetEyeAdaptationTexture(GraphBuilder, View);
BasePassParameters.PreIntegratedGFTexture = GSystemTextures.PreintegratedGF->GetRHI();
BasePassParameters.PreIntegratedGFSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
OIT::SetOITParameters(GraphBuilder, View, BasePassParameters.OIT, OITData);
return GraphBuilder.CreateUniformBuffer(&BasePassParameters);
}
TRDGUniformBufferRef<FTranslucentBasePassUniformParameters> CreateTranslucentBasePassUniformBuffer(
FRDGBuilder& GraphBuilder,
const FScene* Scene,
const FViewInfo& View,
const int32 ViewIndex,
const FTranslucencyLightingVolumeTextures& TranslucencyLightingVolumeTextures,
FRDGTextureRef SceneColorCopyTexture,
const ESceneTextureSetupMode SceneTextureSetupMode,
bool bLumenGIEnabled)
{
FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_None);
return CreateTranslucentBasePassUniformBuffer(
GraphBuilder,
Scene,
View,
ViewIndex,
TranslucencyLightingVolumeTextures,
SceneColorCopyTexture,
SceneTextureSetupMode,
bLumenGIEnabled,
OITData);
}
static FViewShaderParameters GetSeparateTranslucencyViewParameters(const FViewInfo& View, FIntPoint TextureExtent, float ViewportScale, ETranslucencyPass::Type TranslucencyPass)
{
FViewShaderParameters ViewParameters;
const bool bIsPostMotionBlur = (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur);
if (ViewportScale == 1.0f && !bIsPostMotionBlur)
{
// We can use the existing view uniform buffers if no downsampling is required and is not in the post-motionblur pass
ViewParameters = View.GetShaderParameters();
}
else if (bIsPostMotionBlur)
{
// Full-scale post-motionblur pass
FViewUniformShaderParameters ViewUniformParameters;
SetupPostMotionBlurTranslucencyViewParameters(View, ViewUniformParameters);
ViewParameters.View = TUniformBufferRef<FViewUniformShaderParameters>::CreateUniformBufferImmediate(ViewUniformParameters, UniformBuffer_SingleFrame);
if (const FViewInfo* InstancedView = View.GetInstancedView())
{
SetupPostMotionBlurTranslucencyViewParameters(*InstancedView, ViewUniformParameters);
ViewParameters.InstancedView = TUniformBufferRef<FInstancedViewUniformShaderParameters>::CreateUniformBufferImmediate(
reinterpret_cast<const FInstancedViewUniformShaderParameters&>(ViewUniformParameters),
UniformBuffer_SingleFrame);
}
}
else
{
// Downsampled post-DOF or post-motionblur pass
FViewUniformShaderParameters DownsampledTranslucencyViewParameters;
SetupDownsampledTranslucencyViewParameters(
View,
TextureExtent,
GetScaledRect(View.ViewRect, ViewportScale),
TranslucencyPass,
DownsampledTranslucencyViewParameters);
ViewParameters.View = TUniformBufferRef<FViewUniformShaderParameters>::CreateUniformBufferImmediate(DownsampledTranslucencyViewParameters, UniformBuffer_SingleFrame);
if (const FViewInfo* InstancedView = View.GetInstancedView())
{
SetupDownsampledTranslucencyViewParameters(
*InstancedView,
TextureExtent,
GetScaledRect(InstancedView->ViewRect, ViewportScale),
TranslucencyPass,
DownsampledTranslucencyViewParameters);
ViewParameters.InstancedView = TUniformBufferRef<FInstancedViewUniformShaderParameters>::CreateUniformBufferImmediate(
reinterpret_cast<const FInstancedViewUniformShaderParameters&>(DownsampledTranslucencyViewParameters),
UniformBuffer_SingleFrame);
}
}
return ViewParameters;
}
static void RenderViewTranslucencyInner(
FRHICommandListImmediate& RHICmdList,
const FSceneRenderer& SceneRenderer,
const FViewInfo& View,
const FScreenPassTextureViewport Viewport,
const float ViewportScale,
ETranslucencyPass::Type TranslucencyPass,
FRDGParallelCommandListSet* ParallelCommandListSet,
const FInstanceCullingDrawParams& InstanceCullingDrawParams)
{
FMeshPassProcessorRenderState DrawRenderState;
if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur)
{
// No depth test in post-motionblur translucency
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
}
else
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
}
SceneRenderer.SetStereoViewport(RHICmdList, View, ViewportScale);
if (!View.Family->UseDebugViewPS())
{
QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_Start_FDrawSortedTransAnyThreadTask);
const EMeshPass::Type MeshPass = TranslucencyPassToMeshPass(TranslucencyPass);
View.ParallelMeshDrawCommandPasses[MeshPass].DispatchDraw(ParallelCommandListSet, RHICmdList, &InstanceCullingDrawParams);
}
if (IsMainTranslucencyPass(TranslucencyPass))
{
if (ParallelCommandListSet)
{
ParallelCommandListSet->SetStateOnCommandList(RHICmdList);
}
View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, EBlendModeFilter::Translucent, SDPG_World);
View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, EBlendModeFilter::Translucent, SDPG_Foreground);
// editor and debug rendering
if (View.bHasTranslucentViewMeshElements)
{
{
QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_SDPG_World);
DrawDynamicMeshPass(View, RHICmdList,
[&View, &DrawRenderState, TranslucencyPass](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
{
FBasePassMeshProcessor PassMeshProcessor(
View.Family->Scene->GetRenderScene(),
View.GetFeatureLevel(),
&View,
DrawRenderState,
DynamicMeshPassContext,
FBasePassMeshProcessor::EFlags::CanUseDepthStencil,
TranslucencyPass);
const uint64 DefaultBatchElementMask = ~0ull;
for (int32 MeshIndex = 0; MeshIndex < View.ViewMeshElements.Num(); MeshIndex++)
{
const FMeshBatch& MeshBatch = View.ViewMeshElements[MeshIndex];
PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);
}
});
}
{
QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_SDPG_Foreground);
DrawDynamicMeshPass(View, RHICmdList,
[&View, &DrawRenderState, TranslucencyPass](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
{
FBasePassMeshProcessor PassMeshProcessor(
View.Family->Scene->GetRenderScene(),
View.GetFeatureLevel(),
&View,
DrawRenderState,
DynamicMeshPassContext,
FBasePassMeshProcessor::EFlags::CanUseDepthStencil,
TranslucencyPass);
const uint64 DefaultBatchElementMask = ~0ull;
for (int32 MeshIndex = 0; MeshIndex < View.TopViewMeshElements.Num(); MeshIndex++)
{
const FMeshBatch& MeshBatch = View.TopViewMeshElements[MeshIndex];
PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);
}
});
}
}
if (ParallelCommandListSet)
{
RHICmdList.EndRenderPass();
}
}
}
BEGIN_SHADER_PARAMETER_STRUCT(FTranslucentBasePassParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
SHADER_PARAMETER_STRUCT_REF(FReflectionCaptureShaderData, ReflectionCapture)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FTranslucentBasePassUniformParameters, BasePass)
SHADER_PARAMETER_STRUCT_INCLUDE(FInstanceCullingDrawParams, InstanceCullingDrawParams)
SHADER_PARAMETER_STRUCT_INCLUDE(FVirtualShadowMapSamplingParameters, VirtualShadowMapSamplingParameters)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static void RenderTranslucencyViewInner(
FRDGBuilder& GraphBuilder,
const FSceneRenderer& SceneRenderer,
FViewInfo& View,
FScreenPassTextureViewport Viewport,
float ViewportScale,
FRDGTextureMSAA SceneColorTexture,
ERenderTargetLoadAction SceneColorLoadAction,
FRDGTextureRef SceneDepthTexture,
TRDGUniformBufferRef<FTranslucentBasePassUniformParameters> BasePassParameters,
ETranslucencyPass::Type TranslucencyPass,
bool bResolveColorTexture,
bool bRenderInParallel,
FInstanceCullingManager& InstanceCullingManager)
{
if (!View.ShouldRenderView())
{
return;
}
if (SceneColorLoadAction == ERenderTargetLoadAction::EClear)
{
AddClearRenderTargetPass(GraphBuilder, SceneColorTexture.Target);
}
View.BeginRenderView();
FTranslucentBasePassParameters* PassParameters = GraphBuilder.AllocParameters<FTranslucentBasePassParameters>();
PassParameters->View = GetSeparateTranslucencyViewParameters(View, Viewport.Extent, ViewportScale, TranslucencyPass);
PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
PassParameters->BasePass = BasePassParameters;
PassParameters->VirtualShadowMapSamplingParameters = SceneRenderer.ActiveViewFamily->VirtualShadowMapArray.GetSamplingParameters(GraphBuilder);
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture.Target, ERenderTargetLoadAction::ELoad);
if (TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterMotionBlur)
{
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(SceneDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilWrite);
}
PassParameters->RenderTargets.ShadingRateTexture = GVRSImageManager.GetVariableRateShadingImage(GraphBuilder, *SceneRenderer.ActiveViewFamily, nullptr);
PassParameters->RenderTargets.ResolveRect = FResolveRect(Viewport.Rect);
const EMeshPass::Type MeshPass = TranslucencyPassToMeshPass(TranslucencyPass);
View.ParallelMeshDrawCommandPasses[MeshPass].BuildRenderingCommands(GraphBuilder, SceneRenderer.Scene->GPUScene, PassParameters->InstanceCullingDrawParams);
if (bRenderInParallel)
{
GraphBuilder.AddPass(
RDG_EVENT_NAME("Translucency(%s Parallel) %dx%d",
TranslucencyPassToString(TranslucencyPass),
int32(View.ViewRect.Width() * ViewportScale),
int32(View.ViewRect.Height() * ViewportScale)),
PassParameters,
ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass,
[&SceneRenderer, &View, PassParameters, ViewportScale, Viewport, TranslucencyPass](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList)
{
FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_Translucency), SceneRenderer, View, FParallelCommandListBindings(PassParameters), ViewportScale);
RenderViewTranslucencyInner(RHICmdList, SceneRenderer, View, Viewport, ViewportScale, TranslucencyPass, &ParallelCommandListSet, PassParameters->InstanceCullingDrawParams);
});
}
else
{
GraphBuilder.AddPass(
RDG_EVENT_NAME("Translucency(%s) %dx%d",
TranslucencyPassToString(TranslucencyPass),
int32(View.ViewRect.Width() * ViewportScale),
int32(View.ViewRect.Height() * ViewportScale)),
PassParameters,
ERDGPassFlags::Raster,
[&SceneRenderer, &View, ViewportScale, Viewport, TranslucencyPass, PassParameters](FRHICommandListImmediate& RHICmdList)
{
RenderViewTranslucencyInner(RHICmdList, SceneRenderer, View, Viewport, ViewportScale, TranslucencyPass, nullptr, PassParameters->InstanceCullingDrawParams);
});
}
if (bResolveColorTexture)
{
AddResolveSceneColorPass(GraphBuilder, View, SceneColorTexture);
}
}
void FDeferredShadingSceneRenderer::RenderTranslucencyInner(
FRDGBuilder& GraphBuilder,
const FMinimalSceneTextures& SceneTextures,
const FTranslucencyLightingVolumeTextures& TranslucentLightingVolumeTextures,
FTranslucencyPassResourcesMap* OutTranslucencyResourceMap,
FRDGTextureMSAA SharedDepthTexture,
ETranslucencyView ViewsToRender,
FRDGTextureRef SceneColorCopyTexture,
ETranslucencyPass::Type TranslucencyPass,
FInstanceCullingManager& InstanceCullingManager)
{
if (!ShouldRenderTranslucency(TranslucencyPass))
{
return;
}
RDG_WAIT_FOR_TASKS_CONDITIONAL(GraphBuilder, IsTranslucencyWaitForTasksEnabled());
const bool bIsModulate = TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate;
const bool bDepthTest = TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterMotionBlur;
const bool bRenderInParallel = IsParallelTranslucencyEnabled();
const bool bIsScalingTranslucency = SeparateTranslucencyDimensions.Scale < 1.0f;
const bool bRenderInSeparateTranslucency = IsSeparateTranslucencyEnabled(TranslucencyPass, SeparateTranslucencyDimensions.Scale);
// Can't reference scene color in scene textures. Scene color copy is used instead.
ESceneTextureSetupMode SceneTextureSetupMode = ESceneTextureSetupMode::All;
EnumRemoveFlags(SceneTextureSetupMode, ESceneTextureSetupMode::SceneColor);
if (bRenderInSeparateTranslucency)
{
// Create resources shared by each view (each view data is tiled into each of the render target resources)
FRDGTextureMSAA SharedColorTexture = CreatePostDOFTranslucentTexture(GraphBuilder, TranslucencyPass, SeparateTranslucencyDimensions, bIsModulate, ShaderPlatform);
for (int32 ViewIndex = 0, NumProcessedViews = 0; ViewIndex < Views.Num(); ++ViewIndex, ++NumProcessedViews)
{
FViewInfo& View = Views[ViewIndex];
const ETranslucencyView TranslucencyView = GetTranslucencyView(View);
if (!EnumHasAnyFlags(TranslucencyView, ViewsToRender))
{
continue;
}
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
FIntRect ScaledViewRect = GetScaledRect(View.ViewRect, SeparateTranslucencyDimensions.Scale);
const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View);
const bool bCompositeBackToSceneColor = IsMainTranslucencyPass(TranslucencyPass) || EnumHasAnyFlags(TranslucencyView, ETranslucencyView::UnderWater);
const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen;
/** Separate translucency color is either composited immediately or later during post processing. If done immediately, it's because the view doesn't support
* compositing (e.g. we're rendering an underwater view) or because we're downsampling the main translucency pass. In this case, we use a local set of
* textures instead of the external ones passed in.
*/
FRDGTextureMSAA SeparateTranslucencyColorTexture = SharedColorTexture;
// NOTE: No depth test on post-motionblur translucency
FRDGTextureMSAA SeparateTranslucencyDepthTexture;
if (bDepthTest)
{
SeparateTranslucencyDepthTexture = SharedDepthTexture;
}
const ERenderTargetLoadAction SeparateTranslucencyColorLoadAction = NumProcessedViews == 0 || View.Family->bMultiGPUForkAndJoin
? ERenderTargetLoadAction::EClear
: ERenderTargetLoadAction::ELoad;
FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_SeperateTranslucency);
RenderTranslucencyViewInner(
GraphBuilder,
*this,
View,
SeparateTranslucencyViewport,
SeparateTranslucencyDimensions.Scale,
SeparateTranslucencyColorTexture,
SeparateTranslucencyColorLoadAction,
SeparateTranslucencyDepthTexture.Target,
CreateTranslucentBasePassUniformBuffer(GraphBuilder, Scene, View, ViewIndex, TranslucentLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData),
TranslucencyPass,
!bCompositeBackToSceneColor,
bRenderInParallel,
InstanceCullingManager);
{
FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass);
TranslucencyPassResources.ViewRect = ScaledViewRect;
TranslucencyPassResources.ColorTexture = SharedColorTexture;
TranslucencyPassResources.DepthTexture = SharedDepthTexture;
}
if (OITData.PassType & OITPass_SeperateTranslucency)
{
OIT::AddOITComposePass(GraphBuilder, View, OITData, SeparateTranslucencyColorTexture.Target);
}
if (bCompositeBackToSceneColor)
{
FRDGTextureRef SeparateTranslucencyDepthResolve = nullptr;
FRDGTextureRef SceneDepthResolve = nullptr;
if (TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterMotionBlur)
{
::AddResolveSceneDepthPass(GraphBuilder, View, SeparateTranslucencyDepthTexture);
SeparateTranslucencyDepthResolve = SeparateTranslucencyDepthTexture.Resolve;
SceneDepthResolve = SceneTextures.Depth.Resolve;
}
FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass);
FTranslucencyComposition TranslucencyComposition;
TranslucencyComposition.Operation = FTranslucencyComposition::EOperation::ComposeToExistingSceneColor;
TranslucencyComposition.SceneColor = FScreenPassTexture(SceneTextures.Color.Target, View.ViewRect);
TranslucencyComposition.SceneDepth = FScreenPassTexture(SceneTextures.Depth.Resolve, View.ViewRect);
TranslucencyComposition.OutputViewport = FScreenPassTextureViewport(SceneTextures.Depth.Resolve, View.ViewRect);
FScreenPassTexture UpscaledTranslucency = TranslucencyComposition.AddPass(
GraphBuilder, View, TranslucencyPassResources);
ensure(View.ViewRect == UpscaledTranslucency.ViewRect);
ensure(UpscaledTranslucency.Texture == SceneTextures.Color.Target);
//Invalidate.
TranslucencyPassResources = FTranslucencyPassResources();
}
else
{
if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate)
{
FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, ETranslucencyPass::TPT_TranslucencyAfterDOF);
ensure(TranslucencyPassResources.ViewRect == ScaledViewRect);
ensure(TranslucencyPassResources.DepthTexture == SharedDepthTexture);
TranslucencyPassResources.ColorModulateTexture = SharedColorTexture;
}
else
{
check(!bIsModulate);
}
}
++NumProcessedViews;
}
}
else
{
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
const ETranslucencyView TranslucencyView = GetTranslucencyView(View);
if (!EnumHasAnyFlags(TranslucencyView, ViewsToRender))
{
continue;
}
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
const ERenderTargetLoadAction SceneColorLoadAction = ERenderTargetLoadAction::ELoad;
const FScreenPassTextureViewport Viewport(SceneTextures.Color.Target, View.ViewRect);
const float ViewportScale = 1.0f;
const bool bResolveColorTexture = false;
const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen;
FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_RegularTranslucency);
RenderTranslucencyViewInner(
GraphBuilder,
*this,
View,
Viewport,
ViewportScale,
SceneTextures.Color,
SceneColorLoadAction,
SceneTextures.Depth.Target,
CreateTranslucentBasePassUniformBuffer(GraphBuilder, Scene, View, ViewIndex, TranslucentLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData),
TranslucencyPass,
bResolveColorTexture,
bRenderInParallel,
InstanceCullingManager);
if (OITData.PassType & OITPass_RegularTranslucency)
{
OIT::AddOITComposePass(GraphBuilder, View, OITData, SceneTextures.Color.Target);
}
}
}
}
void FDeferredShadingSceneRenderer::RenderTranslucency(
FRDGBuilder& GraphBuilder,
const FMinimalSceneTextures& SceneTextures,
const FTranslucencyLightingVolumeTextures& TranslucentLightingVolumeTextures,
FTranslucencyPassResourcesMap* OutTranslucencyResourceMap,
ETranslucencyView ViewsToRender,
FInstanceCullingManager& InstanceCullingManager)
{
if (!EnumHasAnyFlags(ViewsToRender, ETranslucencyView::UnderWater | ETranslucencyView::AboveWater))
{
return;
}
RDG_GPU_STAT_SCOPE(GraphBuilder, Translucency);
DynamicRenderScaling::FRDGScope DynamicTranslucencyResolutionScope(GraphBuilder, GDynamicTranslucencyResolution);
FRDGTextureRef SceneColorCopyTexture = nullptr;
if (EnumHasAnyFlags(ViewsToRender, ETranslucencyView::AboveWater))
{
SceneColorCopyTexture = AddCopySceneColorPass(GraphBuilder, Views, SceneTextures.Color);
}
const auto ShouldRenderView = [&](const FViewInfo& View, ETranslucencyView TranslucencyView)
{
return View.ShouldRenderView() && EnumHasAnyFlags(TranslucencyView, ViewsToRender);
};
// Create a shared depth texture at the correct resolution.
FRDGTextureMSAA SharedDepthTexture;
const bool bIsScalingTranslucency = SeparateTranslucencyDimensions.Scale != 1.0f;
if (bIsScalingTranslucency)
{
const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(
SeparateTranslucencyDimensions.Extent,
PF_DepthStencil,
FClearValueBinding::DepthFar,
TexCreate_DepthStencilTargetable | TexCreate_ShaderResource,
1,
SeparateTranslucencyDimensions.NumSamples);
SharedDepthTexture = CreateTextureMSAA(
GraphBuilder, Desc,
TEXT("Translucency.Depth"),
GFastVRamConfig.SeparateTranslucencyModulate); // TODO: this should be SeparateTranslucency, but is what the code was doing
// Downscale the depth buffer for each individual view, but shared accross all translucencies.
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
const ETranslucencyView TranslucencyView = GetTranslucencyView(View);
if (!ShouldRenderView(View, TranslucencyView))
{
continue;
}
const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View);
AddDownsampleDepthPass(
GraphBuilder, View,
FScreenPassTexture(SceneTextures.Depth.Resolve, View.ViewRect),
FScreenPassRenderTarget(SharedDepthTexture.Target, SeparateTranslucencyViewport.Rect, ViewIndex == 0 ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad),
EDownsampleDepthFilter::Point);
}
}
else
{
// Uses the existing depth buffer for depth testing the translucency.
SharedDepthTexture = SceneTextures.Depth;
}
if (ActiveViewFamily->AllowTranslucencyAfterDOF())
{
RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_StandardTranslucency, InstanceCullingManager);
if (GetHairStrandsComposition() == EHairStrandsCompositionType::AfterTranslucentBeforeTranslucentAfterDOF)
{
RenderHairComposition(GraphBuilder, Views, SceneTextures.Color.Target, SceneTextures.Depth.Target);
}
RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterDOF, InstanceCullingManager);
RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterDOFModulate, InstanceCullingManager);
RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterMotionBlur, InstanceCullingManager);
}
else // Otherwise render translucent primitives in a single bucket.
{
RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_AllTranslucency, InstanceCullingManager);
}
bool bUpscalePostDOFTranslucency = true;
FRDGTextureRef SharedUpscaledPostDOFTranslucencyColor = nullptr;
if (bUpscalePostDOFTranslucency)
{
const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(
SceneTextures.Color.Resolve->Desc.Extent,
PF_FloatRGBA,
FClearValueBinding::Black,
TexCreate_RenderTargetable | TexCreate_ShaderResource);
SharedUpscaledPostDOFTranslucencyColor = GraphBuilder.CreateTexture(
Desc, TEXT("Translucency.PostDOF.UpscaledColor"));
}
// Upscale to full res.
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
const ETranslucencyView TranslucencyView = GetTranslucencyView(View);
if (!ShouldRenderView(View, TranslucencyView))
{
continue;
}
// Upscale the responsive AA into original depth buffer.
bool bUpscaleResponsiveAA = (
IsTemporalAccumulationBasedMethod(View.AntiAliasingMethod) &&
SharedDepthTexture.Target != SceneTextures.Depth.Target);
if (bUpscaleResponsiveAA)
{
const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View);
AddUpsampleResponsiveAAPass(
GraphBuilder,
View,
FScreenPassTexture(SharedDepthTexture.Target, SeparateTranslucencyViewport.Rect),
/* OutputDepthTexture = */ SceneTextures.Depth.Target);
}
FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, ETranslucencyPass::TPT_TranslucencyAfterDOF);
if (SharedUpscaledPostDOFTranslucencyColor && TranslucencyPassResources.IsValid() && TranslucencyPassResources.ViewRect.Size() != View.ViewRect.Size() && ITemporalUpscaler::GetMainTAAPassConfig(View) != EMainTAAPassConfig::TSR)
{
FTranslucencyComposition TranslucencyComposition;
TranslucencyComposition.Operation = FTranslucencyComposition::EOperation::UpscaleOnly;
TranslucencyComposition.SceneDepth = FScreenPassTexture(SceneTextures.Depth.Resolve, View.ViewRect);
TranslucencyComposition.OutputViewport = FScreenPassTextureViewport(SceneTextures.Depth.Resolve, View.ViewRect);
FScreenPassTexture UpscaledTranslucency = TranslucencyComposition.AddPass(
GraphBuilder, View, TranslucencyPassResources);
TranslucencyPassResources.ViewRect = UpscaledTranslucency.ViewRect;
TranslucencyPassResources.ColorTexture = FRDGTextureMSAA(UpscaledTranslucency.Texture);
TranslucencyPassResources.DepthTexture = FRDGTextureMSAA();
}
}
}