Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBloomSetup.cpp
guillaume abadie 9e6fbfddcc Fixes crash on r.BloomQuality=6
#rb trivial
#jira UE-140499
#preflight 61f9192c80608c7029b3a8ed

#ROBOMERGE-AUTHOR: guillaume.abadie
#ROBOMERGE-SOURCE: CL 18806910 in //UE5/Release-5.0/... via CL 18808614 via CL 18822202
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545)

[CL 18822504 by guillaume abadie in ue5-main branch]
2022-02-02 02:47:24 -05:00

243 lines
9.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "PostProcess/PostProcessBloomSetup.h"
#include "PostProcess/PostProcessDownsample.h"
#include "PostProcess/PostProcessFFTBloom.h"
#include "PostProcess/PostProcessWeightedSampleSum.h"
#include "PixelShaderUtils.h"
namespace
{
const int32 GBloomSetupComputeTileSizeX = 8;
const int32 GBloomSetupComputeTileSizeY = 8;
TAutoConsoleVariable<float> CVarBloomCross(
TEXT("r.GaussianBloom.Cross"),
0.0f,
TEXT("Experimental feature to give bloom kernel a more bright center sample (values between 1 and 3 work without causing aliasing)\n")
TEXT("Existing bloom get lowered to match the same brightness\n")
TEXT("<0 for a anisomorphic lens flare look (X only)\n")
TEXT(" 0 off (default)\n")
TEXT(">0 for a cross look (X and Y)"),
ECVF_RenderThreadSafe);
BEGIN_SHADER_PARAMETER_STRUCT(FBloomSetupParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, Input)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, InputTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, InputSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, EyeAdaptationTexture)
SHADER_PARAMETER(float, BloomThreshold)
END_SHADER_PARAMETER_STRUCT()
FBloomSetupParameters GetBloomSetupParameters(
const FViewInfo& View,
const FScreenPassTextureViewport& InputViewport,
FRDGTextureRef InputTexture,
FRDGTextureRef EyeAdaptationTexture,
float BloomThreshold)
{
FBloomSetupParameters Parameters;
Parameters.View = View.ViewUniformBuffer;
Parameters.Input = GetScreenPassTextureViewportParameters(InputViewport);
Parameters.InputTexture = InputTexture;
Parameters.InputSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
Parameters.EyeAdaptationTexture = EyeAdaptationTexture;
Parameters.BloomThreshold = BloomThreshold;
return Parameters;
}
class FBloomSetupPS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FBloomSetupPS);
SHADER_USE_PARAMETER_STRUCT(FBloomSetupPS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FBloomSetupParameters, BloomSetup)
SHADER_PARAMETER(FScreenTransform, SvPositionToInputTextureUV)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
};
IMPLEMENT_GLOBAL_SHADER(FBloomSetupPS, "/Engine/Private/PostProcessBloom.usf", "BloomSetupPS", SF_Pixel);
class FBloomSetupCS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FBloomSetupCS);
SHADER_USE_PARAMETER_STRUCT(FBloomSetupCS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FBloomSetupParameters, BloomSetup)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, RWOutputTexture)
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEX"), GBloomSetupComputeTileSizeX);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEY"), GBloomSetupComputeTileSizeY);
}
};
IMPLEMENT_GLOBAL_SHADER(FBloomSetupCS, "/Engine/Private/PostProcessBloom.usf", "BloomSetupCS", SF_Compute);
} //!namespace
FScreenPassTexture AddBloomSetupPass(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FBloomSetupInputs& Inputs)
{
check(Inputs.SceneColor.IsValid());
check(Inputs.EyeAdaptationTexture);
check(Inputs.Threshold > -1.0f);
const bool bIsComputePass = View.bUseComputePasses;
FRDGTextureDesc OutputDesc = Inputs.SceneColor.Texture->Desc;
OutputDesc.Reset();
OutputDesc.Flags |= bIsComputePass ? TexCreate_UAV : TexCreate_RenderTargetable;
const FScreenPassTextureViewport Viewport(Inputs.SceneColor);
const FScreenPassRenderTarget Output(GraphBuilder.CreateTexture(OutputDesc, TEXT("BloomSetup")), Viewport.Rect, View.GetOverwriteLoadAction());
if (bIsComputePass)
{
FBloomSetupCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FBloomSetupCS::FParameters>();
PassParameters->BloomSetup = GetBloomSetupParameters(View, Viewport, Inputs.SceneColor.Texture, Inputs.EyeAdaptationTexture, Inputs.Threshold);
PassParameters->RWOutputTexture = GraphBuilder.CreateUAV(Output.Texture);
TShaderMapRef<FBloomSetupCS> ComputeShader(View.ShaderMap);
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("BloomSetup %dx%d (CS)", Viewport.Rect.Width(), Viewport.Rect.Height()),
ComputeShader,
PassParameters,
FComputeShaderUtils::GetGroupCount(Viewport.Rect.Size(), FIntPoint(GBloomSetupComputeTileSizeX, GBloomSetupComputeTileSizeY)));
}
else
{
FBloomSetupPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FBloomSetupPS::FParameters>();
PassParameters->BloomSetup = GetBloomSetupParameters(View, Viewport, Inputs.SceneColor.Texture, Inputs.EyeAdaptationTexture, Inputs.Threshold);
PassParameters->SvPositionToInputTextureUV = (
FScreenTransform::ChangeTextureBasisFromTo(FScreenPassTextureViewport(Output), FScreenTransform::ETextureBasis::TexelPosition, FScreenTransform::ETextureBasis::ViewportUV) *
FScreenTransform::ChangeTextureBasisFromTo(FScreenPassTextureViewport(Inputs.SceneColor), FScreenTransform::ETextureBasis::ViewportUV, FScreenTransform::ETextureBasis::TextureUV));
PassParameters->RenderTargets[0] = Output.GetRenderTargetBinding();
TShaderMapRef<FBloomSetupPS> PixelShader(View.ShaderMap);
FPixelShaderUtils::AddFullscreenPass(
GraphBuilder,
View.ShaderMap,
RDG_EVENT_NAME("BloomSetup %dx%d (PS)", Viewport.Rect.Width(), Viewport.Rect.Height()),
PixelShader,
PassParameters,
Output.ViewRect);
}
return FScreenPassTexture(Output);
}
EBloomQuality GetBloomQuality()
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.BloomQuality"));
return static_cast<EBloomQuality>(FMath::Clamp(
CVar->GetValueOnRenderThread(),
static_cast<int32>(EBloomQuality::Disabled),
static_cast<int32>(EBloomQuality::MAX) - 1));
}
static_assert(
static_cast<uint32>(EBloomQuality::MAX) == FSceneDownsampleChain::StageCount,
"The total number of stages in the scene downsample chain and the number of bloom quality levels must match.");
FScreenPassTexture AddGaussianBloomPasses(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FSceneDownsampleChain* SceneDownsampleChain)
{
check(SceneDownsampleChain);
check(!IsFFTBloomEnabled(View));
const FFinalPostProcessSettings& Settings = View.FinalPostProcessSettings;
const EBloomQuality BloomQuality = GetBloomQuality();
FScreenPassTexture PassOutputs;
if (BloomQuality != EBloomQuality::Disabled)
{
RDG_EVENT_SCOPE(GraphBuilder, "Bloom");
const float CrossBloom = CVarBloomCross.GetValueOnRenderThread();
const FVector2D CrossCenterWeight(FMath::Max(CrossBloom, 0.0f), FMath::Abs(CrossBloom));
check(BloomQuality != EBloomQuality::Disabled);
const uint32 BloomQualityIndex = static_cast<uint32>(BloomQuality);
const uint32 BloomQualityCountMax = static_cast<uint32>(EBloomQuality::MAX);
struct FBloomStage
{
const float Size;
const FLinearColor& Tint;
};
FBloomStage BloomStages[] =
{
{ Settings.Bloom6Size, Settings.Bloom6Tint },
{ Settings.Bloom5Size, Settings.Bloom5Tint },
{ Settings.Bloom4Size, Settings.Bloom4Tint },
{ Settings.Bloom3Size, Settings.Bloom3Tint },
{ Settings.Bloom2Size, Settings.Bloom2Tint },
{ Settings.Bloom1Size, Settings.Bloom1Tint }
};
const uint32 BloomQualityToSceneDownsampleStage[] =
{
static_cast<uint32>(-1), // Disabled (sentinel entry to preserve indices)
3, // Q1
3, // Q2
4, // Q3
5, // Q4
6 // Q5
};
static_assert(UE_ARRAY_COUNT(BloomStages) == BloomQualityCountMax, "Array must be one less than the number of bloom quality entries.");
static_assert(UE_ARRAY_COUNT(BloomQualityToSceneDownsampleStage) == BloomQualityCountMax, "Array must be one less than the number of bloom quality entries.");
check(BloomQualityIndex < BloomQualityCountMax);
// Use bloom quality to select the number of downsample stages to use for bloom.
const uint32 BloomStageCount = BloomQualityToSceneDownsampleStage[BloomQualityIndex];
const float TintScale = (1.0f / BloomQualityCountMax) * Settings.BloomIntensity;
for (uint32 StageIndex = 0, SourceIndex = BloomQualityCountMax - 1; StageIndex < BloomStageCount; ++StageIndex, --SourceIndex)
{
const FBloomStage& BloomStage = BloomStages[StageIndex];
if (BloomStage.Size > SMALL_NUMBER)
{
FGaussianBlurInputs PassInputs;
PassInputs.NameX = TEXT("BloomX");
PassInputs.NameY = TEXT("BloomY");
PassInputs.Filter = SceneDownsampleChain->GetTexture(SourceIndex);
PassInputs.Additive = PassOutputs;
PassInputs.CrossCenterWeight = FVector2f(CrossCenterWeight); // LWC_TODO: Precision loss
PassInputs.KernelSizePercent = BloomStage.Size * Settings.BloomSizeScale;
PassInputs.TintColor = BloomStage.Tint * TintScale;
PassOutputs = AddGaussianBlurPass(GraphBuilder, View, PassInputs);
}
}
}
return PassOutputs;
}