Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/Substrate/SubstrateVisualize.cpp
2025-05-18 13:04:45 +08:00

1517 lines
66 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Substrate.h"
#include "SceneTextureParameters.h"
#include "ScenePrivate.h"
#include "SceneRendering.h"
#include "ScreenPass.h"
#include "ShaderCompiler.h"
#include "PixelShaderUtils.h"
#include "BasePassRendering.h"
#include "IndirectLightRendering.h"
#include "SubstrateVisualizationData.h"
#include "SubstrateVisualizeDefinitions.h"
#include "CanvasItem.h"
namespace Substrate
{
// Forward declarations
void AddSubstrateInternalClassificationTilePass(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FRDGTextureRef* DepthTexture,
const FRDGTextureRef* ColorTexture,
ESubstrateTileType TileMaterialType,
const bool bDebug);
static bool IsSubstrateDebugVisualizationSupported(EShaderPlatform InPlatform, bool bIsEditorOnly, EShaderPermutationFlags Flags)
{
return
Substrate::IsSubstrateEnabled() &&
Substrate::UsesSubstrateMaterialBuffer(InPlatform) &&
GetMaxSupportedFeatureLevel(InPlatform) >= ERHIFeatureLevel::SM5 &&
(bIsEditorOnly ? (IsPCPlatform(InPlatform) || EnumHasAllFlags(Flags, EShaderPermutationFlags::HasEditorOnlyData)) : true);
}
static bool SubstrateDebugVisualizationCanRunOnPlatform(EShaderPlatform InPlatform)
{
return IsSubstrateDebugVisualizationSupported(InPlatform, false, EShaderPermutationFlags::None);
}
class FMaterialPrintInfoCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FMaterialPrintInfoCS);
SHADER_USE_PARAMETER_STRUCT(FMaterialPrintInfoCS, FGlobalShader);
using FPermutationDomain = TShaderPermutationDomain<>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(uint32, bOverrideCursorPosition)
SHADER_PARAMETER(uint32, SubstrateDebugDataSizeInUints)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSubstrateGlobalUniformParameters, Substrate)
SHADER_PARAMETER_STRUCT_INCLUDE(FSceneTextureParameters, SceneTextures)
SHADER_PARAMETER_STRUCT_INCLUDE(ShaderPrint::FShaderParameters, ShaderPrintParameters)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<int>, SubstrateDebugDataUAV)
END_SHADER_PARAMETER_STRUCT()
static bool IsSupported(EShaderPlatform InPlatform, EShaderPermutationFlags InFlags=EShaderPermutationFlags::None)
{
return IsSubstrateDebugVisualizationSupported(InPlatform, false, InFlags);
}
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
{
return PermutationVector;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsSupported(Parameters.Platform, Parameters.Flags);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
ShaderPrint::ModifyCompilationEnvironment(Parameters, OutEnvironment);
// Stay debug and skip optimizations to reduce compilation time on this long shader.
OutEnvironment.CompilerFlags.Add(CFLAG_Debug);
OutEnvironment.SetDefine(TEXT("SHADER_MATERIALPRINT"), 1);
}
};
IMPLEMENT_GLOBAL_SHADER(FMaterialPrintInfoCS, "/Engine/Private/Substrate/SubstrateVisualize.usf", "MaterialPrintInfoCS", SF_Compute);
class FVisualizeMaterialCountPS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FVisualizeMaterialCountPS);
SHADER_USE_PARAMETER_STRUCT(FVisualizeMaterialCountPS, FGlobalShader);
using FPermutationDomain = TShaderPermutationDomain<>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(uint32, ViewMode)
SHADER_PARAMETER(uint32, bRealTimeUpdate)
SHADER_PARAMETER(uint32, bOverrideCursorPosition)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSubstrateGlobalUniformParameters, Substrate)
SHADER_PARAMETER_STRUCT_INCLUDE(FSceneTextureParameters, SceneTextures)
SHADER_PARAMETER_STRUCT_INCLUDE(ShaderPrint::FShaderParameters, ShaderPrintParameters)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool IsSupported(EShaderPlatform InPlatform, EShaderPermutationFlags InFlags=EShaderPermutationFlags::None)
{
return IsSubstrateDebugVisualizationSupported(InPlatform, false, InFlags);
}
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
{
return PermutationVector;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsSupported(Parameters.Platform, Parameters.Flags);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
ShaderPrint::ModifyCompilationEnvironment(Parameters, OutEnvironment);
// Stay debug and skip optimizations to reduce compilation time on this long shader.
OutEnvironment.CompilerFlags.Add(CFLAG_Debug);
OutEnvironment.SetDefine(TEXT("SHADER_MATERIALCOUNT"), 1);
}
};
IMPLEMENT_GLOBAL_SHADER(FVisualizeMaterialCountPS, "/Engine/Private/Substrate/SubstrateVisualize.usf", "VisualizeMaterialPS", SF_Pixel);
class FSubstrateSystemInfoCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FSubstrateSystemInfoCS);
SHADER_USE_PARAMETER_STRUCT(FSubstrateSystemInfoCS, FGlobalShader);
using FPermutationDomain = TShaderPermutationDomain<>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(uint32, SubstrateDebugDataSizeInUints)
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, ClassificationTileDrawIndirectBuffer)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSubstrateGlobalUniformParameters, Substrate)
SHADER_PARAMETER_STRUCT_INCLUDE(FSceneTextureParameters, SceneTextures)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<int>, SubstrateDebugDataUAV)
END_SHADER_PARAMETER_STRUCT()
static bool IsSupported(EShaderPlatform InPlatform, EShaderPermutationFlags InFlags=EShaderPermutationFlags::None)
{
return IsSubstrateDebugVisualizationSupported(InPlatform, false, InFlags);
}
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
{
return PermutationVector;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsSupported(Parameters.Platform, Parameters.Flags);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
ShaderPrint::ModifyCompilationEnvironment(Parameters, OutEnvironment);
// Stay debug and skip optimizations to reduce compilation time on this long shader.
OutEnvironment.CompilerFlags.Add(CFLAG_Debug);
OutEnvironment.SetDefine(TEXT("SHADER_SYSTEMINFO"), 1);
}
};
IMPLEMENT_GLOBAL_SHADER(FSubstrateSystemInfoCS, "/Engine/Private/Substrate/SubstrateVisualize.usf", "MainCS", SF_Compute);
class FMaterialDebugSubstrateTreeCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FMaterialDebugSubstrateTreeCS);
SHADER_USE_PARAMETER_STRUCT(FMaterialDebugSubstrateTreeCS, FGlobalShader);
using FPermutationDomain = TShaderPermutationDomain<>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(uint32, bOverrideCursorPosition)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSubstrateGlobalUniformParameters, Substrate)
SHADER_PARAMETER_STRUCT_INCLUDE(ShaderPrint::FShaderParameters, ShaderPrintParameters)
END_SHADER_PARAMETER_STRUCT()
static bool IsSupported(EShaderPlatform InPlatform, EShaderPermutationFlags InFlags=EShaderPermutationFlags::None)
{
return IsSubstrateDebugVisualizationSupported(InPlatform, true, InFlags)
&& !IsSubstrateBlendableGBufferEnabled(InPlatform)
&& !IsVulkanPlatform(InPlatform) // SUBSTRATE_TODO Move to CPU debug visualisation and it should then work on all platforms
&& !IsMetalPlatform(InPlatform);
}
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
{
return PermutationVector;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsSupported(Parameters.Platform, Parameters.Flags);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
ShaderPrint::ModifyCompilationEnvironment(Parameters, OutEnvironment);
// Stay debug and skip optimizations to reduce compilation time on this long shader.
OutEnvironment.CompilerFlags.Add(CFLAG_Debug);
OutEnvironment.SetDefine(TEXT("SHADER_DEBUGSUBSTRATETREE_CS"), 1);
}
};
IMPLEMENT_GLOBAL_SHADER(FMaterialDebugSubstrateTreeCS, "/Engine/Private/Substrate/SubstrateVisualize.usf", "MaterialDebugSubstrateTreeCS", SF_Compute);
class FMaterialDebugSubstrateTreePS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FMaterialDebugSubstrateTreePS);
SHADER_USE_PARAMETER_STRUCT(FMaterialDebugSubstrateTreePS, FGlobalShader);
using FPermutationDomain = TShaderPermutationDomain<>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(uint32, bOverrideCursorPosition)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSubstrateGlobalUniformParameters, Substrate)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FReflectionUniformParameters, ReflectionStruct)
SHADER_PARAMETER_STRUCT_REF(FReflectionCaptureShaderData, ReflectionCapture)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FForwardLightUniformParameters, ForwardLightStruct)
SHADER_PARAMETER_STRUCT_INCLUDE(FSkyDiffuseLightingParameters, SkyDiffuseLighting)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool IsSupported(EShaderPlatform InPlatform, EShaderPermutationFlags InFlags=EShaderPermutationFlags::None)
{
return IsSubstrateDebugVisualizationSupported(InPlatform, true, InFlags)
&& !IsSubstrateBlendableGBufferEnabled(InPlatform)
&& !IsVulkanPlatform(InPlatform) // SUBSTRATE_TODO Move to CPU debug visualisation and it should then work on all platforms
&& !IsMetalPlatform(InPlatform);
}
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
{
return PermutationVector;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsSupported(Parameters.Platform, Parameters.Flags);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
ShaderPrint::ModifyCompilationEnvironment(Parameters, OutEnvironment);
// Stay debug and skip optimizations to reduce compilation time on this long shader.
OutEnvironment.CompilerFlags.Add(CFLAG_Debug);
OutEnvironment.SetDefine(TEXT("SHADER_DEBUGSUBSTRATETREE_PS"), 1);
}
};
IMPLEMENT_GLOBAL_SHADER(FMaterialDebugSubstrateTreePS, "/Engine/Private/Substrate/SubstrateVisualize.usf", "MaterialDebugSubstrateTreePS", SF_Pixel);
void AddProcessAndPrintSubstrateMaterialPropertiesPasses(FRDGBuilder& GraphBuilder, const FViewInfo& View, FRDGTextureRef SceneColorTexture, EShaderPlatform Platform, FSubstrateViewDebugData::FTransientPixelDebugBuffer& NewSubstratePixelDebugBuffer)
{
if (!FMaterialPrintInfoCS::IsSupported(Platform)) return;
FSubstrateViewDebugData& SubstrateViewDebugData = View.ViewState->GetSubstrateViewDebugData();
////////////////////////////////////////////////////////////////////////////////////////////////////
// Check if the latest readback query is ready and display the data on screen.
TSharedPtr<FRHIGPUBufferReadback> AvailableReadback;
SubstrateViewDebugData.PixelMaterialDebugDataReadbackQueries.Peek(AvailableReadback);
if (AvailableReadback.IsValid() && AvailableReadback->IsReady())
{
SubstrateViewDebugData.PixelMaterialDebugDataReadbackQueries.Dequeue(AvailableReadback);
// Access the data and copy to a frame transient buffer for rendering pass.
void* PixelDebugData = AvailableReadback->Lock(SubstrateViewDebugData.PixelMaterialDebugDataSizeBytes);
if (PixelDebugData == nullptr)
{
return;
}
void* PixelDebugDataToPrint = GraphBuilder.Alloc(SubstrateViewDebugData.PixelMaterialDebugDataSizeBytes);
memcpy(PixelDebugDataToPrint, PixelDebugData, SubstrateViewDebugData.PixelMaterialDebugDataSizeBytes);
////////////////////////////////////////////////////////////////////////////////////////////////////
AddDrawCanvasPass(GraphBuilder, {}, View, FScreenPassRenderTarget(SceneColorTexture, View.ViewRect, ERenderTargetLoadAction::ELoad),
[&View, PixelDebugDataToPrint](FCanvas& Canvas)
{
Canvas.SetScaledToRenderTarget(true);
const FLinearColor Grey = FLinearColor(0.5f, 0.5f, 0.5f, 1.0f);
const FLinearColor Orange = FLinearColor(243.f / 255.f, 156.f / 255.f, 18.f / 255.f, 1.0);
const FLinearColor CompR = FLinearColor(0.8f, 0.2f, 0.2f, 1.0);
const FLinearColor CompG = FLinearColor(0.2f, 0.8f, 0.2f, 1.0);
const FLinearColor CompB = FLinearColor(0.2f, 0.2f, 0.8f, 1.0);
const float DrawPosXLeft = 40.0f;
float DrawPosX = DrawPosXLeft;
float DrawPosY = 50.0f;
FSubstrateDebugDataSerializer S;
S.SubstratePixelDebugData = (int*)PixelDebugDataToPrint;
FSubstratePixelDebugData Data;
SerializeSubstratePixelDebugData(S, Data);
FString MaterialMode;
switch (Data.MaterialMode)
{
case HEADER_MATERIALMODE_NONE:
MaterialMode = TEXT("None");
break;
case HEADER_MATERIALMODE_SLAB_SIMPLE:
MaterialMode = TEXT("Simple BSDF");
break;
case HEADER_MATERIALMODE_SLAB_SINGLE:
MaterialMode = TEXT("Single Slab");
break;
case HEADER_MATERIALMODE_SLAB_COMPLEX:
MaterialMode = TEXT("Complex Slab(s)");
break;
case HEADER_MATERIALMODE_SLWATER:
MaterialMode = TEXT("Single Layer Water");
break;
case HEADER_MATERIALMODE_HAIR:
MaterialMode = TEXT("Hair");
break;
case HEADER_MATERIALMODE_EYE:
MaterialMode = TEXT("Eye");
break;
default:
MaterialMode = TEXT("Unkown material mode, please update visualization code.");
}
if (Data.bIsComplexSpecialMaterial)
{
MaterialMode = TEXT("Complex Special Slab(s)");
}
FString OptimisedLegacyMode;
switch (Data.OptimisedLegacyMode)
{
case SINGLE_OPTLEGACYMODE_NONE:
break;
case SINGLE_OPTLEGACYMODE_CLEARCOAT:
MaterialMode += TEXT(" - Legacy Clear Coat");
break;
case SINGLE_OPTLEGACYMODE_CLOTH:
MaterialMode += TEXT(" - Legacy Cloth");
break;
case SINGLE_OPTLEGACYMODE_SSSWRAP:
MaterialMode += TEXT(" - Legacy SSS-Wrap");
break;
case SINGLE_OPTLEGACYMODE_SSSPROFILE:
MaterialMode += TEXT(" - Legacy SSS-Profile");
break;
case SINGLE_OPTLEGACYMODE_TWO_SIDED_SSSWRAP:
MaterialMode += TEXT(" - Legacy Two-Sided SSS-Wrap (Foliage)");
break;
default:
MaterialMode += TEXT(" - Unkown optimised legacy material mode, please update visualization code.");
}
TArray<FCanvasTextItem> TextItemsBatch; // Not very efficient but this is for debug purpose
FIntPoint BatchMinMaxY = FIntPoint(99999999, -99999999);
auto BeginBatch = [&]()
{
TextItemsBatch.Empty();
TextItemsBatch.Reserve(64);
BatchMinMaxY = FIntPoint(99999999, -99999999);
};
auto ExpendBatchBounds = [&](float X, float Y)
{
BatchMinMaxY = FIntPoint(FMath::Min(BatchMinMaxY.X, Y - 5), FMath::Max(BatchMinMaxY.Y, Y + 20));
};
auto DispatchBatch = [&]()
{
Canvas.DrawTile(DrawPosXLeft - 10.0f, BatchMinMaxY.X, 1000.0f, BatchMinMaxY.Y - BatchMinMaxY.X, 0, 0, 1, 1, FLinearColor(0.0, 0.0, 0.0, 0.3));
for (auto& Item : TextItemsBatch)
{
Canvas.DrawItem(Item);
}
};
auto PrintS = [&](float X, float Y, FString Text, FLinearColor Color = FLinearColor::White)
{
TextItemsBatch.Push(FCanvasTextItem(FVector2D(X, Y), FText::FromString(*Text), GEngine->GetSmallFont(), Color));
ExpendBatchBounds(X, Y);
};
auto PrintI = [&](float X, float Y, int Value, FLinearColor Color = FLinearColor::White)
{
FString String = FString::Printf(TEXT("%i"), Value);
TextItemsBatch.Push(FCanvasTextItem(FVector2D(X, Y), FText::FromString(*String), GetStatsFont(), Color));
ExpendBatchBounds(X, Y);
};
auto PrintUI = [&](float X, float Y, uint32 Value, FLinearColor Color = FLinearColor::White)
{
FString String = FString::Printf(TEXT("%u"), Value);
TextItemsBatch.Push(FCanvasTextItem(FVector2D(X, Y), FText::FromString(*String), GetStatsFont(), Color));
ExpendBatchBounds(X, Y);
};
auto PrintFSmall = [&](float X, float Y, float Value, FLinearColor Color = FLinearColor::White)
{
FString String = FString::Printf(TEXT("%1.3f"), Value);
TextItemsBatch.Push(FCanvasTextItem(FVector2D(X, Y), FText::FromString(*String), GetStatsFont(), Color));
ExpendBatchBounds(X, Y);
};
auto PrintFAdapt = [&](float X, float Y, float Value, FLinearColor Color = FLinearColor::White)
{
FString String;
if (Value > 100)
{
String = FString::Printf(TEXT("%.0f"), Value);
}
else if (Value > 10)
{
String = FString::Printf(TEXT("%2.2f"), Value);
}
else if (Value > 1)
{
String = FString::Printf(TEXT("%1.3f"), Value);
}
else
{
String = FString::Printf(TEXT("%0.4f"), Value);
}
TextItemsBatch.Push(FCanvasTextItem(FVector2D(X, Y), FText::FromString(*String), GetStatsFont(), Color));
ExpendBatchBounds(X, Y);
};
auto PrintFColorSmall = [&](float X, float Y, float R, float G, float B)
{
PrintFSmall(X + 0.0f, Y, R, CompR);
PrintFSmall(X + 40.0f, Y, G, CompG);
PrintFSmall(X + 80.0f, Y, B, CompB);
};
auto PrintFColorAdapt = [&](float X, float Y, float R, float G, float B)
{
PrintFAdapt(X + 0.0f, Y, R, CompR);
PrintFAdapt(X + 50.0f, Y, G, CompG);
PrintFAdapt(X + 100.0f, Y, B, CompB);
};
auto PrintF2DAdapt = [&](float X, float Y, float R, float G)
{
PrintFAdapt(X + 0.0f, Y, R, CompR);
PrintFAdapt(X + 50.0f, Y, G, CompG);
};
auto PrintFBool = [&](float X, float Y, float Value)
{
FString String = Value > 0.0f ? TEXT("Yes") : TEXT("No");
TextItemsBatch.Push(FCanvasTextItem(FVector2D(X, Y), FText::FromString(*String), GetStatsFont(), Value > 0.0f ? FLinearColor::Green : FLinearColor::Red));
ExpendBatchBounds(X, Y);
};
auto NewLine = [&]()
{
DrawPosY += 17;
};
// Header
{
BeginBatch();
PrintS(DrawPosX, DrawPosY, FString::Printf(TEXT("Closure Count = %i"), Data.ClosureCount), FLinearColor(0.2f, 0.8f, 0.2f, 1.0f));
PrintS(DrawPosX + 130.0f, DrawPosY, FString::Printf(TEXT("Material Mode = %s"), *MaterialMode), FLinearColor(0.7f, 0.7f, 0.0f, 1.0f));
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("AO"));
PrintS(DrawPosX + 50.0f, DrawPosY, TEXT("Ind.Irradiance"));
PrintS(DrawPosX + 150.0f, DrawPosY, TEXT("TopRoughness"));
PrintS(DrawPosX + 250.0f, DrawPosY, TEXT("PreShadow"));
PrintS(DrawPosX + 350.0f, DrawPosY, TEXT("ZeroShadow"));
PrintS(DrawPosX + 450.0f, DrawPosY, TEXT("ContactShadow"));
PrintS(DrawPosX + 550.0f, DrawPosY, TEXT("Ind.Occluder"));
PrintS(DrawPosX + 650.0f, DrawPosY, TEXT("HasSSS"));
PrintS(DrawPosX + 720.0f, DrawPosY, TEXT("BasisCount"));
NewLine();
PrintFSmall(DrawPosX + 0.0f, DrawPosY, Data.MaterialAO, Grey);
PrintFSmall(DrawPosX + 50.0f, DrawPosY, Data.IndirectIrradiance, Grey);
PrintFSmall(DrawPosX + 150.0f, DrawPosY, Data.TopLayerRoughness, Grey);
PrintFBool(DrawPosX + 250.0f, DrawPosY, Data.HasPrecShadowMask);
PrintFBool(DrawPosX + 350.0f, DrawPosY, Data.HasZeroPrecShadowMask);
PrintFBool(DrawPosX + 450.0f, DrawPosY, Data.DoesCastContactShadow);
PrintFBool(DrawPosX + 550.0f, DrawPosY, Data.HasDynamicIndirectShadowCasterRepresentation);
PrintFBool(DrawPosX + 650.0f, DrawPosY, Data.HasSubsurface);
PrintI(DrawPosX + 720.0f, DrawPosY, Data.LocalBasesCount, Grey);
DispatchBatch();
}
NewLine();
NewLine();
// Each Closure
for (int i = 0; i < Data.ClosureCount; ++i)
{
FSubsterateDebugClosure& Closure = Data.Closures[i];
BeginBatch();
FString Type;
switch (Closure.Type)
{
case SUBSTRATE_BSDF_TYPE_SLAB:
Type = TEXT("Slab");
break;
case SUBSTRATE_BSDF_TYPE_VOLUMETRICFOGCLOUD:
Type = TEXT("VolumetricFogCloud");
break;
case SUBSTRATE_BSDF_TYPE_UNLIT:
Type = TEXT("Unlit");
break;
case SUBSTRATE_BSDF_TYPE_HAIR:
Type = TEXT("Hair");
break;
case SUBSTRATE_BSDF_TYPE_SINGLELAYERWATER:
Type = TEXT("SingleLayerWater");
break;
case SUBSTRATE_BSDF_TYPE_EYE:
Type = TEXT("Eye");
break;
default:
MaterialMode = TEXT("Unkown closure type, please update visualization code.");
}
PrintS(DrawPosX, DrawPosY, Type, FLinearColor(0.2f, 1.0f, 0.2f, 1.0f));
PrintS(DrawPosX + 100.0f, DrawPosY, FString::Printf(TEXT("[Address=%i]"), Closure.Address), FLinearColor(0.2f, 0.5f, 0.5f, 1.0f));
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("NormalID"));
PrintS(DrawPosX + 100.0f, DrawPosY, TEXT("BasisType"));
PrintS(DrawPosX + 200.0f, DrawPosY, TEXT("Anisotropy"));
PrintS(DrawPosX + 300.0f, DrawPosY, TEXT("TopLayer"));
PrintS(DrawPosX + 400.0f, DrawPosY, TEXT("Scattering"));
PrintS(DrawPosX + 500.0f, DrawPosY, TEXT("IsThin"));
PrintS(DrawPosX + 550.0f, DrawPosY, TEXT("WeightV"));
if (Closure.bHasWeightL)
{
PrintS(DrawPosX + 700.0f, DrawPosY, TEXT("CoverAlongN"));
PrintS(DrawPosX + 800.0f, DrawPosY, TEXT("TransAlongN"));
}
NewLine();
PrintI(DrawPosX + 0.0f, DrawPosY, Closure.NormalID, Grey);
PrintS(DrawPosX + 100.0f, DrawPosY, Closure.BasisType == 0 ? TEXT("Normal") : TEXT("Nor+Tan"), Grey);
PrintFBool(DrawPosX + 200.0f, DrawPosY, Closure.bHasAnisotropy);
PrintFBool(DrawPosX + 300.0f, DrawPosY, Closure.bIsTopLayer);
PrintFBool(DrawPosX + 400.0f, DrawPosY, Closure.SSSType); // TODO: print the special type
PrintFBool(DrawPosX + 500.0f, DrawPosY, Closure.bIsThin);
if (Closure.bHasGreyWeightV)
{
PrintFSmall(DrawPosX + 550.0f, DrawPosY, Closure.LuminanceWeightR, Grey);
}
else
{
PrintFColorSmall(DrawPosX + 550.0f, DrawPosY, Closure.LuminanceWeightR, Closure.LuminanceWeightG, Closure.LuminanceWeightB);
}
if (Closure.bHasWeightL)
{
PrintFSmall(DrawPosX + 700.0f, DrawPosY, Closure.CoverageAboveAlongN, Grey);
PrintFColorSmall(DrawPosX + 800.0f, DrawPosY, Closure.TransmittanceAboveAlongNR, Closure.TransmittanceAboveAlongNG, Closure.TransmittanceAboveAlongNB);
}
NewLine();
DrawPosY += 5; // a little bit more space between the header and data
const float DataOffset = 130.0f;
if (Closure.Type == SUBSTRATE_BSDF_TYPE_SLAB)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Diffuse"), Orange);
PrintFColorSmall(DrawPosX + DataOffset, DrawPosY, Closure.DiffuseR, Closure.DiffuseG, Closure.DiffuseB);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("F0"), Orange);
PrintFColorSmall(DrawPosX + DataOffset, DrawPosY, Closure.F0R, Closure.F0G, Closure.F0B);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Roughness"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.Roughness);
NewLine();
if (Closure.bHasF90)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("F90"), Orange);
PrintFColorSmall(DrawPosX + DataOffset, DrawPosY, Closure.F90R, Closure.F90G, Closure.F90B);
NewLine();
}
if (Closure.bHasAnisotropy)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Anisotropy"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.Anisotropy);
NewLine();
}
if (Data.Closures[i].bHasHaziness)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Haziness"), Orange);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Weight"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].HazeWeight);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Roughness"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].HazeRoughness);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - LegacyClearCoat"), Orange);
PrintFBool(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].HazeSimpleClearCoatMode);
NewLine();
}
if (Closure.SSSType != SSS_TYPE_NONE || Closure.bIsThin)
{
if (Closure.SSSType == SSS_TYPE_WRAP || Closure.SSSType == SSS_TYPE_TWO_SIDED_WRAP)
{
if (Closure.SSSType == SSS_TYPE_WRAP)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("SSS Wrap (Legacy Subsurface)"), Orange);
}
else
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("SSS Two-Sided Wrap (Legacy Foliage)"), Orange);
}
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - MFP"), Orange);
PrintFColorAdapt(DrawPosX + DataOffset, DrawPosY, Closure.SSSMFPR, Closure.SSSMFPG, Closure.SSSMFPB);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Thickness"), Orange);
PrintFAdapt(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSThickness);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Phase"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSPhase);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Opacity"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSOpacity);
NewLine();
}
else if (Closure.SSSType == SSS_TYPE_SIMPLEVOLUME)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("SSS Simple Volume"), Orange);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - MFP"), Orange);
PrintFColorAdapt(DrawPosX + DataOffset, DrawPosY, Closure.SSSMFPR, Closure.SSSMFPG, Closure.SSSMFPB);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Thickness"), Orange);
PrintFAdapt(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSThickness);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Phase"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSPhase);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Opacity"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSOpacity);
NewLine();
}
else if (Closure.SSSType == SSS_TYPE_DIFFUSION_PROFILE)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("SSS Profile"), Orange);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - ProfileID"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSPRofileID);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - ProfileRadius"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSProfileRadius);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - MFP"), Orange);
PrintFColorAdapt(DrawPosX + DataOffset, DrawPosY, Closure.SSSMFPR, Closure.SSSMFPG, Closure.SSSMFPB);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Phase"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSPhase);
NewLine();
if (Closure.bIsThin)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Thickness"), Orange);
PrintFAdapt(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSThickness);
NewLine();
}
}
else if (Closure.SSSType == SSS_TYPE_DIFFUSION)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("SSS Substrate Per Pixel Diffusion"), Orange);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - MFP"), Orange);
PrintFColorAdapt(DrawPosX + DataOffset, DrawPosY, Closure.SSSMFPR, Closure.SSSMFPG, Closure.SSSMFPB);
NewLine();
if (Closure.bIsThin)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - MFPNorm"), Orange);
PrintFColorAdapt(DrawPosX + DataOffset, DrawPosY, Closure.SSSRescaledMFPR, Closure.SSSRescaledMFPG, Closure.SSSRescaledMFPB);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Thickness"), Orange);
PrintFAdapt(DrawPosX + DataOffset, DrawPosY, Closure.SSSThickness);
NewLine();
}
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Phase"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SSSPhase);
NewLine();
}
}
if (Data.Closures[i].FuzzAmount > 0.0f)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Fuzz"), Orange);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - FuzzAmount"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].FuzzAmount);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - FuzzColor"), Orange);
PrintFColorSmall(DrawPosX + DataOffset, DrawPosY, Closure.FuzzColorR, Closure.FuzzColorG, Closure.FuzzColorB);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - FuzzRoughness"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].FuzzRoughness);
NewLine();
}
if (Data.Closures[i].GlintValue < 1.0f)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Glints"), Orange);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Density"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].GlintValue);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - UV DDX"), Orange);
PrintF2DAdapt(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].GlintUVDDXx, Data.Closures[i].GlintUVDDXy);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - UV DDY"), Orange);
PrintF2DAdapt(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].GlintUVDDYx, Data.Closures[i].GlintUVDDYy);
NewLine();
}
if (Data.Closures[i].SpecProfileID >= 0)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Specular Profile"), Orange);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - SpecProfileID"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SpecProfileID);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - SpecProfileMode"), Orange);
PrintS(DrawPosX + DataOffset, DrawPosY, Data.Closures[i].SpecProfileParameterization == 0 ? TEXT("View/Light angles") : TEXT("Half angles"));
NewLine();
}
}
else if (Closure.Type == SUBSTRATE_BSDF_TYPE_HAIR)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("BaseColor"), Orange);
PrintFColorSmall(DrawPosX + DataOffset, DrawPosY, Closure.DiffuseR, Closure.DiffuseG, Closure.DiffuseB);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Specular"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.F0R);// Aliased variable for Hair BSDF
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Roughness"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.Roughness);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Scattering"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.F90R);// Aliased variable for Hair BSDF
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("BackLit"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.F90G);// Aliased variable for Hair BSDF
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Transmittance"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.F90B);// Aliased variable for Hair BSDF
NewLine();
}
else if (Closure.Type == SUBSTRATE_BSDF_TYPE_EYE)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Diffuse"), Orange);
PrintFColorSmall(DrawPosX + DataOffset, DrawPosY, Closure.DiffuseR, Closure.DiffuseG, Closure.DiffuseB);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("F0"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.F0R);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Roughness"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.Roughness);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("IrisMask"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.F90R);// Aliased variable for Eye BSDF
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("IrisDistance"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.F90G);// Aliased variable for Eye BSDF
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("IrisNormal"), Orange);
PrintFColorSmall(DrawPosX + DataOffset, DrawPosY, Closure.SSSMFPR, Closure.SSSMFPG, Closure.SSSMFPB);// Aliased variable for Eye BSDF
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("IrisPlaneNormal"), Orange);
PrintFColorSmall(DrawPosX + DataOffset, DrawPosY, Closure.SSSRescaledMFPR, Closure.SSSRescaledMFPG, Closure.SSSRescaledMFPB);// Aliased variable for Eye BSDF
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("SSSPRofileID"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Closure.SSSPRofileID);
NewLine();
}
else if (Closure.Type == SUBSTRATE_BSDF_TYPE_SINGLELAYERWATER)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("BaseColor"), Orange);
PrintFColorSmall(DrawPosX + DataOffset, DrawPosY, Closure.DiffuseR, Closure.DiffuseG, Closure.DiffuseB);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Specular"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.F0R);// Aliased variable for SLW BSDF
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Metallic"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.F0G);// Aliased variable for SLW BSDF
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Roughness"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.Roughness);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("TopMatOpacity"), Orange);
PrintFSmall(DrawPosX + DataOffset, DrawPosY, Closure.SSSOpacity);
NewLine();
}
DispatchBatch();
NewLine();
NewLine();
}
// Footer
{
BeginBatch();
const float DataOffset = 130.0f;
PrintS(DrawPosX, DrawPosY, TEXT("Memory Transactions"), FLinearColor(0.2f, 1.0f, 0.2f, 1.0f));
NewLine();
if (Data.MemoryDisplayMode > 0)
{
if (Data.MemoryDisplayMode == 1)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Header + BSDF"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.MemorySlotA);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - TopNormalTex"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.MemorySlotB);
NewLine();
}
else if (Data.MemoryDisplayMode == 2)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Header"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.MemorySlotA);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - TopNormalTex"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.MemorySlotB);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - BSDF"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.MemorySlotC);
NewLine();
}
else if (Data.MemoryDisplayMode == 3)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Header + Normals"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.MemorySlotA);
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - BSDFs"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.MemorySlotB);
NewLine();
}
else
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("Unkown Memory Display Mode"), FLinearColor::Red);
}
if (Data.MemorySSSData > 0)
{
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - SSS Data"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.MemorySSSData);
NewLine();
}
}
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT(" - Total"), Orange);
PrintI(DrawPosX + DataOffset, DrawPosY, Data.MemoryTotal);
NewLine();
NewLine();
DispatchBatch();
}
BeginBatch();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("GPUFrameNumber"), FLinearColor::White);
PrintUI(DrawPosX + 150, DrawPosY, *(uint32*)(&Data.GPUFrameNumber));
NewLine();
PrintS(DrawPosX + 0.0f, DrawPosY, TEXT("CPUFrameNumber"), FLinearColor::White);
PrintUI(DrawPosX + 150, DrawPosY, View.CachedViewUniformShaderParameters->FrameNumber);
NewLine();
DispatchBatch();
});
////////////////////////////////////////////////////////////////////////////////////////////////////
AvailableReadback->Unlock();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Copy the debug data on GPU into a readback buffer for debug display when available later.
TSharedPtr<FRHIGPUBufferReadback> NewReadBack = MakeShared<FRHIGPUBufferReadback>(TEXT("PixelMaterialDebugDataReadback"));
AddEnqueueCopyPass(GraphBuilder, NewReadBack.Get(), NewSubstratePixelDebugBuffer.DebugData, SubstrateViewDebugData.PixelMaterialDebugDataSizeBytes);
SubstrateViewDebugData.PixelMaterialDebugDataReadbackQueries.Enqueue(NewReadBack);
}
static void AddVisualizeMaterialPropertiesPasses(FRDGBuilder& GraphBuilder, const FViewInfo& View, FScreenPassTexture& ScreenPassSceneColor, EShaderPlatform Platform)
{
if (!FMaterialPrintInfoCS::IsSupported(Platform) || !View.ViewState) return;
FSubstrateViewDebugData& SubstrateViewDebugData = View.ViewState->GetSubstrateViewDebugData();
// Force ShaderPrint on.
ShaderPrint::SetEnabled(true);
ShaderPrint::RequestSpaceForLines(1024);
ShaderPrint::RequestSpaceForCharacters(1024);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Get a new pixel material buffer and render debug data into it
FSubstrateViewDebugData::FTransientPixelDebugBuffer NewSubstratePixelDebugBuffer = SubstrateViewDebugData.CreateTransientPixelDebugBuffer(GraphBuilder);
{
FMaterialPrintInfoCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FMaterialPrintInfoCS::FParameters>();
PassParameters->bOverrideCursorPosition = WITH_EDITOR ? 0u : 1u;
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
PassParameters->Substrate = Substrate::BindSubstrateGlobalUniformParameters(View);
PassParameters->SceneTextures = GetSceneTextureParameters(GraphBuilder, View);
PassParameters->SubstrateDebugDataSizeInUints = NewSubstratePixelDebugBuffer.DebugDataSizeInUints;
PassParameters->SubstrateDebugDataUAV = NewSubstratePixelDebugBuffer.DebugDataUAV;
ShaderPrint::SetParameters(GraphBuilder, View.ShaderPrintData, PassParameters->ShaderPrintParameters);
TShaderMapRef<FMaterialPrintInfoCS> ComputeShader(View.ShaderMap);
FComputeShaderUtils::AddPass(GraphBuilder, RDG_EVENT_NAME("Substrate::VisualizeMaterial(Print)"), ComputeShader, PassParameters, FIntVector(1, 1, 1));
}
AddProcessAndPrintSubstrateMaterialPropertiesPasses(GraphBuilder, View, ScreenPassSceneColor.Texture, Platform, NewSubstratePixelDebugBuffer);
}
static void AddVisualizeMaterialCountPasses(FRDGBuilder & GraphBuilder, const FViewInfo & View, FScreenPassTexture & ScreenPassSceneColor, EShaderPlatform Platform, uint32 ViewMode)
{
if (!FVisualizeMaterialCountPS::IsSupported(Platform)) return;
ShaderPrint::SetEnabled(true);
ShaderPrint::RequestSpaceForLines(1024);
ShaderPrint::RequestSpaceForCharacters(1024);
FRDGTextureRef SceneColorTexture = ScreenPassSceneColor.Texture;
FRHIBlendState* PreMultipliedColorTransmittanceBlend = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_SourceAlpha, BO_Add, BF_Zero, BF_One>::GetRHI();
FVisualizeMaterialCountPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVisualizeMaterialCountPS::FParameters>();
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
PassParameters->ViewMode = FMath::Clamp(ViewMode, 2, 3);
PassParameters->bRealTimeUpdate = View.Family->bRealtimeUpdate ? 1 : 0;
PassParameters->bOverrideCursorPosition = WITH_EDITOR ? 0u : 1u;
PassParameters->Substrate = Substrate::BindSubstrateGlobalUniformParameters(View);
PassParameters->SceneTextures = GetSceneTextureParameters(GraphBuilder, View);
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture, ERenderTargetLoadAction::ELoad);
ShaderPrint::SetParameters(GraphBuilder, View.ShaderPrintData, PassParameters->ShaderPrintParameters);
FVisualizeMaterialCountPS::FPermutationDomain PermutationVector;
TShaderMapRef<FVisualizeMaterialCountPS> PixelShader(View.ShaderMap, PermutationVector);
FPixelShaderUtils::AddFullscreenPass<FVisualizeMaterialCountPS>(GraphBuilder, View.ShaderMap, RDG_EVENT_NAME("Substrate::VisualizeMaterial(Draw)"), PixelShader, PassParameters, ScreenPassSceneColor.ViewRect, PreMultipliedColorTransmittanceBlend);
}
bool IsClassificationAsync();
bool SupportsCMask(const FStaticShaderPlatform InPlatform);
bool UsesSubstrateClosureCountFromMaterialData();
uint32 GetMaterialBufferAllocationMode();
bool Is8bitTileCoordEnabled();
static void AddVisualizeSystemInfoPasses(FRDGBuilder& GraphBuilder, const FViewInfo& View, FScreenPassTexture& ScreenPassSceneColor, EShaderPlatform Platform)
{
if (!FSubstrateSystemInfoCS::IsSupported(Platform) || !View.ViewState)
{
return;
}
// Force ShaderPrint on.
ShaderPrint::SetEnabled(true);
ShaderPrint::RequestSpaceForLines(1024);
ShaderPrint::RequestSpaceForCharacters(1024);
const FRDGTextureDesc MaterialBufferDesc = View.SubstrateViewData.SceneData->MaterialTextureArray->Desc;
const FShadingEnergyConservationData ShadingEnergyConservationData = ShadingEnergyConservation::GetData(View);
FSubstrateSystemInfoCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FSubstrateSystemInfoCS::FParameters>();
PassParameters->ClassificationTileDrawIndirectBuffer = GraphBuilder.CreateSRV(View.SubstrateViewData.ClassificationTileDrawIndirectBuffer, PF_R32_UINT);
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
PassParameters->Substrate = Substrate::BindSubstrateGlobalUniformParameters(View);
PassParameters->SceneTextures = GetSceneTextureParameters(GraphBuilder, View);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Get a new pixel material buffer and render debug data into it
FSubstrateViewDebugData& SubstrateViewDebugData = View.ViewState->GetSubstrateViewDebugData();
FSubstrateViewDebugData::FTransientSystemInfoDebugBuffer NewSubstrateSystemInfoDebugBuffer = SubstrateViewDebugData.CreateTransientSystemInfoDebugBuffer(GraphBuilder);
PassParameters->SubstrateDebugDataSizeInUints = NewSubstrateSystemInfoDebugBuffer.DebugDataSizeInUints;
PassParameters->SubstrateDebugDataUAV = NewSubstrateSystemInfoDebugBuffer.DebugDataUAV;
TShaderMapRef<FSubstrateSystemInfoCS> ComputeShader(View.ShaderMap);
FComputeShaderUtils::AddPass(GraphBuilder, RDG_EVENT_NAME("Substrate::VisualizeSystemInfo"), ComputeShader, PassParameters, FIntVector(1, 1, 1));
struct FSystemInformation
{
int CurrentBytesPerPixel;
int ProjectMaxBytesPerPixel;
int MaterialBufferAllocationInBytes;
int ViewsMaxBytesPerPixel;
int CurrentClosuresPerPixel;
int ViewsMaxClosuresPerPixel;
int ProjectMaxClosuresPerPixel;
int MaterialBufferAllocationMode;
int ShadingQuality;
int bRoughDiffuse;
int bEnergyConservation;
int bEnergyPreservation;
int bUseClosureCountFromMaterialData;
int TileClosureCount;
int bDbufferPass;
int bRoughRefraction;
int TileSize;
int TileCountX;
int TileCountY;
int bCMask;
int bAsync;
int b8BitsCoord;
int bAdvancedDebugEnabled;
int LayerPeelIndex;
} SystemInformation;
SystemInformation.CurrentBytesPerPixel = View.SubstrateViewData.SceneData->EffectiveMaxBytesPerPixel;
SystemInformation.ProjectMaxBytesPerPixel = GetBytePerPixel(View.GetShaderPlatform());
SystemInformation.MaterialBufferAllocationInBytes = MaterialBufferDesc.Extent.X * MaterialBufferDesc.Extent.Y * MaterialBufferDesc.ArraySize * sizeof(uint32);
SystemInformation.ViewsMaxBytesPerPixel = View.SubstrateViewData.SceneData->ViewsMaxBytesPerPixel;
SystemInformation.CurrentClosuresPerPixel = View.SubstrateViewData.SceneData->EffectiveMaxClosurePerPixel;
SystemInformation.ViewsMaxClosuresPerPixel = View.SubstrateViewData.SceneData->ViewsMaxClosurePerPixel;
SystemInformation.ProjectMaxClosuresPerPixel = GetClosurePerPixel(View.GetShaderPlatform());
SystemInformation.MaterialBufferAllocationMode = GetMaterialBufferAllocationMode();
SystemInformation.ShadingQuality = Substrate::GetShadingQuality(View.GetShaderPlatform());
SystemInformation.bRoughDiffuse = View.SubstrateViewData.SceneData->bRoughDiffuse;
SystemInformation.bEnergyConservation = ShadingEnergyConservationData.bEnergyConservation;
SystemInformation.bEnergyPreservation = ShadingEnergyConservationData.bEnergyPreservation;
SystemInformation.bUseClosureCountFromMaterialData = UsesSubstrateClosureCountFromMaterialData() ? 1 : 0;
SystemInformation.TileClosureCount = GetSubstrateMaxClosureCount(View);
SystemInformation.bDbufferPass = IsDBufferPassEnabled(View.GetShaderPlatform()) ? 1 : 0;
SystemInformation.bRoughRefraction = IsOpaqueRoughRefractionEnabled(View.GetShaderPlatform()) ? 1 : 0;
SystemInformation.TileSize = SUBSTRATE_TILE_SIZE;
SystemInformation.TileCountX = View.SubstrateViewData.TileCount.X;
SystemInformation.TileCountY = View.SubstrateViewData.TileCount.Y;
SystemInformation.bCMask = SupportsCMask(View.GetShaderPlatform()) ? 1 : 0;
SystemInformation.bAsync = IsClassificationAsync() ? 1 : 0;
SystemInformation.b8BitsCoord = Is8bitTileCoordEnabled() ? 1 : 0;
SystemInformation.bAdvancedDebugEnabled = IsAdvancedVisualizationEnabled() ? 1 : 0;
SystemInformation.LayerPeelIndex = View.SubstrateViewData.SceneData->PeelLayersAboveDepth;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Check if the latest readback query is ready and display the data on screen.
TSharedPtr<FRHIGPUBufferReadback> AvailableReadback;
SubstrateViewDebugData.SystemInfoDebugDataReadbackQueries.Peek(AvailableReadback);
if (AvailableReadback.IsValid() && AvailableReadback->IsReady())
{
SubstrateViewDebugData.SystemInfoDebugDataReadbackQueries.Dequeue(AvailableReadback);
// Access the data and copy to a frame transient buffer for rendering pass.
void* SystemInfoDebugData = AvailableReadback->Lock(SubstrateViewDebugData.SystemInfoDebugDataSizeBytes);
if (SystemInfoDebugData == nullptr)
{
return;
}
int* SystemInfoDebugDataToPrint = (int*)GraphBuilder.Alloc(SubstrateViewDebugData.SystemInfoDebugDataSizeBytes);
memcpy(SystemInfoDebugDataToPrint, SystemInfoDebugData, SubstrateViewDebugData.SystemInfoDebugDataSizeBytes);
////////////////////////////////////////////////////////////////////////////////////////////////////
AddDrawCanvasPass(GraphBuilder, {}, View, FScreenPassRenderTarget(ScreenPassSceneColor.Texture, View.ViewRect, ERenderTargetLoadAction::ELoad),
[&View, SystemInfoDebugDataToPrint, SystemInformation](FCanvas& Canvas)
{
Canvas.SetScaledToRenderTarget(true);
FSubstrateDebugDataSerializer S;
S.SubstratePixelDebugData = (int*)SystemInfoDebugDataToPrint;
FSubstrateSystemInfoData Data;
SerializeSubstrateSystemInfoDebugData(S, Data);
float DrawPosX = 50.0f;
float DrawPosY = 50.0f;
auto PrintI = [&](float X, float Y, int Value, FLinearColor Color = FLinearColor::White)
{
FString String = FString::Printf(TEXT("%i"), Value);
FCanvasTextItem Item = FCanvasTextItem(FVector2D(X, Y), FText::FromString(*String), GetStatsFont(), Color);
Canvas.DrawItem(Item);
};
auto PrintS = [&](float X, float Y, FString Text, FLinearColor Color = FLinearColor::White)
{
FCanvasTextItem Item = FCanvasTextItem(FVector2D(X, Y), FText::FromString(*Text), GEngine->GetSmallFont(), Color);
Canvas.DrawItem(Item);
};
auto PrintBool = [&](float X, float Y, int Value)
{
FString String = Value > 0.0f ? TEXT("Yes") : TEXT("No");
FCanvasTextItem Item = FCanvasTextItem(FVector2D(X, Y), FText::FromString(*String), GetStatsFont(), Value > 0.0f ? FLinearColor::Green : FLinearColor::Red);
Canvas.DrawItem(Item);
};
auto NewLine = [&]()
{
DrawPosY += 17;
};
Canvas.DrawTile(DrawPosX - 10.0f, DrawPosY - 10.0f, 350.0f, 700.0f, 0, 0, 1, 1, FLinearColor(0.0, 0.0, 0.0, 0.3));
const FLinearColor White = FLinearColor::White;
const FLinearColor Yellow = FLinearColor(1, 1, 0, 1);
const FLinearColor DarkYellow = FLinearColor(0.5, 0.5, 0, 1);
const FLinearColor Orange = FLinearColor(243.f / 255.f, 156.f / 255.f, 18.f / 255.f, 1.0);
FString Text;
PrintS(DrawPosX, DrawPosY, TEXT("General"), Yellow);
NewLine();
{
if (IsSubstrateBlendableGBufferEnabled(View.GetShaderPlatform()))
{
PrintS(DrawPosX, DrawPosY, TEXT(" Using blendable GBuffer with fixed layout."), DarkYellow);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Bytes Per Pixel"), White);
PrintI(DrawPosX + 150, DrawPosY, 4*4, Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Closures Per Pixel"), White);
PrintI(DrawPosX + 150, DrawPosY, 1, Orange);
}
else
{
PrintS(DrawPosX, DrawPosY, TEXT(" Bytes Per Pixel"), DarkYellow);
NewLine();
PrintS(DrawPosX + 0, DrawPosY, TEXT(" Max"), White);
PrintI(DrawPosX + 150, DrawPosY, SystemInformation.CurrentBytesPerPixel, Orange);
PrintS(DrawPosX + 180, DrawPosY, TEXT("/"), DarkYellow);
PrintI(DrawPosX + 190, DrawPosY, SystemInformation.ProjectMaxBytesPerPixel, Orange);
Text = FString::Printf(TEXT("[%i MB]"), SystemInformation.MaterialBufferAllocationInBytes / (1024 * 1024));
PrintS(DrawPosX + 220, DrawPosY, *Text, White);
NewLine();
PrintS(DrawPosX + 0, DrawPosY, TEXT(" Views"), White);
PrintI(DrawPosX + 150, DrawPosY, SystemInformation.ViewsMaxBytesPerPixel, Orange);
PrintS(DrawPosX + 180, DrawPosY, TEXT("/ "), DarkYellow);
PrintI(DrawPosX + 190, DrawPosY, SystemInformation.ProjectMaxBytesPerPixel, Orange);
NewLine();
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Closures Per Pixel"), DarkYellow);
NewLine();
PrintS(DrawPosX + 0, DrawPosY, TEXT(" Max"), White);
PrintI(DrawPosX + 150, DrawPosY, SystemInformation.CurrentClosuresPerPixel, Orange);
PrintS(DrawPosX + 180, DrawPosY, TEXT("/ "), DarkYellow);
PrintI(DrawPosX + 190, DrawPosY, SystemInformation.ProjectMaxClosuresPerPixel, Orange);
NewLine();
PrintS(DrawPosX + 0, DrawPosY, TEXT(" Views"), White);
PrintI(DrawPosX + 150, DrawPosY, SystemInformation.ViewsMaxClosuresPerPixel, Orange);
PrintS(DrawPosX + 180, DrawPosY, TEXT("/ "), DarkYellow);
PrintI(DrawPosX + 190, DrawPosY, SystemInformation.ProjectMaxClosuresPerPixel, Orange);
NewLine();
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Allocation mode"), White);
switch (SystemInformation.MaterialBufferAllocationMode)
{
case 0: PrintS(DrawPosX + 150, DrawPosY, TEXT("View based"), Orange); break;
case 1: PrintS(DrawPosX + 150, DrawPosY, TEXT("View based | Growing-only"), Orange); break;
case 2: PrintS(DrawPosX + 150, DrawPosY, TEXT("Setting based"), Orange); break;
default: PrintS(DrawPosX + 150, DrawPosY, TEXT("Unkown"), Orange); break;
}
}
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Shading quality"), White);
PrintI(DrawPosX + 150, DrawPosY, SystemInformation.ShadingQuality, Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Rough diffuse"), White);
PrintBool(DrawPosX + 150, DrawPosY, SystemInformation.bRoughDiffuse);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Energy conservation"), White);
PrintBool(DrawPosX + 150, DrawPosY, SystemInformation.bEnergyConservation);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Energy preservation"), White);
PrintBool(DrawPosX + 150, DrawPosY, SystemInformation.bEnergyPreservation);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Use #closures mat."), White);
PrintBool(DrawPosX + 150, DrawPosY, SystemInformation.bUseClosureCountFromMaterialData);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Tile closure Count"), White);
PrintI(DrawPosX + 150, DrawPosY, SystemInformation.TileClosureCount, Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" DBuffser pass"), White);
PrintBool(DrawPosX + 150, DrawPosY, SystemInformation.bDbufferPass);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Rough refraction"), White);
PrintBool(DrawPosX + 150, DrawPosY, SystemInformation.bRoughRefraction);
NewLine();
}
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT("Classification"), Yellow);
NewLine();
{
PrintS(DrawPosX, DrawPosY, TEXT(" Tile size"), White);
Text = FString::Printf(TEXT("%ix%i"), SystemInformation.TileSize, SystemInformation.TileSize);
PrintS(DrawPosX + 150, DrawPosY, *Text, Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Tile Resolution"), White);
Text = FString::Printf(TEXT("%ix%i"), SystemInformation.TileCountX, SystemInformation.TileCountY);
PrintS(DrawPosX + 150, DrawPosY, *Text, Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" CMask Classification"), White);
PrintBool(DrawPosX + 150, DrawPosY, SystemInformation.bCMask);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" Async Compute"), White);
PrintBool(DrawPosX + 150, DrawPosY, SystemInformation.bAsync);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" 8Bits coord"), White);
PrintBool(DrawPosX + 150, DrawPosY, SystemInformation.b8BitsCoord);
NewLine();
}
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT("Material Tiles"), Yellow);
NewLine();
{
PrintS(DrawPosX, DrawPosY, TEXT(" # Simple tiles"), White);
PrintI(DrawPosX + 150, DrawPosY, Data.TileCount[SUBSTRATE_TILE_TYPE_SIMPLE], Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" # Single tiles"), White);
PrintI(DrawPosX + 150, DrawPosY, Data.TileCount[SUBSTRATE_TILE_TYPE_SINGLE], Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" # Complex tiles"), White);
PrintI(DrawPosX + 150, DrawPosY, Data.TileCount[SUBSTRATE_TILE_TYPE_COMPLEX], Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" # Complex Special tiles"), White);
PrintI(DrawPosX + 150, DrawPosY, Data.TileCount[SUBSTRATE_TILE_TYPE_COMPLEX_SPECIAL], Orange);
NewLine();
if (SystemInformation.bRoughRefraction)
{
PrintS(DrawPosX, DrawPosY, TEXT(" # Rough refract. tiles"), White);
PrintI(DrawPosX + 150, DrawPosY, Data.TileCount[SUBSTRATE_TILE_TYPE_ROUGH_REFRACT], Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" # Rough r. w/o SSS tiles"), White);
PrintI(DrawPosX + 150, DrawPosY, Data.TileCount[SUBSTRATE_TILE_TYPE_ROUGH_REFRACT_SSS_WITHOUT], Orange);
NewLine();
}
if (SystemInformation.bDbufferPass)
{
PrintS(DrawPosX, DrawPosY, TEXT(" # Decal Simple tiles"), White);
PrintI(DrawPosX + 150, DrawPosY, Data.TileCount[SUBSTRATE_TILE_TYPE_DECAL_SIMPLE], Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" # Decal Single tiles"), White);
PrintI(DrawPosX + 150, DrawPosY, Data.TileCount[SUBSTRATE_TILE_TYPE_DECAL_SINGLE], Orange);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" # Decal Complex tiles"), White);
PrintI(DrawPosX + 150, DrawPosY, Data.TileCount[SUBSTRATE_TILE_TYPE_DECAL_COMPLEX], Orange);
NewLine();
}
}
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT("Debug"), Yellow);
NewLine();
{
PrintS(DrawPosX, DrawPosY, TEXT(" # ADv. Debug"), White);
PrintBool(DrawPosX + 150, DrawPosY, SystemInformation.bAdvancedDebugEnabled);
NewLine();
PrintS(DrawPosX, DrawPosY, TEXT(" # Decal Complex tiles"), White);
PrintI(DrawPosX + 150, DrawPosY, SystemInformation.LayerPeelIndex, Orange);
NewLine();
}
NewLine();
});
////////////////////////////////////////////////////////////////////////////////////////////////////
AvailableReadback->Unlock();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Copy the debug data on GPU into a readback buffer for debug display when available later.
TSharedPtr<FRHIGPUBufferReadback> NewReadBack = MakeShared<FRHIGPUBufferReadback>(TEXT("SystemInfoDebugDataReadback"));
AddEnqueueCopyPass(GraphBuilder, NewReadBack.Get(), NewSubstrateSystemInfoDebugBuffer.DebugData, SubstrateViewDebugData.SystemInfoDebugDataSizeBytes);
SubstrateViewDebugData.SystemInfoDebugDataReadbackQueries.Enqueue(NewReadBack);
}
// Draw each material layer independently
static void AddVisualizeAdvancedMaterialPasses(FRDGBuilder& GraphBuilder, const FViewInfo& View, FScreenPassTexture& ScreenPassSceneColor, EShaderPlatform Platform)
{
if (!IsAdvancedVisualizationEnabled() ||
!FMaterialDebugSubstrateTreeCS::IsSupported(Platform) ||
!FMaterialDebugSubstrateTreePS::IsSupported(Platform))
{
return;
}
ShaderPrint::SetEnabled(true);
ShaderPrint::RequestSpaceForLines(1024);
ShaderPrint::RequestSpaceForCharacters(1024);
FRDGTextureRef SceneColorTexture = ScreenPassSceneColor.Texture;
FRHIBlendState* PreMultipliedColorTransmittanceBlend = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_SourceAlpha, BO_Add, BF_Zero, BF_One>::GetRHI();
{
FMaterialDebugSubstrateTreeCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FMaterialDebugSubstrateTreeCS::FParameters>();
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
PassParameters->Substrate = Substrate::BindSubstrateGlobalUniformParameters(View);
PassParameters->bOverrideCursorPosition = WITH_EDITOR ? 0u : 1u;
ShaderPrint::SetParameters(GraphBuilder, View.ShaderPrintData, PassParameters->ShaderPrintParameters);
TShaderMapRef<FMaterialDebugSubstrateTreeCS> ComputeShader(View.ShaderMap);
FComputeShaderUtils::AddPass(GraphBuilder, RDG_EVENT_NAME("Substrate::SubstrateAdvancedVisualization(Print)"), ComputeShader, PassParameters, FIntVector(1, 1, 1));
}
{
FMaterialDebugSubstrateTreePS::FParameters* PassParameters = GraphBuilder.AllocParameters<FMaterialDebugSubstrateTreePS::FParameters>();
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
PassParameters->Substrate = Substrate::BindSubstrateGlobalUniformParameters(View);
PassParameters->bOverrideCursorPosition = WITH_EDITOR ? 0u : 1u;
PassParameters->ReflectionStruct = CreateReflectionUniformBuffer(GraphBuilder, View);
PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
PassParameters->ForwardLightStruct = View.ForwardLightingResources.ForwardLightUniformBuffer;
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture, ERenderTargetLoadAction::ELoad);
const float DynamicBentNormalAO = 0.0f;
FSkyLightSceneProxy* NullSkyLight = nullptr;
PassParameters->SkyDiffuseLighting = GetSkyDiffuseLightingParameters(NullSkyLight, DynamicBentNormalAO);
FMaterialDebugSubstrateTreePS::FPermutationDomain PermutationVector;
TShaderMapRef<FMaterialDebugSubstrateTreePS> PixelShader(View.ShaderMap, PermutationVector);
FPixelShaderUtils::AddFullscreenPass<FMaterialDebugSubstrateTreePS>(GraphBuilder, View.ShaderMap, RDG_EVENT_NAME("Substrate::SubstrateAdvancedVisualization(Draw)"), PixelShader, PassParameters, ScreenPassSceneColor.ViewRect, PreMultipliedColorTransmittanceBlend);
}
}
bool ShouldRenderSubstrateRoughRefractionRnD();
void SubstrateRoughRefractionRnD(FRDGBuilder& GraphBuilder, const FViewInfo& View, FScreenPassTexture& ScreenPassSceneColor);
static FSubstrateViewMode GetSubstrateVisualizeMode(const FViewInfo & View)
{
FSubstrateViewMode Out = FSubstrateViewMode::None;
if (IsSubstrateEnabled() && SubstrateDebugVisualizationCanRunOnPlatform(View.GetShaderPlatform()))
{
const uint32 ViewMode = FSubstrateVisualizationData::GetViewMode();
switch (ViewMode)
{
case 1: return FSubstrateViewMode::MaterialProperties;
case 2: return FSubstrateViewMode::MaterialCount;
case 3: return FSubstrateViewMode::AdvancedMaterialProperties;
case 4: return FSubstrateViewMode::MaterialClassification;
case 5: return FSubstrateViewMode::DecalClassification;
case 6: return FSubstrateViewMode::RoughRefractionClassification;
case 7: return FSubstrateViewMode::SubstrateInfo;
case 8: return FSubstrateViewMode::MaterialByteCount;
}
const FSubstrateVisualizationData& VisualizationData = GetSubstrateVisualizationData();
if (View.Family && View.Family->EngineShowFlags.VisualizeSubstrate)
{
Out = VisualizationData.GetViewMode(View.CurrentSubstrateVisualizationMode);
}
}
return Out;
}
bool ShouldRenderSubstrateDebugPasses(const FViewInfo& View)
{
return GetSubstrateVisualizeMode(View) != FSubstrateViewMode::None || ShouldRenderSubstrateRoughRefractionRnD();
}
FScreenPassTexture AddSubstrateDebugPasses(FRDGBuilder& GraphBuilder, const FViewInfo& View, FScreenPassTexture& ScreenPassSceneColor)
{
check(IsSubstrateEnabled());
const FSubstrateViewMode DebugMode = GetSubstrateVisualizeMode(View);
if (DebugMode != FSubstrateViewMode::None)
{
RDG_EVENT_SCOPE(GraphBuilder, "Substrate::VisualizeMaterial");
const bool bDebugPass = true;
if (DebugMode == FSubstrateViewMode::MaterialProperties)
{
AddVisualizeMaterialPropertiesPasses(GraphBuilder, View, ScreenPassSceneColor, View.GetShaderPlatform());
}
if (DebugMode == FSubstrateViewMode::MaterialCount)
{
AddVisualizeMaterialCountPasses(GraphBuilder, View, ScreenPassSceneColor, View.GetShaderPlatform(), 2);
}
if (DebugMode == FSubstrateViewMode::MaterialByteCount)
{
AddVisualizeMaterialCountPasses(GraphBuilder, View, ScreenPassSceneColor, View.GetShaderPlatform(), 3);
}
if (DebugMode == FSubstrateViewMode::AdvancedMaterialProperties)
{
AddVisualizeAdvancedMaterialPasses(GraphBuilder, View, ScreenPassSceneColor, View.GetShaderPlatform());
}
else if (DebugMode == FSubstrateViewMode::SubstrateInfo)
{
AddVisualizeSystemInfoPasses(GraphBuilder, View, ScreenPassSceneColor, View.GetShaderPlatform());
}
else if (DebugMode == FSubstrateViewMode::DecalClassification)
{
if (IsDBufferPassEnabled(View.GetShaderPlatform()))
{
AddSubstrateInternalClassificationTilePass(GraphBuilder, View, nullptr, &ScreenPassSceneColor.Texture, ESubstrateTileType::EDecalSimple, bDebugPass);
AddSubstrateInternalClassificationTilePass(GraphBuilder, View, nullptr, &ScreenPassSceneColor.Texture, ESubstrateTileType::EDecalSingle, bDebugPass);
AddSubstrateInternalClassificationTilePass(GraphBuilder, View, nullptr, &ScreenPassSceneColor.Texture, ESubstrateTileType::EDecalComplex, bDebugPass);
}
}
else if (DebugMode == FSubstrateViewMode::RoughRefractionClassification)
{
if (IsOpaqueRoughRefractionEnabled(View.GetShaderPlatform()))
{
AddSubstrateInternalClassificationTilePass(GraphBuilder, View, nullptr, &ScreenPassSceneColor.Texture, ESubstrateTileType::EOpaqueRoughRefraction, bDebugPass);
AddSubstrateInternalClassificationTilePass(GraphBuilder, View, nullptr, &ScreenPassSceneColor.Texture, ESubstrateTileType::EOpaqueRoughRefractionSSSWithout, bDebugPass);
}
}
else if (DebugMode == FSubstrateViewMode::MaterialClassification)
{
if (GetSubstrateUsesComplexSpecialPath(View))
{
AddSubstrateInternalClassificationTilePass(GraphBuilder, View, nullptr, &ScreenPassSceneColor.Texture, ESubstrateTileType::EComplexSpecial, bDebugPass);
}
AddSubstrateInternalClassificationTilePass(GraphBuilder, View, nullptr, &ScreenPassSceneColor.Texture, ESubstrateTileType::EComplex, bDebugPass);
AddSubstrateInternalClassificationTilePass(GraphBuilder, View, nullptr, &ScreenPassSceneColor.Texture, ESubstrateTileType::ESingle, bDebugPass);
AddSubstrateInternalClassificationTilePass(GraphBuilder, View, nullptr, &ScreenPassSceneColor.Texture, ESubstrateTileType::ESimple, bDebugPass);
}
}
SubstrateRoughRefractionRnD(GraphBuilder, View, ScreenPassSceneColor);
return MoveTemp(ScreenPassSceneColor);
}
} // namespace Substrate
FSubstrateViewDebugData::FSubstrateViewDebugData()
{
//
}
template<typename T>
static T InternalCreateTransientPixelDebugBuffer(FRDGBuilder& GraphBuilder, uint32 DataSizeInBytes, const TCHAR* Name)
{
T Out;
const uint32 SizeOfUint = sizeof(uint32);
const uint32 NumUints = FMath::DivideAndRoundUp(DataSizeInBytes, SizeOfUint);
FRDGBufferDesc RDGBufferDesc = FRDGBufferDesc::CreateStructuredDesc(SizeOfUint, NumUints);
RDGBufferDesc.Usage |= BUF_SourceCopy;
Out.DebugDataSizeInUints = NumUints;
Out.DebugData = GraphBuilder.CreateBuffer(RDGBufferDesc, Name);
Out.DebugDataUAV = GraphBuilder.CreateUAV(FRDGBufferUAVDesc(Out.DebugData, PF_R32_UINT));
return Out;
}
FSubstrateViewDebugData::FTransientPixelDebugBuffer FSubstrateViewDebugData::CreateTransientPixelDebugBuffer(FRDGBuilder& GraphBuilder)
{
FTransientPixelDebugBuffer Out = InternalCreateTransientPixelDebugBuffer<FSubstrateViewDebugData::FTransientPixelDebugBuffer>(GraphBuilder, sizeof(FSubstratePixelDebugData), TEXT("PixelMaterialDebugData"));
PixelMaterialDebugDataSizeBytes = Out.DebugDataSizeInUints * sizeof(uint32);
return Out;
}
FSubstrateViewDebugData::FTransientPixelDebugBuffer FSubstrateViewDebugData::CreateDummyPixelDebugBuffer(FRDGBuilder& GraphBuilder)
{
return InternalCreateTransientPixelDebugBuffer<FSubstrateViewDebugData::FTransientPixelDebugBuffer>(GraphBuilder, sizeof(uint32), TEXT("DummyPixelMaterialDebugData"));
}
FSubstrateViewDebugData::FTransientSystemInfoDebugBuffer FSubstrateViewDebugData::CreateTransientSystemInfoDebugBuffer(FRDGBuilder& GraphBuilder)
{
FSubstrateViewDebugData::FTransientSystemInfoDebugBuffer Out = InternalCreateTransientPixelDebugBuffer<FSubstrateViewDebugData::FTransientSystemInfoDebugBuffer>(GraphBuilder, SUBSTRATE_TILE_TYPE_COUNT * sizeof(uint32), TEXT("SystemInfoDebugData"));
SystemInfoDebugDataSizeBytes = Out.DebugDataSizeInUints * sizeof(uint32);
return Out;
}
void FSubstrateViewDebugData::SafeRelease()
{
TSharedPtr<FRHIGPUBufferReadback> It;
while (PixelMaterialDebugDataReadbackQueries.Dequeue(It))
{
It.Reset();
}
while (SystemInfoDebugDataReadbackQueries.Dequeue(It))
{
It.Reset();
}
}