Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp
zach bethel 2103b268d4 Clean up of base pass uniform buffers to only include RDG versions.
#rb christopher.waters
#rnx

[CL 14636107 by zach bethel in ue5-main branch]
2020-11-02 16:51:34 -04:00

1154 lines
47 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 "Lumen/LumenTranslucencyVolumeLighting.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> CVarSeparateTranslucencyAutoDownsample(
TEXT("r.SeparateTranslucencyAutoDownsample"),
0,
TEXT("Whether to automatically downsample separate translucency based on last frame's GPU time.\n")
TEXT("Automatic downsampling is only used when r.SeparateTranslucencyScreenPercentage is 100"),
ECVF_Scalability | ECVF_Default);
static TAutoConsoleVariable<float> CVarSeparateTranslucencyDurationDownsampleThreshold(
TEXT("r.SeparateTranslucencyDurationDownsampleThreshold"),
1.5f,
TEXT("When smoothed full-res translucency GPU duration is larger than this value (ms), the entire pass will be downsampled by a factor of 2 in each dimension."),
ECVF_Scalability | ECVF_Default);
static TAutoConsoleVariable<float> CVarSeparateTranslucencyDurationUpsampleThreshold(
TEXT("r.SeparateTranslucencyDurationUpsampleThreshold"),
.5f,
TEXT("When smoothed half-res translucency GPU duration is smaller than this value (ms), the entire pass will be restored to full resolution.\n")
TEXT("This should be around 1/4 of r.SeparateTranslucencyDurationDownsampleThreshold to avoid toggling downsampled state constantly."),
ECVF_Scalability | ECVF_Default);
static TAutoConsoleVariable<float> CVarSeparateTranslucencyMinDownsampleChangeTime(
TEXT("r.SeparateTranslucencyMinDownsampleChangeTime"),
1.0f,
TEXT("Minimum time in seconds between changes to automatic downsampling state, used to prevent rapid swapping between half and full res."),
ECVF_Scalability | 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);
static const TCHAR* TranslucencyPassToString(ETranslucencyPass::Type TranslucencyPass)
{
switch (TranslucencyPass)
{
case ETranslucencyPass::TPT_StandardTranslucency:
return TEXT("Standard");
case ETranslucencyPass::TPT_TranslucencyAfterDOF:
return TEXT("AfterDOF");
case ETranslucencyPass::TPT_TranslucencyAfterDOFModulate:
return TEXT("AfterDOFModulate");
case ETranslucencyPass::TPT_AllTranslucency:
return TEXT("All");
}
checkNoEntry();
return TEXT("");
}
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_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)
{
return true;
}
// Otherwise it only gets rendered in the separate buffer if it is downsampled.
if (DownsampleScale < 1.0f)
{
return true;
}
return false;
}
static void AddBeginTranslucencyTimerPass(FRDGBuilder& GraphBuilder, const FViewInfo& View)
{
#if STATS
if (View.ViewState)
{
AddPass(GraphBuilder, [&View](FRHICommandListImmediate& RHICmdList)
{
View.ViewState->TranslucencyTimer.Begin(RHICmdList);
});
}
#endif
}
static void AddEndTranslucencyTimerPass(FRDGBuilder& GraphBuilder, const FViewInfo& View)
{
#if STATS
if (View.ViewState)
{
AddPass(GraphBuilder, [&View](FRHICommandListImmediate& RHICmdList)
{
View.ViewState->TranslucencyTimer.End(RHICmdList);
});
}
#endif
}
static bool HasSeparateTranslucencyTimer(const FViewInfo& View)
{
return View.ViewState && GSupportsTimestampRenderQueries
#if !STATS
&& (CVarSeparateTranslucencyAutoDownsample.GetValueOnRenderThread() != 0)
#endif
;
}
static void AddBeginSeparateTranslucencyTimerPass(FRDGBuilder& GraphBuilder, const FViewInfo& View, ETranslucencyPass::Type TranslucencyPass)
{
if (HasSeparateTranslucencyTimer(View))
{
AddPass(GraphBuilder, [&View, TranslucencyPass](FRHICommandListImmediate& RHICmdList)
{
if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate)
{
View.ViewState->SeparateTranslucencyModulateTimer.Begin(RHICmdList);
}
else
{
View.ViewState->SeparateTranslucencyTimer.Begin(RHICmdList);
}
});
}
}
static void AddEndSeparateTranslucencyTimerPass(FRDGBuilder& GraphBuilder, const FViewInfo& View, ETranslucencyPass::Type TranslucencyPass)
{
if (HasSeparateTranslucencyTimer(View))
{
AddPass(GraphBuilder, [&View, TranslucencyPass](FRHICommandListImmediate& RHICmdList)
{
if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate)
{
View.ViewState->SeparateTranslucencyModulateTimer.End(RHICmdList);
}
else
{
View.ViewState->SeparateTranslucencyTimer.End(RHICmdList);
}
});
}
}
FSeparateTranslucencyDimensions UpdateTranslucencyTimers(FRHICommandListImmediate& RHICmdList, TArrayView<const FViewInfo> Views)
{
bool bAnyViewWantsDownsampledSeparateTranslucency = false;
#if STATS
const bool bSeparateTranslucencyAutoDownsample = CVarSeparateTranslucencyAutoDownsample.GetValueOnRenderThread() != 0;
#else
const bool bSeparateTranslucencyAutoDownsample = false;
#endif
if (bSeparateTranslucencyAutoDownsample)
{
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
SCOPED_GPU_MASK(RHICmdList, View.GPUMask);
FSceneViewState* ViewState = View.ViewState;
if (ViewState)
{
//We always tick the separate trans timer but only need the other timer for stats
bool bSeparateTransTimerSuccess = ViewState->SeparateTranslucencyTimer.Tick(RHICmdList);
bool bSeparateTransModulateTimerSuccess = ViewState->SeparateTranslucencyModulateTimer.Tick(RHICmdList);
if (STATS)
{
ViewState->TranslucencyTimer.Tick(RHICmdList);
//Stats are fed the most recent available time and so are lagged a little.
float MostRecentTotalTime = ViewState->TranslucencyTimer.GetTimeMS() +
ViewState->SeparateTranslucencyTimer.GetTimeMS() +
ViewState->SeparateTranslucencyModulateTimer.GetTimeMS();
SET_FLOAT_STAT(STAT_TranslucencyGPU, MostRecentTotalTime);
}
if (bSeparateTranslucencyAutoDownsample && bSeparateTransTimerSuccess)
{
float LastFrameTranslucencyDurationMS = ViewState->SeparateTranslucencyTimer.GetTimeMS() + ViewState->SeparateTranslucencyModulateTimer.GetTimeMS();
const bool bOriginalShouldAutoDownsampleTranslucency = ViewState->bShouldAutoDownsampleTranslucency;
if (ViewState->bShouldAutoDownsampleTranslucency)
{
ViewState->SmoothedFullResTranslucencyGPUDuration = 0;
const float LerpAlpha = ViewState->SmoothedHalfResTranslucencyGPUDuration == 0 ? 1.0f : .1f;
ViewState->SmoothedHalfResTranslucencyGPUDuration = FMath::Lerp(ViewState->SmoothedHalfResTranslucencyGPUDuration, LastFrameTranslucencyDurationMS, LerpAlpha);
// Don't re-asses switching for some time after the last switch
if (View.Family->CurrentRealTime - ViewState->LastAutoDownsampleChangeTime > CVarSeparateTranslucencyMinDownsampleChangeTime.GetValueOnRenderThread())
{
// Downsample if the smoothed time is larger than the threshold
ViewState->bShouldAutoDownsampleTranslucency = ViewState->SmoothedHalfResTranslucencyGPUDuration > CVarSeparateTranslucencyDurationUpsampleThreshold.GetValueOnRenderThread();
if (!ViewState->bShouldAutoDownsampleTranslucency)
{
// Do 'log LogRenderer verbose' to get these
UE_LOG(LogRenderer, Verbose, TEXT("Upsample: %.1fms < %.1fms"), ViewState->SmoothedHalfResTranslucencyGPUDuration, CVarSeparateTranslucencyDurationUpsampleThreshold.GetValueOnRenderThread());
}
}
}
else
{
ViewState->SmoothedHalfResTranslucencyGPUDuration = 0;
const float LerpAlpha = ViewState->SmoothedFullResTranslucencyGPUDuration == 0 ? 1.0f : .1f;
ViewState->SmoothedFullResTranslucencyGPUDuration = FMath::Lerp(ViewState->SmoothedFullResTranslucencyGPUDuration, LastFrameTranslucencyDurationMS, LerpAlpha);
if (View.Family->CurrentRealTime - ViewState->LastAutoDownsampleChangeTime > CVarSeparateTranslucencyMinDownsampleChangeTime.GetValueOnRenderThread())
{
// Downsample if the smoothed time is larger than the threshold
ViewState->bShouldAutoDownsampleTranslucency = ViewState->SmoothedFullResTranslucencyGPUDuration > CVarSeparateTranslucencyDurationDownsampleThreshold.GetValueOnRenderThread();
if (ViewState->bShouldAutoDownsampleTranslucency)
{
UE_LOG(LogRenderer, Verbose, TEXT("Downsample: %.1fms > %.1fms"), ViewState->SmoothedFullResTranslucencyGPUDuration, CVarSeparateTranslucencyDurationDownsampleThreshold.GetValueOnRenderThread());
}
}
}
if (bOriginalShouldAutoDownsampleTranslucency != ViewState->bShouldAutoDownsampleTranslucency)
{
ViewState->LastAutoDownsampleChangeTime = View.Family->CurrentRealTime;
}
bAnyViewWantsDownsampledSeparateTranslucency = bAnyViewWantsDownsampledSeparateTranslucency || ViewState->bShouldAutoDownsampleTranslucency;
}
}
}
}
float EffectiveScale = FMath::Clamp(CVarSeparateTranslucencyScreenPercentage.GetValueOnRenderThread() / 100.0f, 0.0f, 1.0f);
// 'r.SeparateTranslucencyScreenPercentage' CVar wins over automatic downsampling
if (FMath::IsNearlyEqual(EffectiveScale, 1.0f) && bAnyViewWantsDownsampledSeparateTranslucency)
{
EffectiveScale = 0.5f;
}
const FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get();
FSeparateTranslucencyDimensions Dimensions;
Dimensions.Extent = GetScaledExtent(SceneContext.GetBufferSizeXY(), EffectiveScale);
Dimensions.NumSamples = SceneContext.GetNumSceneColorMSAASamples(Views[0].FeatureLevel);
Dimensions.Scale = EffectiveScale;
return Dimensions;
}
FRDGTextureMSAA FSeparateTranslucencyTextures::GetColorForWrite(FRDGBuilder& GraphBuilder)
{
if (!ColorTexture.IsValid())
{
const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(Dimensions.Extent, PF_FloatRGBA, FClearValueBinding::Black, TexCreate_RenderTargetable | TexCreate_ShaderResource, 1, Dimensions.NumSamples);
ColorTexture = CreateTextureMSAA(GraphBuilder, Desc, TEXT("SeparateTranslucencyColor"), GFastVRamConfig.SeparateTranslucency);
}
return ColorTexture;
}
FRDGTextureRef FSeparateTranslucencyTextures::GetColorForRead(FRDGBuilder& GraphBuilder) const
{
if (ColorTexture.IsValid())
{
return ColorTexture.Resolve;
}
return GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackAlphaOneDummy);
}
FRDGTextureMSAA FSeparateTranslucencyTextures::GetColorModulateForWrite(FRDGBuilder& GraphBuilder)
{
if (!ColorModulateTexture.IsValid())
{
const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(Dimensions.Extent, PF_FloatR11G11B10, FClearValueBinding::White, TexCreate_RenderTargetable | TexCreate_ShaderResource, 1, Dimensions.NumSamples);
ColorModulateTexture = CreateTextureMSAA(GraphBuilder, Desc, TEXT("SeparateTranslucencyModulateColor"), GFastVRamConfig.SeparateTranslucencyModulate);
}
return ColorModulateTexture;
}
FRDGTextureRef FSeparateTranslucencyTextures::GetColorModulateForRead(FRDGBuilder& GraphBuilder) const
{
if (ColorModulateTexture.IsValid())
{
return ColorModulateTexture.Resolve;
}
return GraphBuilder.RegisterExternalTexture(GSystemTextures.WhiteDummy);
}
FRDGTextureMSAA FSeparateTranslucencyTextures::GetForWrite(FRDGBuilder& GraphBuilder, ETranslucencyPass::Type TranslucencyPass)
{
if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate)
{
return GetColorModulateForWrite(GraphBuilder);
}
else
{
return GetColorForWrite(GraphBuilder);
}
}
/** 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);
AddCopyToResolveTargetPass(GraphBuilder, SceneColor.Target, SceneColor.Resolve, FResolveRect(View.ViewRect));
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;
}
/** Pixel shader to upsample separate translucency. */
class FTranslucencyUpsamplePS : public FGlobalShader
{
public:
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, LowResColorTexture)
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float>, LowResDepthTexture)
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float>, FullResDepthTexture)
SHADER_PARAMETER(FVector2D, LowResExtentInverse)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
FTranslucencyUpsamplePS() = default;
FTranslucencyUpsamplePS(const FGlobalShaderType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{}
};
class FTranslucencySimpleUpsamplePS : public FTranslucencyUpsamplePS
{
protected:
DECLARE_GLOBAL_SHADER(FTranslucencySimpleUpsamplePS);
SHADER_USE_PARAMETER_STRUCT(FTranslucencySimpleUpsamplePS, FTranslucencyUpsamplePS);
};
IMPLEMENT_GLOBAL_SHADER(FTranslucencySimpleUpsamplePS, "/Engine/Private/TranslucencyUpsampling.usf", "SimpleUpsamplingPS", SF_Pixel);
class FTranslucencyNearestDepthNeighborUpsamplePS : public FTranslucencyUpsamplePS
{
public:
DECLARE_GLOBAL_SHADER(FTranslucencyNearestDepthNeighborUpsamplePS);
SHADER_USE_PARAMETER_STRUCT(FTranslucencyNearestDepthNeighborUpsamplePS, FTranslucencyUpsamplePS);
};
IMPLEMENT_GLOBAL_SHADER(FTranslucencyNearestDepthNeighborUpsamplePS, "/Engine/Private/TranslucencyUpsampling.usf", "NearestDepthNeighborUpsamplingPS", SF_Pixel);
static void AddTranslucencyUpsamplePass(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
FScreenPassRenderTarget Output,
FScreenPassTexture DownsampledTranslucencyColor,
FRDGTextureRef DownsampledTranslucencyDepthTexture,
FRDGTextureRef SceneDepthTexture,
float DownsampleScale)
{
const bool bHalfResDownsample = FMath::IsNearlyEqual(DownsampleScale, 0.5f);
const bool bUseNearestDepthNeighborUpsample = GSeparateTranslucencyUpsampleMode > 0 && bHalfResDownsample;
TShaderMapRef<FScreenVS> VertexShader(View.ShaderMap);
TShaderRef<FTranslucencyUpsamplePS> PixelShader;
FRHIBlendState* BlendState = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_SourceAlpha>::GetRHI();
if (bUseNearestDepthNeighborUpsample)
{
PixelShader = TShaderMapRef<FTranslucencyNearestDepthNeighborUpsamplePS>(View.ShaderMap);
}
else
{
PixelShader = TShaderMapRef<FTranslucencySimpleUpsamplePS>(View.ShaderMap);
}
const FScreenPassTextureViewport OutputViewport(Output);
const FScreenPassTextureViewport InputViewport(DownsampledTranslucencyColor);
const FIntPoint LowResExtent = DownsampledTranslucencyColor.Texture->Desc.Extent;
auto* PassParameters = GraphBuilder.AllocParameters<FTranslucencyUpsamplePS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
PassParameters->FullResDepthTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMetaData(SceneDepthTexture, ERDGTextureMetaDataAccess::Depth));
PassParameters->LowResColorTexture = DownsampledTranslucencyColor.Texture;
PassParameters->LowResDepthTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMetaData(DownsampledTranslucencyDepthTexture, ERDGTextureMetaDataAccess::Depth));
PassParameters->LowResExtentInverse = FVector2D(1.0f / LowResExtent.X, 1.0f / LowResExtent.Y);
PassParameters->RenderTargets[0] = Output.GetRenderTargetBinding();
AddDrawScreenPass(GraphBuilder, RDG_EVENT_NAME("TranslucencyUpsample"), View, OutputViewport, InputViewport, VertexShader, PixelShader, BlendState, PassParameters);
}
bool FSceneRenderer::ShouldRenderTranslucency() const
{
return ViewFamily.EngineShowFlags.Translucency
&& !ViewFamily.EngineShowFlags.VisualizeLightCulling
&& !ViewFamily.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;
}
void SetupDownsampledTranslucencyViewParameters(
const FViewInfo& View,
FScreenPassTextureViewport DownsampledTranslucencyViewport,
FViewUniformShaderParameters& DownsampledTranslucencyViewParameters)
{
DownsampledTranslucencyViewParameters = *View.CachedViewUniformShaderParameters;
// Update the parts of DownsampledTranslucencyParameters which are dependent on the buffer size and view rect
View.SetupViewRectUniformBufferParameters(
DownsampledTranslucencyViewParameters,
DownsampledTranslucencyViewport.Extent,
DownsampledTranslucencyViewport.Rect,
View.ViewMatrices,
View.PrevViewInfo.ViewMatrices);
}
void SetupTranslucentBasePassUniformParameters(
FRDGBuilder& GraphBuilder,
const FSceneRenderTargets& SceneRenderTargets,
const FViewInfo& View,
const FTranslucentVolumeLightingTextures* TranslucentVolumeLightingTextures,
FRDGTextureRef SceneColorCopyTexture,
ESceneTextureSetupMode SceneTextureSetupMode,
const int32 ViewIndex,
FTranslucentBasePassUniformParameters& BasePassParameters)
{
const auto GetRDG = [&](const TRefCountPtr<IPooledRenderTarget>& PooledRenderTarget, ERDGTextureFlags Flags = ERDGTextureFlags::None)
{
return GraphBuilder.RegisterExternalTexture(PooledRenderTarget, ERenderTargetTexture::ShaderResource, Flags);
};
SetupSharedBasePassParameters(GraphBuilder, View, BasePassParameters.Shared);
SetupSceneTextureUniformParameters(&GraphBuilder, View.FeatureLevel, SceneRenderTargets, SceneTextureSetupMode, BasePassParameters.SceneTextures);
FRDGTextureRef BlackDummyTexture = GetRDG(GSystemTextures.BlackDummy);
// Material SSR
{
float PrevSceneColorPreExposureInvValue = 1.0f / View.PreExposure;
if (View.HZB)
{
BasePassParameters.HZBTexture = GetRDG(View.HZB);
BasePassParameters.HZBSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
FRDGTextureRef PrevSceneColorTexture = BlackDummyTexture;
if (View.PrevViewInfo.CustomSSRInput.IsValid())
{
PrevSceneColorTexture = GetRDG(View.PrevViewInfo.CustomSSRInput);
PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure;
}
else if (View.PrevViewInfo.TemporalAAHistory.IsValid())
{
PrevSceneColorTexture = GetRDG(View.PrevViewInfo.TemporalAAHistory.RT[0]);
PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure;
}
BasePassParameters.PrevSceneColor = PrevSceneColorTexture;
BasePassParameters.PrevSceneColorSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
const FVector2D HZBUvFactor(
float(View.ViewRect.Width()) / float(2 * View.HZBMipmap0Size.X),
float(View.ViewRect.Height()) / float(2 * View.HZBMipmap0Size.Y)
);
const FVector4 HZBUvFactorAndInvFactorValue(
HZBUvFactor.X,
HZBUvFactor.Y,
1.0f / HZBUvFactor.X,
1.0f / HZBUvFactor.Y
);
BasePassParameters.HZBUvFactorAndInvFactor = HZBUvFactorAndInvFactorValue;
}
else
{
BasePassParameters.HZBTexture = BlackDummyTexture;
BasePassParameters.HZBSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
BasePassParameters.PrevSceneColor = BlackDummyTexture;
BasePassParameters.PrevSceneColorSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
}
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->GetRenderTargetItem().ShaderResourceTexture;
BasePassParameters.VolumetricCloudDepth = VolumetricReconstructRTDepth->GetRenderTargetItem().ShaderResourceTexture;
BasePassParameters.ApplyVolumetricCloudOnTransparent = 1.0f;
}
}
if (BasePassParameters.VolumetricCloudColor == nullptr)
{
BasePassParameters.VolumetricCloudColor = GSystemTextures.BlackAlphaOneDummy->GetRenderTargetItem().ShaderResourceTexture;
BasePassParameters.VolumetricCloudDepth = GSystemTextures.BlackDummy->GetRenderTargetItem().ShaderResourceTexture;
}
FIntPoint ViewportOffset = View.ViewRect.Min;
FIntPoint ViewportExtent = View.ViewRect.Size();
// Scene render targets might not exist yet; avoids NaNs.
FIntPoint EffectiveBufferSize = SceneRenderTargets.GetBufferSizeXY();
EffectiveBufferSize.X = FMath::Max(EffectiveBufferSize.X, 1);
EffectiveBufferSize.Y = FMath::Max(EffectiveBufferSize.Y, 1);
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;
}
FVector2D InvBufferSize(1.0f / float(EffectiveBufferSize.X), 1.0f / float(EffectiveBufferSize.Y));
FVector4 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;
}
// Translucency Lighting Volume
{
if (TranslucentVolumeLightingTextures)
{
BasePassParameters.TranslucencyLightingVolumeAmbientInner = TranslucentVolumeLightingTextures->GetAmbient(ViewIndex, TVC_Inner);
BasePassParameters.TranslucencyLightingVolumeAmbientOuter = TranslucentVolumeLightingTextures->GetAmbient(ViewIndex, TVC_Outer);
BasePassParameters.TranslucencyLightingVolumeDirectionalInner = TranslucentVolumeLightingTextures->GetDirectional(ViewIndex, TVC_Inner);
BasePassParameters.TranslucencyLightingVolumeDirectionalOuter = TranslucentVolumeLightingTextures->GetDirectional(ViewIndex, TVC_Outer);
}
else
{
BasePassParameters.TranslucencyLightingVolumeAmbientInner = BlackDummyTexture;
BasePassParameters.TranslucencyLightingVolumeAmbientOuter = BlackDummyTexture;
BasePassParameters.TranslucencyLightingVolumeDirectionalInner = BlackDummyTexture;
BasePassParameters.TranslucencyLightingVolumeDirectionalOuter = BlackDummyTexture;
}
BasePassParameters.TranslucencyLightingVolumeAmbientInnerSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
BasePassParameters.TranslucencyLightingVolumeAmbientOuterSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
BasePassParameters.TranslucencyLightingVolumeDirectionalInnerSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
BasePassParameters.TranslucencyLightingVolumeDirectionalOuterSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
}
BasePassParameters.LumenParameters = GetLumenTranslucencyLightingParameters(View.LumenTranslucencyGIVolume);
BasePassParameters.SceneColorCopyTexture = BlackDummyTexture;
BasePassParameters.SceneColorCopySampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
if (SceneColorCopyTexture)
{
BasePassParameters.SceneColorCopyTexture = SceneColorCopyTexture;
}
BasePassParameters.EyeAdaptationTexture = BlackDummyTexture;
// Setup by passes that support it
if (View.HasValidEyeAdaptationTexture())
{
BasePassParameters.EyeAdaptationTexture = GetRDG(View.GetEyeAdaptationTexture(), ERDGTextureFlags::MultiFrame);
}
BasePassParameters.PreIntegratedGFTexture = GSystemTextures.PreintegratedGF->GetRenderTargetItem().ShaderResourceTexture;
BasePassParameters.PreIntegratedGFSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
}
TRDGUniformBufferRef<FTranslucentBasePassUniformParameters> CreateTranslucentBasePassUniformBuffer(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FTranslucentVolumeLightingTextures* TranslucentVolumeLightingTextures,
FRDGTextureRef SceneColorCopyTexture,
ESceneTextureSetupMode SceneTextureSetupMode,
const int32 ViewIndex)
{
FSceneRenderTargets& SceneRenderTargets = FSceneRenderTargets::Get();
FTranslucentBasePassUniformParameters* BasePassParameters = GraphBuilder.AllocParameters<FTranslucentBasePassUniformParameters>();
SetupTranslucentBasePassUniformParameters(GraphBuilder, SceneRenderTargets, View, TranslucentVolumeLightingTextures, SceneColorCopyTexture, SceneTextureSetupMode, ViewIndex, *BasePassParameters);
return GraphBuilder.CreateUniformBuffer(BasePassParameters);
}
static void UpdateSeparateTranslucencyViewState(FScene* Scene, const FViewInfo& View, const FScreenPassTextureViewport& SeparateTranslucencyViewport, FMeshPassProcessorRenderState& DrawRenderState)
{
Scene->UniformBuffers.UpdateViewUniformBuffer(View);
FViewUniformShaderParameters DownsampledTranslucencyViewParameters;
SetupDownsampledTranslucencyViewParameters(View, SeparateTranslucencyViewport, DownsampledTranslucencyViewParameters);
Scene->UniformBuffers.UpdateViewUniformBufferImmediate(DownsampledTranslucencyViewParameters);
DrawRenderState.SetViewUniformBuffer(Scene->UniformBuffers.ViewUniformBuffer);
if ((View.IsInstancedStereoPass() || View.bIsMobileMultiViewEnabled) && View.Family->Views.Num() > 0)
{
// When drawing the left eye in a stereo scene, copy the right eye view values into the instanced view uniform buffer.
const EStereoscopicPass StereoPassIndex = IStereoRendering::IsStereoEyeView(View) ? eSSP_RIGHT_EYE : eSSP_FULL;
const FViewInfo& InstancedView = static_cast<const FViewInfo&>(View.Family->GetStereoEyeView(StereoPassIndex));
SetupDownsampledTranslucencyViewParameters(InstancedView, SeparateTranslucencyViewport, DownsampledTranslucencyViewParameters);
Scene->UniformBuffers.InstancedViewUniformBuffer.UpdateUniformBufferImmediate(reinterpret_cast<FInstancedViewUniformShaderParameters&>(DownsampledTranslucencyViewParameters));
DrawRenderState.SetInstancedViewUniformBuffer(Scene->UniformBuffers.InstancedViewUniformBuffer);
}
}
static void RenderViewTranslucencyInner(
FRHICommandListImmediate& RHICmdList,
const FSceneRenderer& SceneRenderer,
const FViewInfo& View,
const FScreenPassTextureViewport Viewport,
const float ViewportScale,
ETranslucencyPass::Type TranslucencyPass,
FRDGParallelCommandListSet* ParallelCommandListSet)
{
FMeshPassProcessorRenderState DrawRenderState(View);
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
UpdateSeparateTranslucencyViewState(SceneRenderer.Scene, View, Viewport, DrawRenderState);
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);
}
if (IsMainTranslucencyPass(TranslucencyPass))
{
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)
{
if (ParallelCommandListSet)
{
ParallelCommandListSet->SetStateOnCommandList(RHICmdList);
}
{
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_RDG_UNIFORM_BUFFER(FTranslucentBasePassUniformParameters, BasePass)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static void RenderTranslucencyViewInner(
FRDGBuilder& GraphBuilder,
const FSceneRenderer& SceneRenderer,
const FViewInfo& View,
FScreenPassTextureViewport Viewport,
float ViewportScale,
FRDGTextureMSAA SceneColorTexture,
ERenderTargetLoadAction SceneColorLoadAction,
FRDGTextureRef SceneDepthTexture,
TRDGUniformBufferRef<FTranslucentBasePassUniformParameters> BasePassParameters,
ETranslucencyPass::Type TranslucencyPass,
bool bResolveColorTexture,
bool bRenderInParallel)
{
FTranslucentBasePassParameters* PassParameters = GraphBuilder.AllocParameters<FTranslucentBasePassParameters>();
PassParameters->BasePass = BasePassParameters;
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(SceneDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilWrite);
PassParameters->RenderTargets.ResolveRect = FResolveRect(Viewport.Rect);
if (bRenderInParallel)
{
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture.Target, nullptr, ERenderTargetLoadAction::ELoad);
if (SceneColorLoadAction == ERenderTargetLoadAction::EClear)
{
AddClearRenderTargetPass(GraphBuilder, SceneColorTexture.Target);
}
GraphBuilder.AddPass(
RDG_EVENT_NAME("SeparateTranslucencyParallel"),
PassParameters,
ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass,
[&SceneRenderer, &View, PassParameters, ViewportScale, Viewport, TranslucencyPass](FRHICommandListImmediate& RHICmdList)
{
FRDGParallelCommandListSet ParallelCommandListSet(RHICmdList, GET_STATID(STAT_CLP_Translucency), SceneRenderer, View, FParallelCommandListBindings(PassParameters), ViewportScale);
RenderViewTranslucencyInner(RHICmdList, SceneRenderer, View, Viewport, ViewportScale, TranslucencyPass, &ParallelCommandListSet);
});
if (bResolveColorTexture)
{
AddResolveSceneColorPass(GraphBuilder, View, SceneColorTexture);
}
}
else
{
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture.Target, bResolveColorTexture ? SceneColorTexture.Resolve : nullptr, SceneColorLoadAction);
GraphBuilder.AddPass(
RDG_EVENT_NAME("SeparateTranslucency"),
PassParameters,
ERDGPassFlags::Raster,
[&SceneRenderer, &View, ViewportScale, Viewport, TranslucencyPass](FRHICommandListImmediate& RHICmdList)
{
RenderViewTranslucencyInner(RHICmdList, SceneRenderer, View, Viewport, ViewportScale, TranslucencyPass, nullptr);
});
}
}
void FDeferredShadingSceneRenderer::RenderTranslucencyInner(
FRDGBuilder& GraphBuilder,
const FTranslucentVolumeLightingTextures& TranslucentVolumeLightingTextures,
FRDGTextureMSAA SceneColorTexture,
FRDGTextureMSAA SceneDepthTexture,
FSeparateTranslucencyTextures* OutSeparateTranslucencyTextures,
ETranslucencyView ViewsToRender,
FRDGTextureRef SceneColorCopyTexture,
ETranslucencyPass::Type TranslucencyPass)
{
if (!ShouldRenderTranslucency(TranslucencyPass))
{
return;
}
RDG_EVENT_SCOPE(GraphBuilder, "%s", TranslucencyPassToString(TranslucencyPass));
RDG_GPU_STAT_SCOPE(GraphBuilder, Translucency);
RDG_WAIT_FOR_TASKS_CONDITIONAL(GraphBuilder, IsTranslucencyWaitForTasksEnabled());
const bool bRenderInParallel = IsParallelTranslucencyEnabled();
const bool bRenderInSeparateTranslucency = IsSeparateTranslucencyEnabled(TranslucencyPass, SeparateTranslucencyDimensions.Scale);
const auto ShouldRenderView = [&](const FViewInfo& View, ETranslucencyView TranslucencyView)
{
return View.ShouldRenderView() && EnumHasAnyFlags(TranslucencyView, ViewsToRender);
};
// Can't reference scene color in scene textures. Scene color copy is used instead.
ESceneTextureSetupMode SceneTextureSetupMode = ESceneTextureSetupMode::All;
EnumRemoveFlags(SceneTextureSetupMode, ESceneTextureSetupMode::SceneColor);
if (bRenderInSeparateTranslucency)
{
for (int32 ViewIndex = 0, NumProcessedViews = 0; ViewIndex < Views.Num(); ++ViewIndex, ++NumProcessedViews)
{
const FViewInfo& View = Views[ViewIndex];
const ETranslucencyView TranslucencyView = GetTranslucencyView(View);
if (!ShouldRenderView(View, TranslucencyView))
{
continue;
}
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetViewport(View.ViewRect);
const bool bCompositeBackToSceneColor = IsMainTranslucencyPass(TranslucencyPass) || EnumHasAnyFlags(TranslucencyView, ETranslucencyView::UnderWater);
checkf(bCompositeBackToSceneColor || OutSeparateTranslucencyTextures, TEXT("OutSeparateTranslucencyTextures is null, but we aren't compositing immediately back to scene color."));
/** 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.
*/
FSeparateTranslucencyTextures LocalSeparateTranslucencyTextures(SeparateTranslucencyDimensions);
FRDGTextureMSAA SeparateTranslucencyColorTexture;
if (bCompositeBackToSceneColor)
{
SeparateTranslucencyColorTexture = LocalSeparateTranslucencyTextures.GetForWrite(GraphBuilder, TranslucencyPass);
}
else
{
SeparateTranslucencyColorTexture = OutSeparateTranslucencyTextures->GetForWrite(GraphBuilder, TranslucencyPass);
}
// When rendering to a 1-to-1 separate translucency target, use the existing scene depth.
FRDGTextureMSAA SeparateTranslucencyDepthTexture = SceneDepthTexture;
// Rendering to a downscaled target; allocate a new depth texture and downsample depth.
if (SeparateTranslucencyDimensions.Scale < 1.0f)
{
const FRDGTextureDesc DepthDesc = FRDGTextureDesc::Create2D(
SeparateTranslucencyDimensions.Extent, PF_DepthStencil, FClearValueBinding::None, TexCreate_DepthStencilTargetable | TexCreate_ShaderResource, 1, SeparateTranslucencyDimensions.NumSamples);
SeparateTranslucencyDepthTexture = CreateTextureMSAA(GraphBuilder, DepthDesc, TEXT("SeparateTranslucencyDepth"));
AddDownsampleDepthPass(
GraphBuilder, View,
FScreenPassTexture(SceneDepthTexture.Resolve, View.ViewRect),
FScreenPassRenderTarget(SeparateTranslucencyDepthTexture.Target, SeparateTranslucencyViewport.Rect, ERenderTargetLoadAction::ENoAction),
EDownsampleDepthFilter::Point);
}
AddBeginSeparateTranslucencyTimerPass(GraphBuilder, View, TranslucencyPass);
const ERenderTargetLoadAction SeparateTranslucencyColorLoadAction = NumProcessedViews == 0 || View.Family->bMultiGPUForkAndJoin
? ERenderTargetLoadAction::EClear
: ERenderTargetLoadAction::ELoad;
RenderTranslucencyViewInner(
GraphBuilder,
*this,
View,
SeparateTranslucencyViewport,
SeparateTranslucencyDimensions.Scale,
SeparateTranslucencyColorTexture,
SeparateTranslucencyColorLoadAction,
SeparateTranslucencyDepthTexture.Target,
CreateTranslucentBasePassUniformBuffer(GraphBuilder, View, &TranslucentVolumeLightingTextures, SceneColorCopyTexture, SceneTextureSetupMode, ViewIndex),
TranslucencyPass,
!bCompositeBackToSceneColor,
bRenderInParallel);
if (bCompositeBackToSceneColor)
{
::AddResolveSceneDepthPass(GraphBuilder, View, SeparateTranslucencyDepthTexture);
AddTranslucencyUpsamplePass(
GraphBuilder, View,
FScreenPassRenderTarget(SceneColorTexture.Target, View.ViewRect, ERenderTargetLoadAction::ELoad),
FScreenPassTexture(SeparateTranslucencyColorTexture.Resolve, SeparateTranslucencyViewport.Rect),
SeparateTranslucencyDepthTexture.Resolve,
SceneDepthTexture.Resolve,
SeparateTranslucencyDimensions.Scale);
}
AddEndSeparateTranslucencyTimerPass(GraphBuilder, View, TranslucencyPass);
}
}
else
{
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
const FViewInfo& View = Views[ViewIndex];
const ETranslucencyView TranslucencyView = GetTranslucencyView(View);
if (!ShouldRenderView(View, TranslucencyView))
{
continue;
}
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
AddBeginTranslucencyTimerPass(GraphBuilder, View);
const ERenderTargetLoadAction SceneColorLoadAction = ERenderTargetLoadAction::ELoad;
const FScreenPassTextureViewport Viewport(SceneColorTexture.Target, View.ViewRect);
const float ViewportScale = 1.0f;
const bool bResolveColorTexture = false;
RenderTranslucencyViewInner(
GraphBuilder,
*this,
View,
Viewport,
ViewportScale,
SceneColorTexture,
SceneColorLoadAction,
SceneDepthTexture.Target,
CreateTranslucentBasePassUniformBuffer(GraphBuilder, View, &TranslucentVolumeLightingTextures, SceneColorCopyTexture, SceneTextureSetupMode, ViewIndex),
TranslucencyPass,
bResolveColorTexture,
bRenderInParallel);
AddEndTranslucencyTimerPass(GraphBuilder, View);
}
}
}
void FDeferredShadingSceneRenderer::RenderTranslucency(
FRDGBuilder& GraphBuilder,
const FTranslucentVolumeLightingTextures& TranslucentVolumeLightingTextures,
FRDGTextureMSAA SceneColorTexture,
FRDGTextureMSAA SceneDepthTexture,
FSeparateTranslucencyTextures* OutSeparateTranslucencyTextures,
ETranslucencyView ViewsToRender)
{
if (!EnumHasAnyFlags(ViewsToRender, ETranslucencyView::UnderWater | ETranslucencyView::AboveWater))
{
return;
}
RDG_EVENT_SCOPE(GraphBuilder, "Translucency");
FRDGTextureRef SceneColorCopyTexture = nullptr;
if (EnumHasAnyFlags(ViewsToRender, ETranslucencyView::AboveWater))
{
SceneColorCopyTexture = AddCopySceneColorPass(GraphBuilder, Views, SceneColorTexture);
}
if (ViewFamily.AllowTranslucencyAfterDOF())
{
RenderTranslucencyInner(GraphBuilder, TranslucentVolumeLightingTextures, SceneColorTexture, SceneDepthTexture, OutSeparateTranslucencyTextures, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_StandardTranslucency);
RenderTranslucencyInner(GraphBuilder, TranslucentVolumeLightingTextures, SceneColorTexture, SceneDepthTexture, OutSeparateTranslucencyTextures, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterDOF);
RenderTranslucencyInner(GraphBuilder, TranslucentVolumeLightingTextures, SceneColorTexture, SceneDepthTexture, OutSeparateTranslucencyTextures, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterDOFModulate);
}
else // Otherwise render translucent primitives in a single bucket.
{
RenderTranslucencyInner(GraphBuilder, TranslucentVolumeLightingTextures, SceneColorTexture, SceneDepthTexture, OutSeparateTranslucencyTextures, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_AllTranslucency);
}
}