1005 lines
44 KiB
C++
1005 lines
44 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "NaniteVisualize.h"
|
|
#include "DataDrivenShaderPlatformInfo.h"
|
|
#include "NaniteVisualizationData.h"
|
|
#include "PostProcess/SceneFilterRendering.h"
|
|
#include "PostProcess/PostProcessing.h"
|
|
#include "PostProcess/PostProcessVisualizeComplexity.h"
|
|
#include "PostProcess/SceneRenderTargets.h"
|
|
#include "PixelShaderUtils.h"
|
|
#include "ScenePrivate.h"
|
|
#include "SceneTextureReductions.h"
|
|
#include "PrimitiveDrawingUtils.h"
|
|
#include "Rendering/NaniteStreamingManager.h"
|
|
#include "DebugViewModeHelpers.h"
|
|
#include "Materials/Material.h"
|
|
#include "Materials/MaterialRenderProxy.h"
|
|
#include "MeshPaintVisualize.h"
|
|
#include "NaniteSceneProxy.h"
|
|
#include "ShaderPrint.h"
|
|
#include "InstanceDataSceneProxy.h"
|
|
#include "Nanite/NaniteMaterialsSceneExtension.h"
|
|
#include "NaniteEditor.h"
|
|
#include "NaniteDefinitions.h"
|
|
|
|
// Specifies if visualization only shows Nanite information that passes full scene depth test
|
|
// -1: Use default composition specified the each mode
|
|
// 0: Force composition with scene depth off
|
|
// 1: Force composition with scene depth on
|
|
int32 GNaniteVisualizeComposite = -1;
|
|
FAutoConsoleVariableRef CVarNaniteVisualizeComposite(
|
|
TEXT("r.Nanite.Visualize.Composite"),
|
|
GNaniteVisualizeComposite,
|
|
TEXT("")
|
|
);
|
|
|
|
int32 GNaniteVisualizeEdgeDetect = 1;
|
|
static FAutoConsoleVariableRef CVarNaniteVisualizeEdgeDetect(
|
|
TEXT("r.Nanite.Visualize.EdgeDetect"),
|
|
GNaniteVisualizeEdgeDetect,
|
|
TEXT("")
|
|
);
|
|
|
|
int32 GNaniteVisualizeOverdrawScale = 15; // % of contribution per pixel evaluation (up to 100%)
|
|
FAutoConsoleVariableRef CVarNaniteVisualizeOverdrawScale(
|
|
TEXT("r.Nanite.Visualize.OverdrawScale"),
|
|
GNaniteVisualizeOverdrawScale,
|
|
TEXT("")
|
|
);
|
|
|
|
int32 GNaniteVisualizeComplexityScale = 80; // % of contribution per material evaluation (up to 100%)
|
|
FAutoConsoleVariableRef CVarNaniteVisualizeComplexityScale(
|
|
TEXT("r.Nanite.Visualize.ComplexityScale"),
|
|
GNaniteVisualizeComplexityScale,
|
|
TEXT("")
|
|
);
|
|
|
|
// Fudge factor chosen by visually comparing Nanite vs non-Nanite cube shader complexity using default material, and choosing value where colors match.
|
|
int32 GNaniteVisualizeComplexityOverhead = 7400; // Baseline overhead of Nanite ALU (added to global shader budget)
|
|
FAutoConsoleVariableRef CVarNaniteVisualizeComplexityOverhead(
|
|
TEXT("r.Nanite.Visualize.ComplexityOverhead"),
|
|
GNaniteVisualizeComplexityOverhead,
|
|
TEXT("")
|
|
);
|
|
|
|
int32 GNanitePickingDomain = NANITE_PICKING_DOMAIN_TRIANGLE;
|
|
FAutoConsoleVariableRef CVarNanitePickingDomain(
|
|
TEXT("r.Nanite.Picking.Domain"),
|
|
GNanitePickingDomain,
|
|
TEXT("")
|
|
);
|
|
|
|
int32 GNanitePixelProgrammableVisMode = NANITE_PIXEL_PROG_VIS_MODE_DEFAULT;
|
|
FAutoConsoleVariableRef CVarNanitePixelProgrammableVisMode(
|
|
TEXT("r.Nanite.Visualize.PixelProgrammableVisMode"),
|
|
GNanitePixelProgrammableVisMode,
|
|
TEXT("0: Show masked, pixel depth offset, and dynamic displacement materials.\n")
|
|
TEXT("1: Show masked materials only.\n")
|
|
TEXT("2: Show pixel depth offset only.\n")
|
|
TEXT("3: Show dynamic displacement only.")
|
|
);
|
|
|
|
static uint32 GetMeshPaintVisualizationModeArg()
|
|
{
|
|
// Pack for shader unpacking in GetMeshPaintingShowMode(), GetMeshPaintingChannelMode() and GetMeshPaintingTextureMode().
|
|
// Assumes that EMeshPaintVisualizeShowMode matches NANITE_MESH_PAINTING_SHOW_*
|
|
const uint32 ShowMode = MeshPaintVisualize::GetShowMode();
|
|
// Assumes EVertexColorViewMode enums matches NANITE_MESH_PAINTING_CHANNELS_*
|
|
const uint32 ChannelMode = MeshPaintVisualize::GetChannelMode();
|
|
const uint32 TextureMode = MeshPaintVisualize::GetTextureAsset_RenderThread() == nullptr ? NANITE_MESH_PAINTING_TEXTURE_DEFAULT : NANITE_MESH_PAINTING_TEXTURE_ASSET;
|
|
return (ShowMode & 0x1) | ((ChannelMode & 0x7) << 1) | ((TextureMode & 0x1) << 4);
|
|
}
|
|
|
|
static FIntVector4 GetVisualizeConfig(int32 ModeID, bool bCompositeScene, bool bEdgeDetect)
|
|
{
|
|
if (ModeID != INDEX_NONE)
|
|
{
|
|
int32 ModeArg = 0;
|
|
switch (ModeID)
|
|
{
|
|
case NANITE_VISUALIZE_PICKING:
|
|
ModeArg = GNanitePickingDomain;
|
|
break;
|
|
case NANITE_VISUALIZE_PIXEL_PROGRAMMABLE_RASTER:
|
|
ModeArg = GNanitePixelProgrammableVisMode;
|
|
break;
|
|
case NANITE_VISUALIZE_VERTEX_COLOR:
|
|
case NANITE_VISUALIZE_MESH_PAINT_TEXTURE:
|
|
ModeArg = GetMeshPaintVisualizationModeArg();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return FIntVector4(ModeID, ModeArg, bCompositeScene ? 1 : 0, bEdgeDetect ? 1 : 0);
|
|
}
|
|
|
|
return FIntVector4(INDEX_NONE, 0, 0, 0);
|
|
}
|
|
|
|
static FIntVector4 GetVisualizeScales(int32 ModeID, uint32 ShadingExportCount)
|
|
{
|
|
if (ModeID != INDEX_NONE)
|
|
{
|
|
return FIntVector4(GNaniteVisualizeOverdrawScale, GNaniteVisualizeComplexityScale, int32(ShadingExportCount), 0 /* Unused */);
|
|
}
|
|
|
|
return FIntVector4(INDEX_NONE, 0, 0, 0);
|
|
}
|
|
|
|
static bool VisualizationRequiresHiZDecode(int32 ModeID)
|
|
{
|
|
switch (ModeID)
|
|
{
|
|
case NANITE_VISUALIZE_SCENE_Z_MIN:
|
|
case NANITE_VISUALIZE_SCENE_Z_MAX:
|
|
case NANITE_VISUALIZE_SCENE_Z_DELTA:
|
|
case NANITE_VISUALIZE_SCENE_Z_DECODED:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
class FNaniteVisualizeCS : public FNaniteGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FNaniteVisualizeCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FNaniteVisualizeCS, FNaniteGlobalShader);
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportNanite(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FNaniteGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("NANITE_USE_VIEW_UNIFORM_BUFFER"), 1);
|
|
}
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, DebugOutput)
|
|
SHADER_PARAMETER(FIntVector4, VisualizeConfig)
|
|
SHADER_PARAMETER(FIntVector4, VisualizeScales)
|
|
SHADER_PARAMETER(FIntVector4, PageConstants)
|
|
SHADER_PARAMETER(uint32, MaxVisibleClusters)
|
|
SHADER_PARAMETER(uint32, RenderFlags)
|
|
SHADER_PARAMETER(uint32, RegularMaterialRasterBinCount)
|
|
SHADER_PARAMETER(uint32, FixedFunctionBin)
|
|
SHADER_PARAMETER(FIntPoint, PickingPixelPos)
|
|
SHADER_PARAMETER(uint32, NumEditorSelectedHitProxyIds)
|
|
SHADER_PARAMETER(uint32, MeshPaintTextureCoordinate)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneUniformParameters, Scene)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FVirtualShadowMapUniformParameters, VirtualShadowMap)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, ClusterPageData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, HierarchyBuffer)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, VisibleClustersSWHW)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, ShadingBinData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FNaniteRasterBinMeta>, RasterBinMeta)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UlongType>, VisBuffer64)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UlongType>, DbgBuffer64)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, DbgBuffer32)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, ShadingMask)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float>, SceneDepth)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float>, SceneZDecoded)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<FUint32Vector4>, SceneZLayout)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, FastClearTileVis)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, MaterialHitProxyTable)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, EditorSelectedHitProxyIds)
|
|
SHADER_PARAMETER_TEXTURE(Texture2D<float4>, MeshPaintTexture)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
};
|
|
IMPLEMENT_GLOBAL_SHADER(FNaniteVisualizeCS, "/Engine/Private/Nanite/NaniteVisualize.usf", "VisualizeCS", SF_Compute);
|
|
|
|
class FNanitePickingCS : public FNaniteGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FNanitePickingCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FNanitePickingCS, FNaniteGlobalShader);
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportNanite(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FNaniteGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("NANITE_USE_VIEW_UNIFORM_BUFFER"), 1);
|
|
}
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(ShaderPrint::FShaderParameters, ShaderPrintUniformBuffer)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<FNanitePickingFeedback>, FeedbackBuffer)
|
|
SHADER_PARAMETER(FIntVector4, VisualizeConfig)
|
|
SHADER_PARAMETER(FIntVector4, PageConstants)
|
|
SHADER_PARAMETER(uint32, MaxVisibleClusters)
|
|
SHADER_PARAMETER(uint32, RenderFlags)
|
|
SHADER_PARAMETER(uint32, RegularMaterialRasterBinCount)
|
|
SHADER_PARAMETER(FIntPoint, PickingPixelPos)
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneUniformParameters, Scene)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, ShadingBinData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, ClusterPageData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, HierarchyBuffer)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, VisibleClustersSWHW)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UlongType>, VisBuffer64)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UlongType>, DbgBuffer64)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, DbgBuffer32)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, ShadingMask)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float>, SceneDepth)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, MaterialHitProxyTable)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
};
|
|
IMPLEMENT_GLOBAL_SHADER(FNanitePickingCS, "/Engine/Private/Nanite/NaniteVisualize.usf", "PickingCS", SF_Compute);
|
|
|
|
class FDepthDecodeCS : public FNaniteGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FDepthDecodeCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FDepthDecodeCS, FNaniteGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FPackedView>, InViews)
|
|
SHADER_PARAMETER(FUint32Vector4, ViewRect)
|
|
SHADER_PARAMETER(FUint32Vector4, HTileConfig)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<float>, SceneDepth)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, ShadingMask)
|
|
SHADER_PARAMETER_RDG_TEXTURE_SRV(TextureMetadata, SceneHTileBuffer)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float>, SceneZDecoded)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<FUint32Vector4>, SceneZLayout)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportNanite(Parameters.Platform);
|
|
}
|
|
};
|
|
IMPLEMENT_GLOBAL_SHADER(FDepthDecodeCS, "/Engine/Private/Nanite/NaniteDepthDecode.usf", "DepthDecode", SF_Compute);
|
|
|
|
#if WITH_DEBUG_VIEW_MODES
|
|
|
|
class FExportDebugViewPS : public FNaniteGlobalShader
|
|
{
|
|
public:
|
|
DECLARE_GLOBAL_SHADER(FExportDebugViewPS);
|
|
SHADER_USE_PARAMETER_STRUCT(FExportDebugViewPS, FNaniteGlobalShader);
|
|
|
|
static const uint32 kMSAASampleCountMaxLog2 = 3; // = log2(MSAASampleCountMax)
|
|
class FSampleCountDimension : SHADER_PERMUTATION_RANGE_INT("MSAA_SAMPLE_COUNT_LOG2", 0, kMSAASampleCountMaxLog2 + 1);
|
|
using FPermutationDomain = TShaderPermutationDomain<FSampleCountDimension>;
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneUniformParameters, Scene)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, VisibleClustersSWHW)
|
|
SHADER_PARAMETER(FIntVector4, PageConstants)
|
|
SHADER_PARAMETER(FIntVector4, ViewRect)
|
|
SHADER_PARAMETER(float, InvShaderBudget)
|
|
SHADER_PARAMETER(FVector3f, SelectionColor)
|
|
SHADER_PARAMETER(FVector3f, OverlayIntensityColor)
|
|
SHADER_PARAMETER(uint32, DebugViewMode)
|
|
SHADER_PARAMETER(uint32, NumEditorSelectedHitProxyIds)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, ClusterPageData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, HierarchyBuffer)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UlongType>, VisBuffer64)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float>, SceneDepth)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, ShadingMask)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, DebugViewData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, MaterialHitProxyTable)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, EditorSelectedHitProxyIds)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, ShadingBinData)
|
|
RENDER_TARGET_BINDING_SLOTS()
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool IsPlatformSupported(EShaderPlatform ShaderPlatform)
|
|
{
|
|
return DoesPlatformSupportNanite(ShaderPlatform) && FDataDrivenShaderPlatformInfo::GetSupportsDebugViewShaders(ShaderPlatform);
|
|
}
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsPlatformSupported(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FNaniteGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("NANITE_USE_VIEW_UNIFORM_BUFFER"), 1);
|
|
|
|
const FPermutationDomain PermutationVector(Parameters.PermutationId);
|
|
const int32 SampleCount = 1 << PermutationVector.Get<FSampleCountDimension>();
|
|
OutEnvironment.SetDefine(TEXT("MSAA_SAMPLE_COUNT"), SampleCount);
|
|
|
|
// Note: Must match EDebugViewMode in NaniteVisualize.h
|
|
OutEnvironment.SetDefine(TEXT("DEBUG_VIEW_NONE"), (uint32)Nanite::EDebugViewMode::None);
|
|
OutEnvironment.SetDefine(TEXT("DEBUG_VIEW_WIREFRAME"), (uint32)Nanite::EDebugViewMode::Wireframe);
|
|
OutEnvironment.SetDefine(TEXT("DEBUG_VIEW_SHADER_COMPLEXITY"), (uint32)Nanite::EDebugViewMode::ShaderComplexity);
|
|
OutEnvironment.SetDefine(TEXT("DEBUG_VIEW_LIGHTMAP_DENSITY"), (uint32)Nanite::EDebugViewMode::LightmapDensity);
|
|
OutEnvironment.SetDefine(TEXT("DEBUG_VIEW_PRIMITIVE_COLOR"), (uint32)Nanite::EDebugViewMode::PrimitiveColor);
|
|
OutEnvironment.SetDefine(TEXT("DEBUG_VIEW_LWC_COMPLEXITY"), (uint32)Nanite::EDebugViewMode::LWCComplexity);
|
|
|
|
OutEnvironment.SetDefine(TEXT("MATERIAL_DEBUG_VIEW_INFO_STRIDE"), (uint32)sizeof(FNaniteMaterialDebugViewInfo::FPacked));
|
|
}
|
|
};
|
|
IMPLEMENT_GLOBAL_SHADER(FExportDebugViewPS, "/Engine/Private/Nanite/NaniteDebugViews.usf", "ExportDebugViewPS", SF_Pixel);
|
|
|
|
extern float GMaxLWCComplexity;
|
|
|
|
#endif // WITH_DEBUG_VIEW_MODES
|
|
|
|
namespace Nanite
|
|
{
|
|
|
|
static FRDGBufferSRVRef GetShadingBinDataSRV(FRDGBuilder& GraphBuilder)
|
|
{
|
|
FRDGBufferRef ShadingBinData = nullptr;
|
|
if (Nanite::GGlobalResources.GetShadingBinDataBufferRef().IsValid())
|
|
{
|
|
ShadingBinData = GraphBuilder.RegisterExternalBuffer(Nanite::GGlobalResources.GetShadingBinDataBufferRef());
|
|
}
|
|
else
|
|
{
|
|
ShadingBinData = GSystemTextures.GetDefaultByteAddressBuffer(GraphBuilder, 4u);
|
|
}
|
|
|
|
return GraphBuilder.CreateSRV(ShadingBinData);
|
|
}
|
|
|
|
static FRDGTextureRef GetFastClearTileVis(FRDGBuilder& GraphBuilder)
|
|
{
|
|
FRDGTextureRef FastClearTileVis = nullptr;
|
|
if (Nanite::GGlobalResources.GetFastClearTileVisRef().IsValid())
|
|
{
|
|
FastClearTileVis = GraphBuilder.RegisterExternalTexture(Nanite::GGlobalResources.GetFastClearTileVisRef());
|
|
}
|
|
else
|
|
{
|
|
FastClearTileVis = GSystemTextures.GetZeroUIntDummy(GraphBuilder);
|
|
}
|
|
|
|
return FastClearTileVis;
|
|
}
|
|
|
|
static FRHITexture* GetMeshPaintTexture()
|
|
{
|
|
if (FRHITexture* TextureRHI = MeshPaintVisualize::GetTextureAsset_RenderThread())
|
|
{
|
|
return TextureRHI;
|
|
}
|
|
return GWhiteTexture->TextureRHI.GetReference();
|
|
}
|
|
|
|
static FRDGBufferRef PerformPicking(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FScene* Scene,
|
|
const FSceneTextures& SceneTextures,
|
|
Nanite::FRasterResults& Data,
|
|
const FViewInfo& View
|
|
)
|
|
{
|
|
// Force shader print on
|
|
ShaderPrint::SetEnabled(true);
|
|
|
|
// Make sure there's space for all debug lines the picking CS could possibly draw
|
|
const uint32 NumDebugLines =
|
|
8 * 2 // 2 OBBs - Instance + Cluster
|
|
+ 3 // Instance origin axis
|
|
+ 32 * 3 // (Cluster domain) Cluster LOD bounds sphere
|
|
+ 8 * 16 * 3 // (Cluster domain, Spline mesh) Slice spheres used to generate deformed cluster AABB
|
|
;
|
|
ShaderPrint::RequestSpaceForLines(NumDebugLines);
|
|
|
|
const FNaniteVisualizationData& VisualizationData = GetNaniteVisualizationData();
|
|
const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);
|
|
|
|
const FNaniteRasterPipelines& RasterPipelines = Scene->NaniteRasterPipelines[ENaniteMeshPass::BasePass];
|
|
|
|
FRDGBufferDesc PickingFeedbackBufferDesc(FRDGBufferDesc::CreateStructuredDesc(sizeof(FNanitePickingFeedback), 1));
|
|
PickingFeedbackBufferDesc.Usage |= BUF_SourceCopy;
|
|
FRDGBufferRef PickingFeedback = GraphBuilder.CreateBuffer(PickingFeedbackBufferDesc, TEXT("Nanite.PickingFeedback"));
|
|
FRDGBufferRef HitProxyIDBuffer = GSystemTextures.GetDefaultByteAddressBuffer(GraphBuilder, 4u); // NOTE: unused in this mode
|
|
|
|
{
|
|
FNanitePickingCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FNanitePickingCS::FParameters>();
|
|
ShaderPrint::SetParameters(GraphBuilder, View.ShaderPrintData, PassParameters->ShaderPrintUniformBuffer);
|
|
PassParameters->View = View.GetShaderParameters();
|
|
PassParameters->Scene = View.GetSceneUniforms().GetBuffer(GraphBuilder);
|
|
PassParameters->ShadingBinData = GetShadingBinDataSRV(GraphBuilder);
|
|
PassParameters->ClusterPageData = Nanite::GStreamingManager.GetClusterPageDataSRV(GraphBuilder);
|
|
PassParameters->HierarchyBuffer = Nanite::GStreamingManager.GetHierarchySRV(GraphBuilder);
|
|
PassParameters->VisualizeConfig = GetVisualizeConfig(NANITE_VISUALIZE_PICKING, /* bCompositeScene = */ false, GNaniteVisualizeEdgeDetect != 0);
|
|
PassParameters->PageConstants = Data.PageConstants;
|
|
PassParameters->MaxVisibleClusters = Data.MaxVisibleClusters;
|
|
PassParameters->RenderFlags = Data.RenderFlags;
|
|
PassParameters->RegularMaterialRasterBinCount = RasterPipelines.GetRegularBinCount();
|
|
PassParameters->PickingPixelPos = FIntPoint((int32)VisualizationData.GetPickingMousePos().X, (int32)VisualizationData.GetPickingMousePos().Y);
|
|
PassParameters->VisibleClustersSWHW = GraphBuilder.CreateSRV(Data.VisibleClustersSWHW);
|
|
PassParameters->VisBuffer64 = Data.VisBuffer64;
|
|
PassParameters->DbgBuffer64 = Data.DbgBuffer64;
|
|
PassParameters->DbgBuffer32 = Data.DbgBuffer32;
|
|
PassParameters->ShadingMask = Data.ShadingMask;
|
|
PassParameters->SceneDepth = SceneTextures.Depth.Target;
|
|
PassParameters->MaterialHitProxyTable = GraphBuilder.CreateSRV(HitProxyIDBuffer);
|
|
PassParameters->FeedbackBuffer = GraphBuilder.CreateUAV(PickingFeedback);
|
|
|
|
auto PickingShader = View.ShaderMap->GetShader<FNanitePickingCS>();
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("Nanite::Picking"),
|
|
PickingShader,
|
|
PassParameters,
|
|
FIntVector(1, 1, 1));
|
|
}
|
|
|
|
return PickingFeedback;
|
|
}
|
|
|
|
void DisplayPicking(const FScene* Scene, const FNanitePickingFeedback& PickingFeedback, uint32 RenderFlags, FScreenMessageWriter& Writer)
|
|
{
|
|
const FNaniteVisualizationData& VisualizationData = GetNaniteVisualizationData();
|
|
if (VisualizationData.GetActiveModeID() != NANITE_VISUALIZE_PICKING)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (GNanitePickingDomain)
|
|
{
|
|
case NANITE_PICKING_DOMAIN_TRIANGLE:
|
|
Writer.DrawLine(FText::FromString(TEXT("Domain [Triangle]")), 10, FColor::Yellow);
|
|
break;
|
|
|
|
case NANITE_PICKING_DOMAIN_CLUSTER:
|
|
Writer.DrawLine(FText::FromString(TEXT("Domain [Cluster]")), 10, FColor::Yellow);
|
|
break;
|
|
|
|
case NANITE_PICKING_DOMAIN_INSTANCE:
|
|
Writer.DrawLine(FText::FromString(TEXT("Domain [Instance]")), 10, FColor::Yellow);
|
|
break;
|
|
|
|
case NANITE_PICKING_DOMAIN_PRIMITIVE:
|
|
Writer.DrawLine(FText::FromString(TEXT("Domain [Primitive]")), 10, FColor::Yellow);
|
|
break;
|
|
|
|
default:
|
|
break; // Invalid picking domain
|
|
}
|
|
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Pixel [%d:%d]"), PickingFeedback.PixelX, PickingFeedback.PixelY)), 10, FColor::Yellow);
|
|
|
|
if (PickingFeedback.PrimitiveId == ~uint32(0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const int32 PickedPrimitiveIndex = Scene->GetPrimitiveIndex(FPersistentPrimitiveIndex{int32(PickingFeedback.PrimitiveId)});
|
|
if (!Scene->PrimitiveSceneProxies.IsValidIndex(PickedPrimitiveIndex))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FPrimitiveSceneProxy* PickedSceneProxy = Scene->PrimitiveSceneProxies[PickedPrimitiveIndex];
|
|
if (!PickedSceneProxy->IsNaniteMesh())
|
|
{
|
|
return;
|
|
}
|
|
|
|
const Nanite::FSceneProxyBase* PickedNaniteProxy = (const Nanite::FSceneProxyBase*)PickedSceneProxy;
|
|
const FPrimitiveSceneInfo* PickedSceneInfo = Scene->Primitives[PickedPrimitiveIndex];
|
|
|
|
Writer.EmptyLine();
|
|
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Persistent Index: %d"), PickingFeedback.PersistentIndex)), 10, FColor::Yellow);
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Primitive Id: %d"), PickedPrimitiveIndex)), 10, FColor::Yellow);
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Instance Id: %d"), PickingFeedback.InstanceId)), 10, FColor::Yellow);
|
|
const FInstanceSceneDataBuffers *InstanceSceneDataBuffers = PickedNaniteProxy->GetInstanceSceneDataBuffers();
|
|
int32 NumInstances = InstanceSceneDataBuffers ? InstanceSceneDataBuffers->GetNumInstances() : 0;
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Instance Count: %d"), NumInstances)), 10, FColor::Yellow);
|
|
|
|
Writer.EmptyLine();
|
|
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Page Index: %d"), PickingFeedback.PageIndex)), 10, FColor::Yellow);
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Group Index: %d"), PickingFeedback.GroupIndex)), 10, FColor::Yellow);
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Cluster Index: %d"), PickingFeedback.ClusterIndex)), 10, FColor::Yellow);
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Triangle Index: %d"), PickingFeedback.TriangleIndex)), 10, FColor::Yellow);
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Hierarchy Offset: %d"), PickingFeedback.HierarchyOffset)), 10, FColor::Yellow);
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Runtime Resource Id: %d"), PickingFeedback.RuntimeResourceID)), 10, FColor::Yellow);
|
|
|
|
Writer.EmptyLine();
|
|
|
|
#if NANITE_ASSEMBLY_DATA
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Assembly Transform Offset: %d"), PickingFeedback.AssemblyTransformOffset)), 10, FColor::Yellow);
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Assembly Transform Index: %d"), PickingFeedback.AssemblyTransformIndex)), 10, FColor::Yellow);
|
|
|
|
Writer.EmptyLine();
|
|
#endif
|
|
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Raster Depth: %.6f"), *reinterpret_cast<const float*>(&PickingFeedback.DepthInt))), 10, FColor::Yellow);
|
|
|
|
if (PickingFeedback.RasterMode == 1)
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Raster Mode: Hardware"))), 10, FColor::Yellow);
|
|
}
|
|
else if (PickingFeedback.RasterMode == 2)
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Raster Mode: Software"))), 10, FColor::Yellow);
|
|
}
|
|
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Raster Bin: %d"), PickingFeedback.RasterBin)), 10, FColor::Yellow);
|
|
|
|
Writer.EmptyLine();
|
|
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Shading Bin: %d"), PickingFeedback.ShadingBin)), 10, FColor::Yellow);
|
|
|
|
if (PickingFeedback.MaterialMode == 0)
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Material Mode: Fast"))), 10, FColor::Yellow);
|
|
}
|
|
else if (PickingFeedback.MaterialMode == 1)
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Material Mode: Slow"))), 10, FColor::Yellow);
|
|
}
|
|
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Material Index: %d"), PickingFeedback.MaterialIndex)), 10, FColor::Yellow);
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Material Count: %d"), PickingFeedback.MaterialCount)), 10, FColor::Yellow);
|
|
|
|
Writer.EmptyLine();
|
|
|
|
const TArray<Nanite::FSceneProxyBase::FMaterialSection>& PickedMaterialSections = PickedNaniteProxy->GetMaterialSections();
|
|
if (int32(PickingFeedback.MaterialIndex) < PickedMaterialSections.Num())
|
|
{
|
|
const Nanite::FSceneProxyBase::FMaterialSection& PickedMaterialSection = PickedMaterialSections[PickingFeedback.MaterialIndex];
|
|
|
|
if (PickedMaterialSection.ShadingMaterialProxy)
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Shading Material [%s]"), *PickedMaterialSection.ShadingMaterialProxy->GetMaterialName())), 10, FColor::Yellow);
|
|
}
|
|
|
|
Writer.EmptyLine();
|
|
|
|
FMaterialRenderProxy* FixedFunctionProxy = UMaterial::GetDefaultMaterial(MD_Surface)->GetRenderProxy();
|
|
|
|
const bool bDisableProgrammable = (RenderFlags & NANITE_RENDER_FLAG_DISABLE_PROGRAMMABLE) != 0;
|
|
if (!bDisableProgrammable && PickedMaterialSection.RasterMaterialProxy && PickedMaterialSection.RasterMaterialProxy != FixedFunctionProxy)
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Raster Material [%s]"), *PickedMaterialSection.RasterMaterialProxy->GetMaterialName())), 10, FColor::Yellow);
|
|
const FMaterial& PickedRasterMaterial = PickedMaterialSection.RasterMaterialProxy->GetIncompleteMaterialWithFallback(Scene->GetFeatureLevel());
|
|
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT(" Programmable:"))), 10, FColor::Yellow);
|
|
|
|
if (PickedRasterMaterial.MaterialUsesDisplacement_RenderThread())
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT(" - Displacement Mapping"))), 10, FColor::Yellow);
|
|
}
|
|
|
|
if (PickedRasterMaterial.MaterialUsesWorldPositionOffset_RenderThread())
|
|
{
|
|
if (PickedNaniteProxy->EvaluateWorldPositionOffset())
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT(" - World Position Offset"))), 10, FColor::Yellow);
|
|
}
|
|
else
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT(" - World Position Offset [Disabled]"))), 10, FColor::Yellow);
|
|
}
|
|
}
|
|
|
|
if (PickedRasterMaterial.MaterialUsesPixelDepthOffset_RenderThread())
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT(" - Pixel Depth Offset"))), 10, FColor::Yellow);
|
|
}
|
|
|
|
if (PickedRasterMaterial.IsMasked())
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT(" - Alpha Masking"))), 10, FColor::Yellow);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Writer.DrawLine(FText::FromString(FString::Printf(TEXT("Raster Material [Fixed Function]"))), 10, FColor::Yellow);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AddVisualizationPasses(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FScene* Scene,
|
|
const FSceneTextures& SceneTextures,
|
|
const FEngineShowFlags& EngineShowFlags,
|
|
TArrayView<const FViewInfo> Views,
|
|
TArrayView<Nanite::FRasterResults> Results,
|
|
FNanitePickingFeedback& PickingFeedback,
|
|
FVirtualShadowMapArray& VirtualShadowMapArray
|
|
)
|
|
{
|
|
checkSlow(DoesPlatformSupportNanite(GMaxRHIShaderPlatform));
|
|
|
|
const FNaniteVisualizationData& VisualizationData = GetNaniteVisualizationData();
|
|
|
|
FRDGBufferRef PickingBuffer = nullptr;
|
|
|
|
if (Scene && Views.Num() > 0 && VisualizationData.IsActive() && EngineShowFlags.VisualizeNanite)
|
|
{
|
|
// Don't create the hit proxy ID buffer until it's needed
|
|
// TODO: Permutation with hit proxy support to keep this clean when !WITH_EDITOR?
|
|
FRDGBufferRef HitProxyIDBuffer = GSystemTextures.GetDefaultByteAddressBuffer(GraphBuilder, 4u);
|
|
bool bHitProxyIDBufferCreated = false;
|
|
|
|
// These should always match 1:1
|
|
if (ensure(Views.Num() == Results.Num()))
|
|
{
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
const FViewInfo& View = Views[ViewIndex];
|
|
Nanite::FRasterResults& Data = Results[ViewIndex];
|
|
|
|
// Skip over secondary instanced stereo views, which use the primary view's data instead
|
|
if (View.ShouldRenderView())
|
|
{
|
|
const int32 ViewWidth = View.ViewRectWithSecondaryViews.Max.X - View.ViewRectWithSecondaryViews.Min.X;
|
|
const int32 ViewHeight = View.ViewRectWithSecondaryViews.Max.Y - View.ViewRectWithSecondaryViews.Min.Y;
|
|
const FIntPoint ViewSize = FIntPoint(ViewWidth, ViewHeight);
|
|
|
|
const FNaniteRasterPipelines& RasterPipelines = Scene->NaniteRasterPipelines[ENaniteMeshPass::BasePass];
|
|
|
|
LLM_SCOPE_BYTAG(Nanite);
|
|
RDG_EVENT_SCOPE_STAT(GraphBuilder, NaniteDebug, "Nanite::Visualization");
|
|
RDG_GPU_STAT_SCOPE(GraphBuilder, NaniteDebug);
|
|
|
|
const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);
|
|
const FIntPoint TileGridDim = FMath::DivideAndRoundUp(ViewSize, { 8, 8 });
|
|
|
|
FRDGTextureRef VisBuffer64 = Data.VisBuffer64 ? Data.VisBuffer64 : SystemTextures.Black;
|
|
FRDGTextureRef DbgBuffer64 = Data.DbgBuffer64 ? Data.DbgBuffer64 : SystemTextures.Black;
|
|
FRDGTextureRef DbgBuffer32 = Data.DbgBuffer32 ? Data.DbgBuffer32 : SystemTextures.Black;
|
|
FRDGTextureRef ShadingMask = Data.ShadingMask ? Data.ShadingMask : SystemTextures.Black;
|
|
|
|
FRDGBufferRef RasterBinMeta = Data.RasterBinMeta ? Data.RasterBinMeta : GSystemTextures.GetDefaultStructuredBuffer<FNaniteRasterBinMeta>(GraphBuilder);
|
|
|
|
FRDGBufferRef VisibleClustersSWHW = Data.VisibleClustersSWHW;
|
|
|
|
// Debug picking feedback (mouse dependent, does not support stereo)
|
|
if (VisualizationData.GetActiveModeID() == NANITE_VISUALIZE_PICKING && Views.Num() == 1)
|
|
{
|
|
PickingBuffer = PerformPicking(GraphBuilder, Scene, SceneTextures, Data, View);
|
|
}
|
|
|
|
Data.Visualizations.Reset();
|
|
|
|
const bool bSingleVisualization = VisualizationData.GetActiveModeID() > 0;
|
|
const bool bOverviewVisualization = VisualizationData.GetActiveModeID() == 0;
|
|
|
|
if (bSingleVisualization)
|
|
{
|
|
// Single visualization
|
|
FVisualizeResult Visualization = {};
|
|
Visualization.ModeName = VisualizationData.GetActiveModeName();
|
|
Visualization.ModeID = VisualizationData.GetActiveModeID();
|
|
Visualization.bCompositeScene = VisualizationData.GetActiveModeDefaultComposited();
|
|
Visualization.bSkippedTile = false;
|
|
Data.Visualizations.Emplace(Visualization);
|
|
}
|
|
else if (bOverviewVisualization)
|
|
{
|
|
// Overview mode
|
|
const auto& OverviewModeNames = VisualizationData.GetOverviewModeNames();
|
|
for (const FName& ModeName : OverviewModeNames)
|
|
{
|
|
FVisualizeResult Visualization = {};
|
|
Visualization.ModeName = ModeName;
|
|
Visualization.ModeID = VisualizationData.GetModeID(Visualization.ModeName);
|
|
Visualization.bCompositeScene = VisualizationData.GetModeDefaultComposited(Visualization.ModeName);
|
|
Visualization.bSkippedTile = Visualization.ModeName == NAME_None;
|
|
Data.Visualizations.Emplace(Visualization);
|
|
}
|
|
}
|
|
|
|
bool bRequiresHitProxyIDs = false;
|
|
bool bRequiresHiZDecode = false;
|
|
for (FVisualizeResult& Visualization : Data.Visualizations)
|
|
{
|
|
if (Visualization.bSkippedTile)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bRequiresHitProxyIDs |= Visualization.ModeID == NANITE_VISUALIZE_HIT_PROXY_DEPTH;
|
|
bRequiresHitProxyIDs |= Visualization.ModeID == NANITE_VISUALIZE_VERTEX_COLOR;
|
|
bRequiresHitProxyIDs |= Visualization.ModeID == NANITE_VISUALIZE_MESH_PAINT_TEXTURE;
|
|
bRequiresHiZDecode |= VisualizationRequiresHiZDecode(Visualization.ModeID);
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
const uint32 HitProxyIdCount = View.EditorSelectedNaniteHitProxyIds.Num();
|
|
if (bRequiresHitProxyIDs && !bHitProxyIDBufferCreated)
|
|
{
|
|
auto& MaterialsExtension = Scene->GetExtension<Nanite::FMaterialsSceneExtension>();
|
|
HitProxyIDBuffer = MaterialsExtension.CreateHitProxyIDBuffer(GraphBuilder);
|
|
bHitProxyIDBufferCreated = true;
|
|
}
|
|
#else
|
|
const uint32 HitProxyIdCount = 0;
|
|
#endif
|
|
|
|
FRDGTextureRef DefaultUintVec4 = GSystemTextures.GetDefaultTexture(GraphBuilder, ETextureDimension::Texture2D, PF_R32G32B32A32_UINT, FUintVector4(0.0, 0.0, 0.0, 0.0));
|
|
|
|
FRDGTextureRef SceneZDecoded = SystemTextures.Black;
|
|
FRDGTextureRef SceneZLayout = DefaultUintVec4;
|
|
if (bRequiresHiZDecode && UseComputeDepthExport())
|
|
{
|
|
const uint32 PixelsWide = uint32(ViewSize.X);
|
|
const uint32 PixelsTall = uint32(ViewSize.Y);
|
|
const uint32 PlatformConfig = RHIGetHTilePlatformConfig(PixelsWide, PixelsTall);
|
|
|
|
FRDGTextureDesc SceneZDecodedDesc = FRDGTextureDesc::Create2D(ViewSize, PF_R32_FLOAT, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV);
|
|
SceneZDecoded = GraphBuilder.CreateTexture(SceneZDecodedDesc, TEXT("Nanite.SceneZDecoded"));
|
|
|
|
FRDGTextureDesc SceneZLayoutDesc = FRDGTextureDesc::Create2D(ViewSize, PF_R32G32B32A32_UINT, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_UAV);
|
|
SceneZLayout = GraphBuilder.CreateTexture(SceneZLayoutDesc, TEXT("Nanite.SceneZLayout"));
|
|
|
|
FDepthDecodeCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FDepthDecodeCS::FParameters>();
|
|
PassParameters->View = View.ViewUniformBuffer;
|
|
PassParameters->InViews = GraphBuilder.CreateSRV(Data.ViewsBuffer);
|
|
PassParameters->ViewRect = FUint32Vector4((uint32)View.ViewRectWithSecondaryViews.Min.X, (uint32)View.ViewRectWithSecondaryViews.Min.Y, (uint32)View.ViewRectWithSecondaryViews.Max.X, (uint32)View.ViewRectWithSecondaryViews.Max.Y);
|
|
PassParameters->HTileConfig = FUint32Vector4(PlatformConfig, PixelsWide, 0, 0);
|
|
PassParameters->SceneDepth = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMetaData(SceneTextures.Depth.Target, ERDGTextureMetaDataAccess::CompressedSurface));
|
|
PassParameters->ShadingMask = ShadingMask;
|
|
PassParameters->SceneHTileBuffer = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateForMetaData(SceneTextures.Depth.Target, ERDGTextureMetaDataAccess::HTile));
|
|
PassParameters->SceneZDecoded = GraphBuilder.CreateUAV(SceneZDecoded);
|
|
PassParameters->SceneZLayout = GraphBuilder.CreateUAV(SceneZLayout);
|
|
|
|
auto ComputeShader = View.ShaderMap->GetShader<FDepthDecodeCS>();
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("DepthDecode"),
|
|
ERDGPassFlags::Compute | ERDGPassFlags::NeverCull,
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(ViewSize, 8)
|
|
);
|
|
}
|
|
|
|
for (FVisualizeResult& Visualization : Data.Visualizations)
|
|
{
|
|
if (Visualization.bSkippedTile)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Apply force off/on scene composition
|
|
if (GNaniteVisualizeComposite == 0)
|
|
{
|
|
// Force off
|
|
Visualization.bCompositeScene = false;
|
|
}
|
|
else if (GNaniteVisualizeComposite == 1)
|
|
{
|
|
// Force on
|
|
Visualization.bCompositeScene = true;
|
|
}
|
|
|
|
FRDGTextureDesc VisualizationOutputDesc = FRDGTextureDesc::Create2D(
|
|
View.ViewRectWithSecondaryViews.Max,
|
|
PF_A32B32G32R32F,
|
|
FClearValueBinding::None,
|
|
TexCreate_ShaderResource | TexCreate_UAV);
|
|
|
|
Visualization.ModeOutput = GraphBuilder.CreateTexture(VisualizationOutputDesc, TEXT("Nanite.Visualization"));
|
|
|
|
FNaniteVisualizeCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FNaniteVisualizeCS::FParameters>();
|
|
|
|
FGraphicsPipelineRenderTargetsInfo RenderTargetsInfo;
|
|
const uint32 ShadingExportCount = SceneTextures.Config.GetGBufferRenderTargetsInfo(RenderTargetsInfo);
|
|
|
|
PassParameters->View = View.GetShaderParameters();
|
|
PassParameters->Scene = View.GetSceneUniforms().GetBuffer(GraphBuilder);
|
|
PassParameters->VirtualShadowMap = VirtualShadowMapArray.GetUniformBuffer(ViewIndex);
|
|
PassParameters->ClusterPageData = Nanite::GStreamingManager.GetClusterPageDataSRV(GraphBuilder);
|
|
PassParameters->HierarchyBuffer = Nanite::GStreamingManager.GetHierarchySRV(GraphBuilder);
|
|
PassParameters->VisualizeConfig = GetVisualizeConfig(Visualization.ModeID, Visualization.bCompositeScene, GNaniteVisualizeEdgeDetect != 0);
|
|
PassParameters->VisualizeScales = GetVisualizeScales(Visualization.ModeID, ShadingExportCount);
|
|
PassParameters->PageConstants = Data.PageConstants;
|
|
PassParameters->MaxVisibleClusters = Data.MaxVisibleClusters;
|
|
PassParameters->RenderFlags = Data.RenderFlags;
|
|
PassParameters->NumEditorSelectedHitProxyIds = HitProxyIdCount;
|
|
PassParameters->RegularMaterialRasterBinCount = RasterPipelines.GetRegularBinCount();
|
|
PassParameters->PickingPixelPos = FIntPoint((int32)VisualizationData.GetPickingMousePos().X, (int32)VisualizationData.GetPickingMousePos().Y);
|
|
PassParameters->VisibleClustersSWHW = GraphBuilder.CreateSRV(VisibleClustersSWHW);
|
|
PassParameters->VisBuffer64 = VisBuffer64;
|
|
PassParameters->DbgBuffer64 = DbgBuffer64;
|
|
PassParameters->DbgBuffer32 = DbgBuffer32;
|
|
PassParameters->ShadingMask = ShadingMask;
|
|
PassParameters->SceneDepth = SceneTextures.Depth.Target;
|
|
PassParameters->SceneZDecoded = SceneZDecoded;
|
|
PassParameters->SceneZLayout = SceneZLayout;
|
|
PassParameters->FastClearTileVis = GetFastClearTileVis(GraphBuilder);
|
|
PassParameters->MaterialHitProxyTable = GraphBuilder.CreateSRV(HitProxyIDBuffer);
|
|
PassParameters->ShadingBinData = GetShadingBinDataSRV(GraphBuilder);
|
|
PassParameters->RasterBinMeta = GraphBuilder.CreateSRV(RasterBinMeta);
|
|
PassParameters->DebugOutput = GraphBuilder.CreateUAV(Visualization.ModeOutput);
|
|
PassParameters->EditorSelectedHitProxyIds = Nanite::GetEditorSelectedHitProxyIdsSRV(GraphBuilder, View);
|
|
PassParameters->MeshPaintTexture = GetMeshPaintTexture();
|
|
PassParameters->MeshPaintTextureCoordinate = MeshPaintVisualize::GetTextureCoordinateIndex();
|
|
|
|
auto ComputeShader = View.ShaderMap->GetShader<FNaniteVisualizeCS>();
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("Nanite::Visualize"),
|
|
ERDGPassFlags::Compute | ERDGPassFlags::NeverCull,
|
|
ComputeShader,
|
|
PassParameters,
|
|
FComputeShaderUtils::GetGroupCount(ViewSize, 8)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (PickingBuffer != nullptr)
|
|
{
|
|
const int32 MaxPickingBuffers = Nanite::GGlobalResources.MaxPickingBuffers;
|
|
|
|
int32& PickingBufferWriteIndex = Nanite::GGlobalResources.PickingBufferWriteIndex;
|
|
int32& PickingBufferNumPending = Nanite::GGlobalResources.PickingBufferNumPending;
|
|
|
|
TArray<TUniquePtr<FRHIGPUBufferReadback>>& PickingBuffers = Nanite::GGlobalResources.PickingBuffers;
|
|
|
|
// Skip when queue is full. It is NOT safe to EnqueueCopy on a buffer that already has a pending copy
|
|
if (PickingBufferNumPending < MaxPickingBuffers)
|
|
{
|
|
TUniquePtr<FRHIGPUBufferReadback>* GPUBufferReadback = &PickingBuffers[PickingBufferWriteIndex];
|
|
if (!GPUBufferReadback->IsValid())
|
|
{
|
|
static const FName PickingFeedbackName(TEXT("Nanite.PickingFeedback"));
|
|
PickingBuffers[PickingBufferWriteIndex] = MakeUnique<FRHIGPUBufferReadback>(PickingFeedbackName);
|
|
GPUBufferReadback = &PickingBuffers[PickingBufferWriteIndex];
|
|
}
|
|
|
|
AddEnqueueCopyPass(GraphBuilder, GPUBufferReadback->Get(), PickingBuffer, 0);
|
|
|
|
PickingBufferWriteIndex = (PickingBufferWriteIndex + 1) % MaxPickingBuffers;
|
|
PickingBufferNumPending = FMath::Min(PickingBufferNumPending + 1, MaxPickingBuffers);
|
|
}
|
|
|
|
{
|
|
TUniquePtr<FRHIGPUBufferReadback>* LatestPickingBuffer = nullptr;
|
|
|
|
// Find latest buffer that is ready
|
|
while (PickingBufferNumPending > 0)
|
|
{
|
|
uint32 Index = (PickingBufferWriteIndex + MaxPickingBuffers - PickingBufferNumPending) % MaxPickingBuffers;
|
|
if (PickingBuffers[Index]->IsReady())
|
|
{
|
|
--PickingBufferNumPending;
|
|
LatestPickingBuffer = &PickingBuffers[Index];
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (LatestPickingBuffer && LatestPickingBuffer->IsValid())
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(LockBuffer);
|
|
const FNanitePickingFeedback* DataPtr = (const FNanitePickingFeedback*)(*LatestPickingBuffer)->Lock(sizeof(FNanitePickingFeedback));
|
|
if (DataPtr)
|
|
{
|
|
PickingFeedback = *DataPtr;
|
|
(*LatestPickingBuffer)->Unlock();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if WITH_DEBUG_VIEW_MODES
|
|
|
|
void RenderDebugViewMode(
|
|
FRDGBuilder& GraphBuilder,
|
|
EDebugViewMode DebugViewMode,
|
|
const FScene& Scene,
|
|
const FViewInfo& View,
|
|
const FSceneViewFamily& ViewFamily,
|
|
const FRasterResults& RasterResults,
|
|
FRDGTextureRef OutputColorTexture,
|
|
FRDGTextureRef InputDepthTexture,
|
|
FRDGTextureRef OutputDepthTexture,
|
|
FRDGTextureRef QuadOverdrawTexture
|
|
)
|
|
{
|
|
LLM_SCOPE_BYTAG(Nanite);
|
|
RDG_EVENT_SCOPE_STAT(GraphBuilder, NaniteDebug, "Nanite::DebugView");
|
|
RDG_GPU_STAT_SCOPE(GraphBuilder, NaniteDebug);
|
|
|
|
if (!FExportDebugViewPS::IsPlatformSupported(View.GetShaderPlatform()))
|
|
{
|
|
UE_CALL_ONCE([](){ UE_LOG(LogNanite, Error, TEXT("Platform does not support Nanite debug view shaders")); });
|
|
return;
|
|
}
|
|
|
|
const uint32 GlobalShaderBudget = GetMaxShaderComplexityCount(View.GetFeatureLevel());
|
|
|
|
// Increase the shader budget for Nanite meshes to account for baseline ALU overhead.
|
|
const uint32 NaniteShaderBudget = GlobalShaderBudget + uint32(GNaniteVisualizeComplexityOverhead);
|
|
|
|
const FLinearColor SelectionColor = GetSelectionColor(FLinearColor::White, true /* selected */, false /* hovered */, false /* use overlay intensity */);
|
|
const FLinearColor OverlayIntensityColor = GetSelectionColor(FLinearColor::White, false /* selected */, false /* hovered */, true /* use overlay intensity */);
|
|
// TODO: Need to apply hover intensity to per-primitive wireframe color, not white
|
|
//const FLinearColor HoveredColor = GetSelectionColor(FLinearColor::White, false /* selected */, true /* hovered */);
|
|
|
|
FExportDebugViewPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FExportDebugViewPS::FParameters>();
|
|
PassParameters->View = View.GetShaderParameters();
|
|
PassParameters->Scene = View.GetSceneUniforms().GetBuffer(GraphBuilder);
|
|
PassParameters->VisibleClustersSWHW = GraphBuilder.CreateSRV(RasterResults.VisibleClustersSWHW);
|
|
PassParameters->PageConstants = RasterResults.PageConstants;
|
|
PassParameters->ViewRect = FIntVector4(View.ViewRect.Min.X, View.ViewRect.Min.Y, View.ViewRect.Max.X, View.ViewRect.Max.Y);
|
|
if (View.Family->GetDebugViewShaderMode() == DVSM_LWCComplexity)
|
|
{
|
|
PassParameters->InvShaderBudget = 1.0f / GMaxLWCComplexity;
|
|
}
|
|
else
|
|
{
|
|
PassParameters->InvShaderBudget = 1.0f / float(NaniteShaderBudget);
|
|
}
|
|
PassParameters->SelectionColor = FVector3f(SelectionColor.R, SelectionColor.G, SelectionColor.B);
|
|
PassParameters->OverlayIntensityColor = FVector3f(OverlayIntensityColor.R, OverlayIntensityColor.G, OverlayIntensityColor.B);
|
|
PassParameters->DebugViewMode = uint32(DebugViewMode);
|
|
PassParameters->ClusterPageData = Nanite::GStreamingManager.GetClusterPageDataSRV(GraphBuilder);
|
|
PassParameters->HierarchyBuffer = Nanite::GStreamingManager.GetHierarchySRV(GraphBuilder);
|
|
PassParameters->VisBuffer64 = RasterResults.VisBuffer64;
|
|
PassParameters->SceneDepth = InputDepthTexture;
|
|
PassParameters->ShadingMask = RasterResults.ShadingMask;
|
|
PassParameters->DebugViewData = GraphBuilder.CreateSRV(Scene.GetExtension<Nanite::FMaterialsSceneExtension>().CreateDebugViewModeBuffer(GraphBuilder));
|
|
PassParameters->EditorSelectedHitProxyIds = Nanite::GetEditorSelectedHitProxyIdsSRV(GraphBuilder, View);
|
|
PassParameters->ShadingBinData = GetShadingBinDataSRV(GraphBuilder);
|
|
PassParameters->MaterialHitProxyTable = GraphBuilder.CreateSRV(
|
|
#if WITH_EDITOR
|
|
Scene.GetExtension<Nanite::FMaterialsSceneExtension>().CreateHitProxyIDBuffer(GraphBuilder)
|
|
#else
|
|
// TODO: Permutation with hit proxy support to keep this clean?
|
|
// For now, bind a valid SRV
|
|
GSystemTextures.GetDefaultByteAddressBuffer(GraphBuilder, 4u)
|
|
#endif
|
|
);
|
|
|
|
PassParameters->RenderTargets[0] = FRenderTargetBinding(OutputColorTexture, ERenderTargetLoadAction::ELoad, 0);
|
|
|
|
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(OutputDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite);
|
|
|
|
#if WITH_EDITOR
|
|
const uint32 HitProxyIdCount = View.EditorSelectedNaniteHitProxyIds.Num();
|
|
#else
|
|
const uint32 HitProxyIdCount = 0;
|
|
#endif
|
|
PassParameters->NumEditorSelectedHitProxyIds = HitProxyIdCount;
|
|
|
|
const int MSAASampleCountDim = FMath::FloorLog2(InputDepthTexture->Desc.NumSamples);
|
|
|
|
FExportDebugViewPS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FExportDebugViewPS::FSampleCountDimension>(MSAASampleCountDim);
|
|
|
|
auto PixelShader = View.ShaderMap->GetShader<FExportDebugViewPS>(PermutationVector.ToDimensionValueId());
|
|
|
|
FRHIDepthStencilState* DepthStencilState = TStaticDepthStencilState<true, CF_DepthNearOrEqual>::GetRHI();
|
|
|
|
FPixelShaderUtils::AddFullscreenPass(
|
|
GraphBuilder,
|
|
View.ShaderMap,
|
|
RDG_EVENT_NAME("Export Debug View"),
|
|
PixelShader,
|
|
PassParameters,
|
|
View.ViewRect,
|
|
nullptr,
|
|
nullptr,
|
|
DepthStencilState
|
|
);
|
|
}
|
|
|
|
#endif // WITH_DEBUG_VIEW_MODES
|
|
|
|
} // namespace Nanite
|