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

810 lines
35 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "NaniteComposition.h"
#include "Rendering/NaniteResources.h"
#include "Rendering/NaniteStreamingManager.h"
#include "ScenePrivate.h"
#include "SystemTextures.h"
#include "PixelShaderUtils.h"
#include "PostProcess/SceneRenderTargets.h"
BEGIN_SHADER_PARAMETER_STRUCT(FDummyDepthDecompressParameters, )
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float>, SceneDepth)
END_SHADER_PARAMETER_STRUCT()
int32 GNaniteResummarizeHTile = 1;
static FAutoConsoleVariableRef CVarNaniteResummarizeHTile(
TEXT("r.Nanite.ResummarizeHTile"),
GNaniteResummarizeHTile,
TEXT("")
);
int32 GNaniteDecompressDepth = 0;
static FAutoConsoleVariableRef CVarNaniteDecompressDepth(
TEXT("r.Nanite.DecompressDepth"),
GNaniteDecompressDepth,
TEXT("")
);
int32 GNaniteCustomDepthExportMethod = 1;
static FAutoConsoleVariableRef CVarNaniteCustomDepthExportMethod(
TEXT("r.Nanite.CustomDepth.ExportMethod"),
GNaniteCustomDepthExportMethod,
TEXT("0 - Export depth/stencil into separate targets via PS\n")
TEXT("1 - Export depth/stencil direct to target via CS (requires HTILE support)\n")
);
#if WITH_EDITORONLY_DATA
extern int32 GNaniteIsolateInvalidCoarseMesh;
#endif
class FNaniteMarkStencilPS : public FNaniteGlobalShader
{
DECLARE_GLOBAL_SHADER(FNaniteMarkStencilPS);
SHADER_USE_PARAMETER_STRUCT(FNaniteMarkStencilPS, FNaniteGlobalShader);
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return DoesPlatformSupportNanite(Parameters.Platform);
}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UlongType>, VisBuffer64)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FNaniteMarkStencilPS, "/Engine/Private/Nanite/NaniteExportGBuffer.usf", "MarkStencilPS", SF_Pixel);
class FEmitSceneDepthPS : public FNaniteGlobalShader
{
DECLARE_GLOBAL_SHADER(FEmitSceneDepthPS);
SHADER_USE_PARAMETER_STRUCT(FEmitSceneDepthPS, FNaniteGlobalShader);
class FVelocityExportDim : SHADER_PERMUTATION_BOOL("VELOCITY_EXPORT");
class FShadingMaskExportDim : SHADER_PERMUTATION_BOOL("SHADING_MASK_EXPORT");
class FSkinningDim : SHADER_PERMUTATION_BOOL("USE_SKINNING");
using FPermutationDomain = TShaderPermutationDomain<FVelocityExportDim, FShadingMaskExportDim, FSkinningDim>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
const FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FSkinningDim>())
{
if (!NaniteSkinnedMeshesSupported())
{
return false;
}
if (!PermutationVector.Get<FVelocityExportDim>())
{
// Skinning is only needed when velocity will be exported
return false;
}
}
return DoesPlatformSupportNanite(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FNaniteGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetRenderTargetOutputFormat(0, PF_R32_UINT);
}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneUniformParameters, Scene)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FPackedView>, InViews)
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, VisibleClustersSWHW)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FNaniteRasterBinMeta>, RasterBinMeta)
SHADER_PARAMETER(FIntVector4, PageConstants)
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, ClusterPageData)
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, HierarchyBuffer)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UlongType>, VisBuffer64)
SHADER_PARAMETER(uint32, MeshPassIndex)
SHADER_PARAMETER(uint32, RegularMaterialRasterBinCount)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FEmitSceneDepthPS, "/Engine/Private/Nanite/NaniteExportGBuffer.usf", "EmitSceneDepthPS", SF_Pixel);
class FEmitSceneStencilPS : public FNaniteGlobalShader
{
DECLARE_GLOBAL_SHADER(FEmitSceneStencilPS);
SHADER_USE_PARAMETER_STRUCT(FEmitSceneStencilPS, 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("SHADING_MASK_LOAD"), 1);
}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneUniformParameters, Scene)
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, VisibleClustersSWHW)
SHADER_PARAMETER(FIntVector4, PageConstants)
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, ClusterPageData)
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, HierarchyBuffer)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, ShadingMask)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UlongType>, VisBuffer64)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FEmitSceneStencilPS, "/Engine/Private/Nanite/NaniteExportGBuffer.usf", "EmitSceneStencilPS", SF_Pixel);
class FEmitCustomDepthStencilPS : public FNaniteGlobalShader
{
DECLARE_GLOBAL_SHADER(FEmitCustomDepthStencilPS);
SHADER_USE_PARAMETER_STRUCT(FEmitCustomDepthStencilPS, FNaniteGlobalShader);
class FWriteCustomStencilDim : SHADER_PERMUTATION_BOOL("WRITE_CUSTOM_STENCIL");
using FPermutationDomain = TShaderPermutationDomain<FWriteCustomStencilDim>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return DoesPlatformSupportNanite(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FNaniteGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
const FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FWriteCustomStencilDim>())
{
OutEnvironment.SetRenderTargetOutputFormat(0, PF_R16G16_UINT);
}
}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneUniformParameters, Scene)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FPackedView>, InViews)
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, VisibleClustersSWHW)
SHADER_PARAMETER(FIntVector4, PageConstants)
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>, CustomDepth)
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<uint2>, CustomStencil)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FEmitCustomDepthStencilPS, "/Engine/Private/Nanite/NaniteExportGBuffer.usf", "EmitCustomDepthStencilPS", SF_Pixel);
class FDepthExportCS : public FNaniteGlobalShader
{
DECLARE_GLOBAL_SHADER(FDepthExportCS);
SHADER_USE_PARAMETER_STRUCT(FDepthExportCS, FNaniteGlobalShader);
class FVelocityExportDim : SHADER_PERMUTATION_BOOL("VELOCITY_EXPORT");
class FShadingMaskExportDim : SHADER_PERMUTATION_BOOL("SHADING_MASK_EXPORT");
class FSkinningDim : SHADER_PERMUTATION_BOOL("USE_SKINNING");
using FPermutationDomain = TShaderPermutationDomain<FVelocityExportDim, FShadingMaskExportDim, FSkinningDim>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
const FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FSkinningDim>())
{
if (!NaniteSkinnedMeshesSupported())
{
return false;
}
if (!PermutationVector.Get<FVelocityExportDim>())
{
// Skinning is only needed when velocity will be exported
return false;
}
}
return DoesPlatformSupportNanite(Parameters.Platform);
}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneUniformParameters, Scene)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FPackedView>, InViews)
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, VisibleClustersSWHW)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FNaniteRasterBinMeta>, RasterBinMeta)
SHADER_PARAMETER(FIntVector4, PageConstants)
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, ClusterPageData)
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, HierarchyBuffer)
SHADER_PARAMETER(FIntVector4, DepthExportConfig)
SHADER_PARAMETER(FUint32Vector4, ViewRect)
SHADER_PARAMETER(uint32, bWriteCustomStencil)
SHADER_PARAMETER(uint32, MeshPassIndex)
SHADER_PARAMETER(uint32, RegularMaterialRasterBinCount)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<UlongType>, VisBuffer64)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, Velocity)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<uint>, ShadingMask)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTextureMetadata, SceneHTile)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float>, SceneDepth)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<uint>, SceneStencil)
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FDepthExportCS, "/Engine/Private/Nanite/NaniteDepthExport.usf", "DepthExport", SF_Compute);
BEGIN_SHADER_PARAMETER_STRUCT(FNaniteMarkStencilRectsParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FPixelShaderUtils::FRasterizeToRectsVS::FParameters, VS)
SHADER_PARAMETER_STRUCT_INCLUDE(FNaniteMarkStencilPS::FParameters, PS)
END_SHADER_PARAMETER_STRUCT()
BEGIN_SHADER_PARAMETER_STRUCT(FNaniteEmitDepthRectsParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FPixelShaderUtils::FRasterizeToRectsVS::FParameters, VS)
SHADER_PARAMETER_STRUCT_INCLUDE(FEmitSceneDepthPS::FParameters, PS)
END_SHADER_PARAMETER_STRUCT()
namespace Nanite
{
void EmitDepthTargets(
FRDGBuilder& GraphBuilder,
const FScene& Scene,
const FViewInfo& View,
bool bDrawSceneViewsInOneNanitePass,
FRasterResults& RasterResults,
FRDGTextureRef SceneDepth,
FRDGTextureRef VelocityBuffer,
FRDGTextureRef FirstStageDepthBuffer
)
{
LLM_SCOPE_BYTAG(Nanite);
RDG_EVENT_SCOPE(GraphBuilder, "Nanite::EmitDepthTargets");
FRDGTextureRef VisBuffer64 = RasterResults.VisBuffer64;
#if WITH_EDITORONLY_DATA
// Hide all Nanite meshes when the isolate invalid coarse mesh batch debug mode is active.
if (GNaniteIsolateInvalidCoarseMesh != 0)
{
const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);
VisBuffer64 = SystemTextures.Black;
}
#endif
const FSceneTexturesConfig& Config = View.GetSceneTexturesConfig();
const EShaderPlatform ShaderPlatform = View.GetShaderPlatform();
const FIntPoint SceneTexturesExtent = Config.Extent;
const FClearValueBinding DefaultDepthStencil = Config.DepthClearValue;
float DefaultDepth = 0.0f;
uint32 DefaultStencil = 0;
DefaultDepthStencil.GetDepthStencil(DefaultDepth, DefaultStencil);
const uint32 StencilDecalMask = GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1);
const bool bEmitVelocity = VelocityBuffer != nullptr;
const bool bClearVelocity = bEmitVelocity && !HasBeenProduced(VelocityBuffer);
FRDGTextureDesc ShadingMaskDesc = FRDGTextureDesc::Create2D(
SceneTexturesExtent,
PF_R32_UINT,
FClearValueBinding::Transparent,
TexCreate_RenderTargetable | TexCreate_ShaderResource | TexCreate_UAV);
RasterResults.ShadingMask = GraphBuilder.CreateTexture(ShadingMaskDesc, TEXT("Nanite.ShadingMask"));
RasterResults.ClearTileArgs = nullptr;
RasterResults.ClearTileBuffer = nullptr;
if (UseComputeDepthExport())
{
// NOTE: We intentionally skip calling AddClearRenderTargetPass on the ShadingMask here, since we will explicitly
// write all pixels during the export depth pass below
// Emit depth, stencil, mask and velocity
if (GNaniteDecompressDepth != 0)
{
// Force depth decompression so the depth shader only processes decompressed surfaces
FDummyDepthDecompressParameters* DecompressParams = GraphBuilder.AllocParameters<FDummyDepthDecompressParameters>();
DecompressParams->SceneDepth = SceneDepth;
GraphBuilder.AddPass(
RDG_EVENT_NAME("NaniteDepthDecompress"),
DecompressParams,
ERDGPassFlags::Copy | ERDGPassFlags::NeverCull,
[](FRDGAsyncTask, FRHICommandList&) {}
);
}
const FIntRect ViewRect = bDrawSceneViewsInOneNanitePass ? View.GetFamilyViewRect() : View.ViewRect;
const int32 kHTileSize = 8;
checkf((ViewRect.Min.X % kHTileSize) == 0 && (ViewRect.Min.Y % kHTileSize) == 0, TEXT("Viewport rect must be %d-pixel aligned."), kHTileSize);
const FIntVector DispatchDim = FComputeShaderUtils::GetGroupCount(ViewRect.Size(), kHTileSize);
const uint32 PlatformConfig = RHIGetHTilePlatformConfig(SceneTexturesExtent.X, SceneTexturesExtent.Y);
FRDGTextureUAVRef SceneDepthUAV = GraphBuilder.CreateUAV(FRDGTextureUAVDesc::CreateForMetaData(SceneDepth, ERDGTextureMetaDataAccess::CompressedSurface));
FRDGTextureUAVRef SceneStencilUAV = GraphBuilder.CreateUAV(FRDGTextureUAVDesc::CreateForMetaData(SceneDepth, ERDGTextureMetaDataAccess::Stencil));
FRDGTextureUAVRef SceneHTileUAV = GraphBuilder.CreateUAV(FRDGTextureUAVDesc::CreateForMetaData(SceneDepth, ERDGTextureMetaDataAccess::HTile));
FRDGTextureUAVRef VelocityUAV = bEmitVelocity ? GraphBuilder.CreateUAV(VelocityBuffer) : nullptr;
FRDGTextureUAVRef ShadingMaskUAV = GraphBuilder.CreateUAV(RasterResults.ShadingMask);
FDepthExportCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FDepthExportCS::FParameters>();
PassParameters->View = View.GetShaderParameters();
PassParameters->Scene = View.GetSceneUniforms().GetBuffer(GraphBuilder);
PassParameters->InViews = GraphBuilder.CreateSRV(RasterResults.ViewsBuffer);
PassParameters->VisibleClustersSWHW = GraphBuilder.CreateSRV(RasterResults.VisibleClustersSWHW);
PassParameters->RasterBinMeta = GraphBuilder.CreateSRV(RasterResults.RasterBinMeta);
PassParameters->PageConstants = RasterResults.PageConstants;
PassParameters->ClusterPageData = Nanite::GStreamingManager.GetClusterPageDataSRV(GraphBuilder);
PassParameters->HierarchyBuffer = Nanite::GStreamingManager.GetHierarchySRV(GraphBuilder);
PassParameters->DepthExportConfig = FIntVector4(PlatformConfig, SceneTexturesExtent.X, StencilDecalMask, Nanite::FGlobalResources::GetMaxVisibleClusters());
PassParameters->ViewRect = FUint32Vector4((uint32)ViewRect.Min.X, (uint32)ViewRect.Min.Y, (uint32)ViewRect.Max.X, (uint32)ViewRect.Max.Y);
PassParameters->bWriteCustomStencil = false;
PassParameters->MeshPassIndex = ENaniteMeshPass::BasePass;
PassParameters->RegularMaterialRasterBinCount = Scene.NaniteRasterPipelines[ENaniteMeshPass::BasePass].GetRegularBinCount();
PassParameters->VisBuffer64 = VisBuffer64;
PassParameters->Velocity = VelocityUAV;
PassParameters->ShadingMask = ShadingMaskUAV;
PassParameters->SceneHTile = SceneHTileUAV;
PassParameters->SceneDepth = SceneDepthUAV;
PassParameters->SceneStencil = SceneStencilUAV;
FDepthExportCS::FPermutationDomain PermutationVectorCS;
PermutationVectorCS.Set<FDepthExportCS::FVelocityExportDim>(bEmitVelocity);
PermutationVectorCS.Set<FDepthExportCS::FShadingMaskExportDim>(true);
PermutationVectorCS.Set<FDepthExportCS::FSkinningDim>(bEmitVelocity && NaniteSkinnedMeshesSupported());
auto ComputeShader = View.ShaderMap->GetShader<FDepthExportCS>(PermutationVectorCS);
FComputeShaderUtils::AddPass(GraphBuilder, RDG_EVENT_NAME("DepthExport"), ComputeShader, PassParameters, DispatchDim);
}
else
{
// Can't use ERenderTargetLoadAction::EClear to clear here because it needs to be the same for all render targets.
AddClearRenderTargetPass(GraphBuilder, RasterResults.ShadingMask);
if (bClearVelocity)
{
AddClearRenderTargetPass(GraphBuilder, VelocityBuffer);
}
// Emit scene depth buffer, mask and velocity
{
FEmitSceneDepthPS::FPermutationDomain PermutationVectorPS;
PermutationVectorPS.Set<FEmitSceneDepthPS::FVelocityExportDim>(bEmitVelocity);
PermutationVectorPS.Set<FEmitSceneDepthPS::FShadingMaskExportDim>(true);
PermutationVectorPS.Set<FEmitSceneDepthPS::FSkinningDim>(bEmitVelocity && NaniteSkinnedMeshesSupported());
auto PixelShader = View.ShaderMap->GetShader<FEmitSceneDepthPS>(PermutationVectorPS);
auto* PassParameters = GraphBuilder.AllocParameters<FEmitSceneDepthPS::FParameters>();
PassParameters->View = View.GetShaderParameters();
PassParameters->Scene = View.GetSceneUniforms().GetBuffer(GraphBuilder);
PassParameters->InViews = GraphBuilder.CreateSRV(RasterResults.ViewsBuffer);
PassParameters->VisibleClustersSWHW = GraphBuilder.CreateSRV(RasterResults.VisibleClustersSWHW);
PassParameters->RasterBinMeta = GraphBuilder.CreateSRV(RasterResults.RasterBinMeta);
PassParameters->PageConstants = RasterResults.PageConstants;
PassParameters->VisBuffer64 = VisBuffer64;
PassParameters->ClusterPageData = Nanite::GStreamingManager.GetClusterPageDataSRV(GraphBuilder);
PassParameters->HierarchyBuffer = Nanite::GStreamingManager.GetHierarchySRV(GraphBuilder);
PassParameters->MeshPassIndex = ENaniteMeshPass::BasePass;
PassParameters->RegularMaterialRasterBinCount = Scene.NaniteRasterPipelines[ENaniteMeshPass::BasePass].GetRegularBinCount();
PassParameters->RenderTargets[0] = FRenderTargetBinding(RasterResults.ShadingMask, ERenderTargetLoadAction::ELoad);
PassParameters->RenderTargets[1] = bEmitVelocity ? FRenderTargetBinding(VelocityBuffer, ERenderTargetLoadAction::ELoad) : FRenderTargetBinding();
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(SceneDepth, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilWrite);
FPixelShaderUtils::AddFullscreenPass(
GraphBuilder,
View.ShaderMap,
RDG_EVENT_NAME("Emit Scene Depth/Resolve/Velocity"),
PixelShader,
PassParameters,
bDrawSceneViewsInOneNanitePass ? View.GetFamilyViewRect() : View.ViewRect,
TStaticBlendState<>::GetRHI(),
TStaticRasterizerState<>::GetRHI(),
TStaticDepthStencilState<true, CF_DepthNearOrEqual>::GetRHI()
);
}
// Emit scene stencil
{
auto PixelShader = View.ShaderMap->GetShader<FEmitSceneStencilPS>();
auto* PassParameters = GraphBuilder.AllocParameters<FEmitSceneStencilPS::FParameters>();
PassParameters->View = View.ViewUniformBuffer;
PassParameters->Scene = View.GetSceneUniforms().GetBuffer(GraphBuilder);
PassParameters->VisibleClustersSWHW = GraphBuilder.CreateSRV(RasterResults.VisibleClustersSWHW);
PassParameters->PageConstants = RasterResults.PageConstants;
PassParameters->ClusterPageData = Nanite::GStreamingManager.GetClusterPageDataSRV(GraphBuilder);
PassParameters->HierarchyBuffer = Nanite::GStreamingManager.GetHierarchySRV(GraphBuilder);
PassParameters->ShadingMask = RasterResults.ShadingMask;
PassParameters->VisBuffer64 = VisBuffer64;
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding
(
SceneDepth,
ERenderTargetLoadAction::ELoad,
FExclusiveDepthStencil::DepthWrite_StencilWrite
);
FPixelShaderUtils::AddFullscreenPass(
GraphBuilder,
View.ShaderMap,
RDG_EVENT_NAME("Emit Scene Stencil"),
PixelShader,
PassParameters,
View.ViewRect,
TStaticBlendState<>::GetRHI(),
TStaticRasterizerState<>::GetRHI(),
TStaticDepthStencilState<false, CF_DepthNearOrEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace>::GetRHI(),
StencilDecalMask | GET_STENCIL_BIT_MASK(DISTANCE_FIELD_REPRESENTATION, 1)
);
}
if (GRHISupportsResummarizeHTile && GNaniteResummarizeHTile != 0)
{
// Resummarize HTile meta data if the RHI supports it
AddResummarizeHTilePass(GraphBuilder, SceneDepth);
}
}
// Also emit Nanite to first stage depth buffer, only if necessary for this frame.
// It is not perfect, nanite cluster will have been HZB culled against Niagara opaque meshes that are not in the FirstStage depth buffer, so there will be holes.
// Still an improvement for Niagara opaque particles colliding with depth buffer, and validated by artists.
// Only using the PS path right now until we can optimise for platforms supporting write through UAV.
if (FirstStageDepthBuffer)
{
FEmitSceneDepthPS::FPermutationDomain PermutationVectorPS;
PermutationVectorPS.Set<FEmitSceneDepthPS::FVelocityExportDim>(false);
PermutationVectorPS.Set<FEmitSceneDepthPS::FShadingMaskExportDim>(false);
PermutationVectorPS.Set<FEmitSceneDepthPS::FSkinningDim>(false);
auto PixelShader = View.ShaderMap->GetShader<FEmitSceneDepthPS>(PermutationVectorPS);
auto* PassParameters = GraphBuilder.AllocParameters<FEmitSceneDepthPS::FParameters>();
PassParameters->View = View.GetShaderParameters();
PassParameters->Scene = View.GetSceneUniforms().GetBuffer(GraphBuilder);
PassParameters->InViews = GraphBuilder.CreateSRV(RasterResults.ViewsBuffer);
PassParameters->VisibleClustersSWHW = GraphBuilder.CreateSRV(RasterResults.VisibleClustersSWHW);
PassParameters->RasterBinMeta = GraphBuilder.CreateSRV(RasterResults.RasterBinMeta);
PassParameters->PageConstants = RasterResults.PageConstants;
PassParameters->VisBuffer64 = VisBuffer64;
PassParameters->ClusterPageData = Nanite::GStreamingManager.GetClusterPageDataSRV(GraphBuilder);
PassParameters->HierarchyBuffer = Nanite::GStreamingManager.GetHierarchySRV(GraphBuilder);
PassParameters->MeshPassIndex = ENaniteMeshPass::BasePass;
PassParameters->RegularMaterialRasterBinCount = Scene.NaniteRasterPipelines[ENaniteMeshPass::BasePass].GetRegularBinCount();
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(FirstStageDepthBuffer, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilNop);
FPixelShaderUtils::AddFullscreenPass(
GraphBuilder,
View.ShaderMap,
RDG_EVENT_NAME("Emit Scene First Stage Depth"),
PixelShader,
PassParameters,
bDrawSceneViewsInOneNanitePass ? View.GetFamilyViewRect() : View.ViewRect,
TStaticBlendState<>::GetRHI(),
TStaticRasterizerState<>::GetRHI(),
TStaticDepthStencilState<true, CF_DepthNearOrEqual>::GetRHI()
);
if (GRHISupportsResummarizeHTile && GNaniteResummarizeHTile != 0)
{
// Resummarize HTile meta data if the RHI supports it
AddResummarizeHTilePass(GraphBuilder, FirstStageDepthBuffer);
}
}
}
FCustomDepthContext InitCustomDepthStencilContext(
FRDGBuilder& GraphBuilder,
const FCustomDepthTextures& CustomDepthTextures,
bool bWriteCustomStencil
)
{
enum ECustomDepthExportMethod
{
DepthExportSeparatePS, // Emit depth & stencil from PS (Stencil separated and written to RT0)
DepthExportCS // Emit depth & stencil from CS with HTILE (requires RHI support)
};
check(CustomDepthTextures.IsValid());
FCustomDepthContext Output;
Output.bComputeExport = UseComputeDepthExport() && GNaniteCustomDepthExportMethod == DepthExportCS;
if (Output.bComputeExport)
{
if (!CustomDepthTextures.Depth->HasBeenProduced())
{
AddClearDepthStencilPass(GraphBuilder, CustomDepthTextures.Depth, CustomDepthTextures.DepthAction, CustomDepthTextures.StencilAction);
}
Output.InputDepth = CustomDepthTextures.Depth;
Output.InputStencilSRV = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateWithPixelFormat(CustomDepthTextures.Depth, PF_X24_G8));
// We can output directly to the depth target using compute
Output.DepthTarget = CustomDepthTextures.Depth;
Output.StencilTarget = bWriteCustomStencil ? CustomDepthTextures.Depth : nullptr;
}
else
{
if (CustomDepthTextures.Depth->HasBeenProduced())
{
Output.InputDepth = CustomDepthTextures.Depth;
Output.InputStencilSRV = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateWithPixelFormat(CustomDepthTextures.Depth, PF_X24_G8));
}
else
{
// Custom depth buffer hasn't been produced (because no non-Nanite has been rendered to it), so just composite Nanite
// custom depth with blank 1x1 textures
const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);
Output.InputDepth = SystemTextures.DepthDummy;
Output.InputStencilSRV = SystemTextures.StencilDummySRV;
}
// Since we cannot output the stencil ref from the pixel shader, we'll combine Nanite and non-Nanite custom depth/stencil
// into new, separate targets. Note that stencil test using custom stencil from this point will require tests to be
// performed manually in the pixel shader (see PostProcess materials, for example).
const FIntPoint CustomDepthExtent = CustomDepthTextures.Depth->Desc.Extent;
FRDGTextureDesc OutCustomDepthDesc = FRDGTextureDesc::Create2D(
CustomDepthExtent,
PF_DepthStencil,
FClearValueBinding::DepthFar,
TexCreate_DepthStencilTargetable | TexCreate_ShaderResource);
Output.DepthTarget = GraphBuilder.CreateTexture(OutCustomDepthDesc, TEXT("CombinedCustomDepth"));
if (bWriteCustomStencil)
{
FRDGTextureDesc OutCustomStencilDesc = FRDGTextureDesc::Create2D(
CustomDepthExtent,
PF_R16G16_UINT, //PF_R8G8_UINT,
FClearValueBinding::Transparent,
TexCreate_RenderTargetable | TexCreate_ShaderResource);
Output.StencilTarget = GraphBuilder.CreateTexture(OutCustomStencilDesc, TEXT("CombinedCustomStencil"));
}
}
return Output;
}
void EmitCustomDepthStencilTargets(
FRDGBuilder& GraphBuilder,
const FScene& Scene,
const FViewInfo& View,
bool bDrawSceneViewsInOneNanitePass,
const FIntVector4& PageConstants,
FRDGBufferRef VisibleClustersSWHW,
FRDGBufferRef ViewsBuffer,
FRDGTextureRef VisBuffer64,
const FCustomDepthContext& CustomDepthContext
)
{
LLM_SCOPE_BYTAG(Nanite);
RDG_EVENT_SCOPE(GraphBuilder, "Nanite::EmitCustomDepthStencilTargets");
FRDGTextureRef CustomDepth = CustomDepthContext.InputDepth;
FRDGTextureSRVRef CustomStencilSRV = CustomDepthContext.InputStencilSRV;
const bool bWriteCustomStencil = CustomDepthContext.StencilTarget != nullptr;
if (CustomDepthContext.bComputeExport)
{
// Emit custom depth and stencil from a CS that can handle HTILE
if (GNaniteDecompressDepth != 0)
{
// Force depth decompression so the depth shader only processes decompressed surfaces
FDummyDepthDecompressParameters* DecompressParams = GraphBuilder.AllocParameters<FDummyDepthDecompressParameters>();
DecompressParams->SceneDepth = CustomDepth;
GraphBuilder.AddPass(
RDG_EVENT_NAME("NaniteCustomDepthDecompress"),
DecompressParams,
ERDGPassFlags::Copy | ERDGPassFlags::NeverCull,
[](FRDGAsyncTask, FRHICommandList&) {}
);
}
const FIntRect ViewRect = bDrawSceneViewsInOneNanitePass ? View.GetFamilyViewRect() : View.ViewRect;
const int32 kHTileSize = 8;
checkf((ViewRect.Min.X % kHTileSize) == 0 && (ViewRect.Min.Y % kHTileSize) == 0, TEXT("Viewport rect must be %d-pixel aligned."), kHTileSize);
// Export depth
{
const FIntPoint CustomDepthExtent = CustomDepth->Desc.Extent;
const FIntVector DispatchDim = FComputeShaderUtils::GetGroupCount(ViewRect.Size(), kHTileSize);
const uint32 PlatformConfig = RHIGetHTilePlatformConfig(CustomDepthExtent.X, CustomDepthExtent.Y);
FRDGTextureUAVRef CustomDepthUAV = GraphBuilder.CreateUAV(FRDGTextureUAVDesc::CreateForMetaData(CustomDepth, ERDGTextureMetaDataAccess::CompressedSurface));
FRDGTextureUAVRef CustomStencilUAV = GraphBuilder.CreateUAV(FRDGTextureUAVDesc::CreateForMetaData(CustomDepth, ERDGTextureMetaDataAccess::Stencil));
FRDGTextureUAVRef CustomHTileUAV = GraphBuilder.CreateUAV(FRDGTextureUAVDesc::CreateForMetaData(CustomDepth, ERDGTextureMetaDataAccess::HTile));
FDepthExportCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FDepthExportCS::FParameters>();
PassParameters->View = View.GetShaderParameters();
PassParameters->Scene = View.GetSceneUniforms().GetBuffer(GraphBuilder);
PassParameters->InViews = GraphBuilder.CreateSRV(ViewsBuffer);
PassParameters->VisibleClustersSWHW = GraphBuilder.CreateSRV(VisibleClustersSWHW);
PassParameters->PageConstants = PageConstants;
PassParameters->ClusterPageData = Nanite::GStreamingManager.GetClusterPageDataSRV(GraphBuilder);
PassParameters->HierarchyBuffer = Nanite::GStreamingManager.GetHierarchySRV(GraphBuilder);
PassParameters->DepthExportConfig = FIntVector4(PlatformConfig, CustomDepthExtent.X, 0, Nanite::FGlobalResources::GetMaxVisibleClusters());
PassParameters->ViewRect = FUint32Vector4((uint32)ViewRect.Min.X, (uint32)ViewRect.Min.Y, (uint32)ViewRect.Max.X, (uint32)ViewRect.Max.Y);
PassParameters->bWriteCustomStencil = bWriteCustomStencil;
PassParameters->MeshPassIndex = ENaniteMeshPass::BasePass;
PassParameters->VisBuffer64 = VisBuffer64;
PassParameters->Velocity = nullptr;
PassParameters->ShadingMask = nullptr;
PassParameters->SceneHTile = CustomHTileUAV;
PassParameters->SceneDepth = CustomDepthUAV;
PassParameters->SceneStencil = CustomStencilUAV;
FDepthExportCS::FPermutationDomain PermutationVectorCS;
PermutationVectorCS.Set<FDepthExportCS::FVelocityExportDim>(false);
PermutationVectorCS.Set<FDepthExportCS::FShadingMaskExportDim>(false);
PermutationVectorCS.Set<FDepthExportCS::FSkinningDim>(false);
auto ComputeShader = View.ShaderMap->GetShader<FDepthExportCS>(PermutationVectorCS);
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("DepthExport"),
ComputeShader,
PassParameters,
DispatchDim
);
}
}
else // DepthExportSeparatePS
{
FRDGTextureRef OutCustomDepth = CustomDepthContext.DepthTarget;
FRDGTextureRef OutCustomStencil = CustomDepthContext.StencilTarget;
FEmitCustomDepthStencilPS::FPermutationDomain PermutationVectorPS;
PermutationVectorPS.Set<FEmitCustomDepthStencilPS::FWriteCustomStencilDim>(bWriteCustomStencil);
auto PixelShader = View.ShaderMap->GetShader<FEmitCustomDepthStencilPS>(PermutationVectorPS);
auto* PassParameters = GraphBuilder.AllocParameters<FEmitCustomDepthStencilPS::FParameters>();
// If we aren't emitting stencil, clear it so it's not garbage
ERenderTargetLoadAction StencilLoadAction = OutCustomStencil ? ERenderTargetLoadAction::ENoAction : ERenderTargetLoadAction::EClear;
PassParameters->View = View.ViewUniformBuffer;
PassParameters->Scene = View.GetSceneUniforms().GetBuffer(GraphBuilder);
PassParameters->InViews = GraphBuilder.CreateSRV(ViewsBuffer);
PassParameters->VisibleClustersSWHW = GraphBuilder.CreateSRV(VisibleClustersSWHW);
PassParameters->PageConstants = PageConstants;
PassParameters->VisBuffer64 = VisBuffer64;
PassParameters->ClusterPageData = Nanite::GStreamingManager.GetClusterPageDataSRV(GraphBuilder);
PassParameters->HierarchyBuffer = Nanite::GStreamingManager.GetHierarchySRV(GraphBuilder);
PassParameters->CustomDepth = CustomDepth;
PassParameters->CustomStencil = CustomStencilSRV;
PassParameters->RenderTargets[0] = OutCustomStencil ? FRenderTargetBinding(OutCustomStencil, ERenderTargetLoadAction::ENoAction) : FRenderTargetBinding();
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(OutCustomDepth, ERenderTargetLoadAction::ENoAction, StencilLoadAction, FExclusiveDepthStencil::DepthWrite_StencilNop);
FPixelShaderUtils::AddFullscreenPass(
GraphBuilder,
View.ShaderMap,
OutCustomStencil ? RDG_EVENT_NAME("Emit Custom Depth/Stencil") : RDG_EVENT_NAME("Emit Custom Depth"),
PixelShader,
PassParameters,
bDrawSceneViewsInOneNanitePass ? View.GetFamilyViewRect() : View.ViewRect,
TStaticBlendState<>::GetRHI(),
TStaticRasterizerState<>::GetRHI(),
TStaticDepthStencilState<true, CF_Always>::GetRHI()
);
}
}
void FinalizeCustomDepthStencil(
FRDGBuilder& GraphBuilder,
const FCustomDepthContext& CustomDepthContext,
FCustomDepthTextures& OutTextures
)
{
OutTextures.Depth = CustomDepthContext.DepthTarget;
if (CustomDepthContext.StencilTarget)
{
if (CustomDepthContext.bComputeExport)
{
// we wrote straight to the depth/stencil buffer
OutTextures.Stencil = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateWithPixelFormat(CustomDepthContext.StencilTarget, PF_X24_G8));
}
else
{
// separate stencil texture
OutTextures.Stencil = GraphBuilder.CreateSRV(CustomDepthContext.StencilTarget);
}
}
else
{
OutTextures.Stencil = CustomDepthContext.InputStencilSRV;
}
OutTextures.bSeparateStencilBuffer = !CustomDepthContext.bComputeExport;
}
void MarkSceneStencilRects(
FRDGBuilder& GraphBuilder,
const FRasterContext& RasterContext,
FScene& Scene,
FViewInfo* SharedView,
FIntPoint ViewportSize,
uint32 NumRects,
FRDGBufferSRVRef RectMinMaxBufferSRV,
FRDGTextureRef DepthAtlasTexture
)
{
FNaniteMarkStencilRectsParameters* PassParameters = GraphBuilder.AllocParameters<FNaniteMarkStencilRectsParameters>();
PassParameters->PS.View = SharedView->ViewUniformBuffer;
PassParameters->PS.VisBuffer64 = RasterContext.VisBuffer64;
PassParameters->PS.RenderTargets.DepthStencil = FDepthStencilBinding(
DepthAtlasTexture,
ERenderTargetLoadAction::ELoad,
ERenderTargetLoadAction::ELoad,
FExclusiveDepthStencil::DepthRead_StencilWrite
);
auto PixelShader = SharedView->ShaderMap->GetShader<FNaniteMarkStencilPS>();
FPixelShaderUtils::AddRasterizeToRectsPass(GraphBuilder,
SharedView->ShaderMap,
RDG_EVENT_NAME("Mark Stencil"),
PixelShader,
PassParameters,
ViewportSize,
RectMinMaxBufferSRV,
NumRects,
TStaticBlendState<>::GetRHI(),
TStaticRasterizerState<>::GetRHI(),
TStaticDepthStencilState<false, CF_DepthNearOrEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace>::GetRHI(),
STENCIL_SANDBOX_MASK
);
}
void EmitSceneDepthRects(
FRDGBuilder& GraphBuilder,
const FRasterContext& RasterContext,
FScene& Scene,
FViewInfo* SharedView,
FIntPoint ViewportSize,
uint32 NumRects,
FRDGBufferSRVRef RectMinMaxBufferSRV,
FRDGTextureRef DepthAtlasTexture
)
{
FNaniteEmitDepthRectsParameters* PassParameters = GraphBuilder.AllocParameters<FNaniteEmitDepthRectsParameters>();
PassParameters->PS.VisBuffer64 = RasterContext.VisBuffer64;
PassParameters->PS.RenderTargets.DepthStencil = FDepthStencilBinding(
DepthAtlasTexture,
ERenderTargetLoadAction::ELoad,
ERenderTargetLoadAction::ELoad,
FExclusiveDepthStencil::DepthWrite_StencilRead
);
FEmitSceneDepthPS::FPermutationDomain PermutationVectorPS;
PermutationVectorPS.Set<FEmitSceneDepthPS::FVelocityExportDim>(false);
PermutationVectorPS.Set<FEmitSceneDepthPS::FShadingMaskExportDim>(false);
PermutationVectorPS.Set<FEmitSceneDepthPS::FSkinningDim>(false);
auto PixelShader = SharedView->ShaderMap->GetShader<FEmitSceneDepthPS>(PermutationVectorPS);
FPixelShaderUtils::AddRasterizeToRectsPass(GraphBuilder,
SharedView->ShaderMap,
RDG_EVENT_NAME("Emit Depth"),
PixelShader,
PassParameters,
ViewportSize,
RectMinMaxBufferSRV,
NumRects,
TStaticBlendState<>::GetRHI(),
TStaticRasterizerState<>::GetRHI(),
TStaticDepthStencilState<true, CF_Always, true, CF_Equal>::GetRHI(),
STENCIL_SANDBOX_MASK
);
}
} // Nanite