Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/ShaderPrint.cpp
guillaume abadie 223782df74 Adds missing SHADER_USE_PARAMETER_STRUCT() on some shader classes
#rb trivial

#ROBOMERGE-AUTHOR: guillaume.abadie
#ROBOMERGE-SOURCE: CL 18393957 in //UE5/Release-5.0/... via CL 18393975
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v896-18170469)

[CL 18393985 by guillaume abadie in ue5-release-engine-test branch]
2021-12-07 07:48:20 -05:00

449 lines
17 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ShaderPrint.h"
#include "ShaderPrintParameters.h"
#include "CommonRenderResources.h"
#include "Containers/DynamicRHIResourceArray.h"
#include "Engine/Engine.h"
#include "GlobalShader.h"
#include "PipelineStateCache.h"
#include "RenderGraphBuilder.h"
#include "SceneRendering.h"
#include "SystemTextures.h"
namespace ShaderPrint
{
// Console variables
TAutoConsoleVariable<int32> CVarEnable(
TEXT("r.ShaderPrintEnable"),
0,
TEXT("ShaderPrint debugging toggle.\n"),
ECVF_Cheat | ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarFontSize(
TEXT("r.ShaderPrintFontSize"),
8,
TEXT("ShaderPrint font size.\n"),
ECVF_Cheat | ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarFontSpacingX(
TEXT("r.ShaderPrintFontSpacingX"),
0,
TEXT("ShaderPrint horizontal spacing between symbols.\n"),
ECVF_Cheat | ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarFontSpacingY(
TEXT("r.ShaderPrintFontSpacingY"),
8,
TEXT("ShaderPrint vertical spacing between symbols.\n"),
ECVF_Cheat | ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarMaxValueCount(
TEXT("r.ShaderPrintMaxValueCount"),
2000,
TEXT("ShaderPrint output buffer size.\n"),
ECVF_Cheat | ECVF_RenderThreadSafe);
static uint32 GCharacterRequestCount = 0;
// Structure used by shader buffers to store values and symbols
struct ShaderPrintItem
{
FVector2D ScreenPos;
int32 Value;
int32 Type;
};
// Empty buffer for binding when ShaderPrint is disabled
class FEmptyBuffer : public FBufferWithRDG
{
public:
void InitRHI() override
{
if (!Buffer.IsValid())
{
FRHICommandList* UnusedCmdList = new FRHICommandList(FRHIGPUMask::All());
GetPooledFreeBuffer(*UnusedCmdList, FRDGBufferDesc::CreateStructuredDesc(sizeof(ShaderPrintItem), 1), Buffer, TEXT("EmptyShaderPrintValueBuffer"));
delete UnusedCmdList;
UnusedCmdList = nullptr;
}
}
};
FBufferWithRDG* GEmptyBuffer = new TGlobalResource<FEmptyBuffer>();
// Get value buffer size
// Note that if the ShaderPrint system is disabled we still want to bind a minimal buffer
static int32 GetMaxValueCount()
{
int32 MaxValueCount = FMath::Max(CVarMaxValueCount.GetValueOnRenderThread() + int32(GCharacterRequestCount), 0);
return IsEnabled() ? MaxValueCount : 0;
}
// Get symbol buffer size
// This is some multiple of the value buffer size to allow for maximum value->symbol expansion
static int32 GetMaxSymbolCount()
{
return GetMaxValueCount() * 12;
}
// ShaderPrint uniform buffer
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FUniformBufferParameters, "ShaderPrintUniform");
typedef TUniformBufferRef<FUniformBufferParameters> FUniformBufferRef;
// Fill the uniform buffer parameters
// Return a uniform buffer with values filled and with single frame lifetime
static FUniformBufferRef CreateUniformBuffer(const FShaderPrintData& Data)
{
FUniformBufferParameters Out;
Out.FontSize = Data.FontSize;
Out.Resolution = Data.Resolution;
Out.MaxValueCount = Data.MaxValueCount;
Out.MaxSymbolCount = Data.MaxSymbolCount;
return FUniformBufferRef::CreateUniformBufferImmediate(Out, UniformBuffer_SingleFrame);
}
// Fill the FShaderParameters parameters
void SetParameters(FRDGBuilder& GraphBuilder, const FViewInfo & View, FShaderParameters& OutParameters)
{
OutParameters.UniformBufferParameters = CreateUniformBuffer(View.ShaderPrintData);
OutParameters.RWValuesBuffer = GraphBuilder.CreateUAV(View.ShaderPrintData.ShaderPrintValueBuffer);
}
// Fill the FShaderParameters parameters
void SetParameters(FRDGBuilder& GraphBuilder, const FShaderPrintData& Data, FShaderParameters& OutParameters)
{
OutParameters.UniformBufferParameters = CreateUniformBuffer(Data);
OutParameters.RWValuesBuffer = GraphBuilder.CreateUAV(Data.ShaderPrintValueBuffer);
}
// Supported platforms
bool IsSupported(EShaderPlatform InShaderPlatform)
{
return RHISupportsComputeShaders(InShaderPlatform) && !IsHlslccShaderPlatform(InShaderPlatform);
}
void SetEnabled(bool bInEnabled)
{
CVarEnable->Set(bInEnabled);
}
void SetFontSize(int32 InFontSize)
{
CVarFontSize->Set(FMath::Clamp(InFontSize, 6, 128));
}
void SetMaxValueCount(int32 InMaxCount)
{
CVarMaxValueCount->Set(FMath::Max(256, InMaxCount));
}
void RequestSpaceForCharacters(uint32 MaxElementCount)
{
GCharacterRequestCount += MaxElementCount;
}
bool IsEnabled()
{
return CVarEnable.GetValueOnAnyThread() != 0;
}
bool IsEnabled(const FViewInfo& View)
{
return IsEnabled() && IsSupported(View.GetShaderPlatform());
}
// Shader to initialize the output value buffer
class FShaderInitValueBufferCS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FShaderInitValueBufferCS);
SHADER_USE_PARAMETER_STRUCT(FShaderInitValueBufferCS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<ShaderPrintItem>, RWValuesBuffer)
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(FGlobalShaderPermutationParameters const& Parameters)
{
return IsSupported(Parameters.Platform);
}
};
IMPLEMENT_GLOBAL_SHADER(FShaderInitValueBufferCS, "/Engine/Private/ShaderPrintDraw.usf", "InitValueBufferCS", SF_Compute);
// Shader to fill the indirect parameter arguments ready for the value->symbol compute pass
class FShaderBuildIndirectDispatchArgsCS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FShaderBuildIndirectDispatchArgsCS);
SHADER_USE_PARAMETER_STRUCT(FShaderBuildIndirectDispatchArgsCS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FUniformBufferParameters, UniformBufferParameters)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<ShaderPrintItem>, ValuesBuffer)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<ShaderPrintItem>, RWSymbolsBuffer)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWIndirectDispatchArgsBuffer)
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(FGlobalShaderPermutationParameters const& Parameters)
{
return IsSupported(Parameters.Platform);
}
};
IMPLEMENT_GLOBAL_SHADER(FShaderBuildIndirectDispatchArgsCS, "/Engine/Private/ShaderPrintDraw.usf", "BuildIndirectDispatchArgsCS", SF_Compute);
// Shader to read the values buffer and convert to the symbols buffer
class FShaderBuildSymbolBufferCS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FShaderBuildSymbolBufferCS);
SHADER_USE_PARAMETER_STRUCT(FShaderBuildSymbolBufferCS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FUniformBufferParameters, UniformBufferParameters)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<ShaderPrintItem>, ValuesBuffer)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<ShaderPrintItem>, RWSymbolsBuffer)
RDG_BUFFER_ACCESS(IndirectDispatchArgsBuffer, ERHIAccess::IndirectArgs)
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(FGlobalShaderPermutationParameters const& Parameters)
{
return IsSupported(Parameters.Platform);
}
};
IMPLEMENT_GLOBAL_SHADER(FShaderBuildSymbolBufferCS, "/Engine/Private/ShaderPrintDraw.usf", "BuildSymbolBufferCS", SF_Compute);
// Shader to fill the indirect parameter arguments ready for draw pass
class FShaderBuildIndirectDrawArgsCS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FShaderBuildIndirectDrawArgsCS);
SHADER_USE_PARAMETER_STRUCT(FShaderBuildIndirectDrawArgsCS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FUniformBufferParameters, UniformBufferParameters)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<ShaderPrintItem>, SymbolsBuffer)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, RWIndirectDrawArgsBuffer)
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(FGlobalShaderPermutationParameters const& Parameters)
{
return IsSupported(Parameters.Platform);
}
};
IMPLEMENT_GLOBAL_SHADER(FShaderBuildIndirectDrawArgsCS, "/Engine/Private/ShaderPrintDraw.usf", "BuildIndirectDrawArgsCS", SF_Compute);
// Shader for draw pass to render each symbol
class FShaderDrawSymbols : public FGlobalShader
{
public:
FShaderDrawSymbols()
{}
FShaderDrawSymbols(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
RENDER_TARGET_BINDING_SLOTS()
SHADER_PARAMETER_STRUCT_REF(FUniformBufferParameters, UniformBufferParameters)
SHADER_PARAMETER_TEXTURE(Texture2D, MiniFontTexture)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<ShaderPrintItem>, SymbolsBuffer)
RDG_BUFFER_ACCESS(IndirectDrawArgsBuffer, ERHIAccess::IndirectArgs)
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(FGlobalShaderPermutationParameters const& Parameters)
{
return IsSupported(Parameters.Platform);
}
};
class FShaderDrawSymbolsVS : public FShaderDrawSymbols
{
DECLARE_GLOBAL_SHADER(FShaderDrawSymbolsVS);
SHADER_USE_PARAMETER_STRUCT(FShaderDrawSymbolsVS, FShaderDrawSymbols);
};
IMPLEMENT_GLOBAL_SHADER(FShaderDrawSymbolsVS, "/Engine/Private/ShaderPrintDraw.usf", "DrawSymbolsVS", SF_Vertex);
class FShaderDrawSymbolsPS : public FShaderDrawSymbols
{
DECLARE_GLOBAL_SHADER(FShaderDrawSymbolsPS);
SHADER_USE_PARAMETER_STRUCT(FShaderDrawSymbolsPS, FShaderDrawSymbols);
};
IMPLEMENT_GLOBAL_SHADER(FShaderDrawSymbolsPS, "/Engine/Private/ShaderPrintDraw.usf", "DrawSymbolsPS", SF_Pixel);
void BeginView(FRDGBuilder& GraphBuilder, FViewInfo& View)
{
TRACE_CPUPROFILER_EVENT_SCOPE(ShaderPrint::BeginView);
View.ShaderPrintData = FShaderPrintData();
if (!IsSupported(View.GetShaderPlatform()))
{
return;
}
const FIntPoint Resolution(FMath::Max(View.UnconstrainedViewRect.Size().X, 1), FMath::Max(View.UnconstrainedViewRect.Size().Y, 1));
const float FontWidth = (float)FMath::Max(CVarFontSize.GetValueOnRenderThread(), 1) / (float)Resolution.X;
const float FontHeight = (float)FMath::Max(CVarFontSize.GetValueOnRenderThread(), 1) / (float)Resolution.Y;
const float SpaceWidth = (float)FMath::Max(CVarFontSpacingX.GetValueOnRenderThread(), 1) / (float)Resolution.X;
const float SpaceHeight = (float)FMath::Max(CVarFontSpacingY.GetValueOnRenderThread(), 1) / (float)Resolution.Y;
View.ShaderPrintData.FontSize = FVector4f(FontWidth, FontHeight, SpaceWidth + FontWidth, SpaceHeight + FontHeight);
View.ShaderPrintData.Resolution = Resolution;
View.ShaderPrintData.MaxValueCount = GetMaxValueCount();
View.ShaderPrintData.MaxSymbolCount = GetMaxSymbolCount();
GCharacterRequestCount = 0;
// Early out if system is disabled
// Note that we still bind a dummy ShaderPrintValueBuffer
// This is in case some debug shader code is still active (we don't want an unbound buffer!)
if (!IsEnabled())
{
View.ShaderPrintData.ShaderPrintValueBuffer = GraphBuilder.RegisterExternalBuffer(GEmptyBuffer->Buffer);
return;
}
// Initialize output buffer and store in the view info
// Values buffer contains Count + 1 elements. The first element is only used as a counter.
View.ShaderPrintData.ShaderPrintValueBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(ShaderPrintItem), View.ShaderPrintData.MaxValueCount + 1), TEXT("ShaderPrintValueBuffer"));
// Clear the output buffer internal counter ready for use
const ERHIFeatureLevel::Type FeatureLevel = View.GetFeatureLevel();
FGlobalShaderMap* GlobalShaderMap = GetGlobalShaderMap(FeatureLevel);
TShaderMapRef< FShaderInitValueBufferCS > ComputeShader(GlobalShaderMap);
auto* PassParameters = GraphBuilder.AllocParameters<FShaderInitValueBufferCS::FParameters>();
PassParameters->RWValuesBuffer = GraphBuilder.CreateUAV(View.ShaderPrintData.ShaderPrintValueBuffer);
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("ShaderPrintBeginView"),
ComputeShader,
PassParameters,
FIntVector(1, 1, 1));
}
void DrawView(FRDGBuilder& GraphBuilder, const FViewInfo& View, FRDGTextureRef OutputTexture)
{
check(OutputTexture);
RDG_EVENT_SCOPE(GraphBuilder, "ShaderPrintDrawView");
// Initialize graph managed resources
// Symbols buffer contains Count + 1 elements. The first element is only used as a counter.
FRDGBufferRef SymbolBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(ShaderPrintItem), GetMaxSymbolCount() + 1), TEXT("ShaderPrintSymbolBuffer"));
FRDGBufferRef IndirectDispatchArgsBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc(4), TEXT("ShaderPrintIndirectDispatchArgs"));
FRDGBufferRef IndirectDrawArgsBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc(5), TEXT("ShaderPrintIndirectDrawArgs"));
// Non graph managed resources
FUniformBufferRef UniformBuffer = CreateUniformBuffer(View.ShaderPrintData);
FRDGBufferSRVRef ValuesBuffer = GraphBuilder.CreateSRV(View.ShaderPrintData.ShaderPrintValueBuffer);
FTextureRHIRef FontTexture = GSystemTextures.AsciiTexture->GetRenderTargetItem().ShaderResourceTexture;
const ERHIFeatureLevel::Type FeatureLevel = View.GetFeatureLevel();
FGlobalShaderMap* GlobalShaderMap = GetGlobalShaderMap(FeatureLevel);
// BuildIndirectDispatchArgs
{
typedef FShaderBuildIndirectDispatchArgsCS SHADER;
TShaderMapRef<SHADER> ComputeShader(GlobalShaderMap);
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
PassParameters->UniformBufferParameters = UniformBuffer;
PassParameters->ValuesBuffer = ValuesBuffer;
PassParameters->RWSymbolsBuffer = GraphBuilder.CreateUAV(SymbolBuffer, EPixelFormat::PF_R32_UINT);
PassParameters->RWIndirectDispatchArgsBuffer = GraphBuilder.CreateUAV(IndirectDispatchArgsBuffer, EPixelFormat::PF_R32_UINT);
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("BuildIndirectDispatchArgs"),
ComputeShader, PassParameters,
FIntVector(1, 1, 1));
}
// BuildSymbolBuffer
{
typedef FShaderBuildSymbolBufferCS SHADER;
TShaderMapRef<SHADER> ComputeShader(GlobalShaderMap);
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
PassParameters->UniformBufferParameters = UniformBuffer;
PassParameters->ValuesBuffer = ValuesBuffer;
PassParameters->RWSymbolsBuffer = GraphBuilder.CreateUAV(SymbolBuffer, EPixelFormat::PF_R32_UINT);
PassParameters->IndirectDispatchArgsBuffer = IndirectDispatchArgsBuffer;
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("BuildSymbolBuffer"),
ComputeShader, PassParameters,
IndirectDispatchArgsBuffer, 0);
}
// BuildIndirectDrawArgs
{
typedef FShaderBuildIndirectDrawArgsCS SHADER;
TShaderMapRef<SHADER> ComputeShader(GlobalShaderMap);
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
PassParameters->UniformBufferParameters = UniformBuffer;
PassParameters->SymbolsBuffer = GraphBuilder.CreateSRV(SymbolBuffer);
PassParameters->RWIndirectDrawArgsBuffer = GraphBuilder.CreateUAV(IndirectDrawArgsBuffer, EPixelFormat::PF_R32_UINT);
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("BuildIndirectDrawArgs"),
ComputeShader, PassParameters,
FIntVector(1, 1, 1));
}
// DrawSymbols
{
typedef FShaderDrawSymbols SHADER;
TShaderMapRef< FShaderDrawSymbolsVS > VertexShader(GlobalShaderMap);
TShaderMapRef< FShaderDrawSymbolsPS > PixelShader(GlobalShaderMap);
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
PassParameters->RenderTargets[0] = FRenderTargetBinding(OutputTexture, ERenderTargetLoadAction::ELoad);
PassParameters->UniformBufferParameters = UniformBuffer;
PassParameters->MiniFontTexture = FontTexture;
PassParameters->SymbolsBuffer = GraphBuilder.CreateSRV(SymbolBuffer);
PassParameters->IndirectDrawArgsBuffer = IndirectDrawArgsBuffer;
GraphBuilder.AddPass(
RDG_EVENT_NAME("DrawSymbols"),
PassParameters,
ERDGPassFlags::Raster,
[VertexShader, PixelShader, PassParameters](FRHICommandList& RHICmdListImmediate)
{
FGraphicsPipelineStateInitializer GraphicsPSOInit;
RHICmdListImmediate.ApplyCachedRenderTargets(GraphicsPSOInit);
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One>::GetRHI();
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4();
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
SetGraphicsPipelineState(RHICmdListImmediate, GraphicsPSOInit, 0);
SetShaderParameters(RHICmdListImmediate, VertexShader, VertexShader.GetVertexShader(), *PassParameters);
SetShaderParameters(RHICmdListImmediate, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
RHICmdListImmediate.DrawIndexedPrimitiveIndirect(GTwoTrianglesIndexBuffer.IndexBufferRHI, PassParameters->IndirectDrawArgsBuffer->GetIndirectRHICallBuffer(), 0);
});
}
}
void EndView(FViewInfo& View)
{
View.ShaderPrintData = FShaderPrintData();
}
}