From 292c19fe82436050cc181747d2cc96cd246c968b Mon Sep 17 00:00:00 2001 From: jamie hayes Date: Tue, 26 Apr 2022 14:37:33 -0400 Subject: [PATCH] Add functionality for Nanite instances of a certain type to properly be filtered out if disabled by their respective ShowFlags on the view family. #rb rune.stubbe #preflight 62680e711638ac249e7b8a5a #ROBOMERGE-AUTHOR: jamie.hayes #ROBOMERGE-SOURCE: CL 19921850 via CL 19922083 via CL 19922618 #ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v943-19904690) [CL 19925604 by jamie hayes in ue5-main branch] --- .../Private/Nanite/NanitePrimitiveFilter.usf | 8 +++-- Engine/Shaders/Private/SceneData.ush | 14 +++++++- Engine/Shaders/Shared/NaniteDefinitions.h | 6 ++++ .../PrimitiveUniformShaderParameters.cpp | 5 ++- .../Private/Rendering/NaniteResources.cpp | 14 ++++++++ .../Runtime/Engine/Public/NaniteSceneProxy.h | 16 ++++++++++ .../Public/PrimitiveUniformShaderParameters.h | 32 +++++++++++++++---- .../Private/Nanite/NaniteCullRaster.cpp | 32 +++++++++++-------- 8 files changed, 102 insertions(+), 25 deletions(-) diff --git a/Engine/Shaders/Private/Nanite/NanitePrimitiveFilter.usf b/Engine/Shaders/Private/Nanite/NanitePrimitiveFilter.usf index ee6a3f91a5d0..76832bb60666 100644 --- a/Engine/Shaders/Private/Nanite/NanitePrimitiveFilter.usf +++ b/Engine/Shaders/Private/Nanite/NanitePrimitiveFilter.usf @@ -8,6 +8,7 @@ #include "NaniteDataDecode.ush" uint NumPrimitives; +uint HiddenFilterFlags; #if HAS_HIDDEN_PRIMITIVES_LIST uint NumHiddenPrimitives; @@ -54,15 +55,16 @@ void PrimitiveFilter // GPU Scene version of IsPrimitiveHidden() from SceneVisibility.cpp if (PrimitiveId < NumPrimitives) { - bool bHidden = false; - FPrimitiveSceneData PrimitiveData = GetPrimitiveData(PrimitiveId); const uint PrimitiveComponentId = PrimitiveData.PrimitiveComponentId; + // Allow arbitrary flag matching on the primitive (used for the ViewFamily's EngineShowFlags) + bool bHidden = ((PrimitiveData.NaniteFilterFlags & ~HiddenFilterFlags) != PrimitiveData.NaniteFilterFlags); + #if HAS_HIDDEN_PRIMITIVES_LIST // If any primitives are explicitly hidden, remove them now. BRANCH - if (NumHiddenPrimitives > 0) + if (!bHidden && NumHiddenPrimitives > 0) { bHidden = BinarySearchLoop(HiddenPrimitivesList, NumHiddenPrimitives, PrimitiveComponentId); } diff --git a/Engine/Shaders/Private/SceneData.ush b/Engine/Shaders/Private/SceneData.ush index 707d8e5a09d9..7249ab80313a 100644 --- a/Engine/Shaders/Private/SceneData.ush +++ b/Engine/Shaders/Private/SceneData.ush @@ -4,6 +4,7 @@ #include "LargeWorldCoordinates.ush" #include "OctahedralCommon.ush" +#include "/Engine/Shared/NaniteDefinitions.h" #ifndef USE_GLOBAL_GPU_SCENE_DATA #define USE_GLOBAL_GPU_SCENE_DATA 0 @@ -144,6 +145,7 @@ struct FPrimitiveSceneData float3 WireframeColor; // TODO: Should refactor out all editor data into a separate buffer float3 LevelColor; // TODO: Should refactor out all editor data into a separate buffer uint NaniteImposterIndex; + uint NaniteFilterFlags; float4 CustomPrimitiveData[NUM_CUSTOM_PRIMITIVE_DATA]; // TODO: Move to associated array to shrink primitive data and pack cachelines more effectively }; @@ -183,6 +185,8 @@ FPrimitiveSceneData GetPrimitiveDataFromUniformBuffer() PrimitiveData.InstancePayloadDataStride = Primitive.InstancePayloadDataStride; PrimitiveData.WireframeColor = Primitive.WireframeColor; PrimitiveData.LevelColor = Primitive.LevelColor; + PrimitiveData.NaniteImposterIndex = Primitive.NaniteImposterIndexAndFilterFlags & NANITE_IMPOSTER_INDEX_MASK; + PrimitiveData.NaniteFilterFlags = Primitive.NaniteImposterIndexAndFilterFlags >> NANITE_IMPOSTER_INDEX_NUM_BITS; PrimitiveData.PersistentPrimitiveIndex = Primitive.PersistentPrimitiveIndex; UNROLL for (int DataIndex = 0; DataIndex < NUM_CUSTOM_PRIMITIVE_DATA; ++DataIndex) @@ -292,10 +296,18 @@ FPrimitiveSceneData GetPrimitiveData(uint PrimitiveId) PrimitiveData.InstanceLocalBoundsExtent = LoadPrimitivePrimitiveSceneDataElement(PrimitiveIndex, 28).xyz; PrimitiveData.InstancePayloadDataStride = asuint(LoadPrimitivePrimitiveSceneDataElement(PrimitiveIndex, 28).w); PrimitiveData.WireframeColor = LoadPrimitivePrimitiveSceneDataElement(PrimitiveIndex, 29).xyz; - PrimitiveData.NaniteImposterIndex = asuint(LoadPrimitivePrimitiveSceneDataElement(PrimitiveIndex, 29).w); PrimitiveData.LevelColor = LoadPrimitivePrimitiveSceneDataElement(PrimitiveIndex, 30).xyz; PrimitiveData.PersistentPrimitiveIndex = asint(LoadPrimitivePrimitiveSceneDataElement(PrimitiveIndex, 30).w); + uint NaniteImposterIndexAndFilterFlags = asuint(LoadPrimitivePrimitiveSceneDataElement(PrimitiveIndex, 29).w); + PrimitiveData.NaniteFilterFlags = NaniteImposterIndexAndFilterFlags >> NANITE_IMPOSTER_INDEX_NUM_BITS; + PrimitiveData.NaniteImposterIndex = NaniteImposterIndexAndFilterFlags & NANITE_IMPOSTER_INDEX_MASK; + + if (PrimitiveData.NaniteImposterIndex == NANITE_IMPOSTER_INDEX_MASK) + { + PrimitiveData.NaniteImposterIndex = INVALID_NANITE_IMPOSTER_INDEX; + } + // TODO: Move to associated array (and editor data) to shrink primitive data and better pack cachelines UNROLL for (int DataIndex = 0; DataIndex < NUM_CUSTOM_PRIMITIVE_DATA; ++DataIndex) diff --git a/Engine/Shaders/Shared/NaniteDefinitions.h b/Engine/Shaders/Shared/NaniteDefinitions.h index 0c81d47da1b7..19af76f22ad7 100644 --- a/Engine/Shaders/Shared/NaniteDefinitions.h +++ b/Engine/Shaders/Shared/NaniteDefinitions.h @@ -60,6 +60,12 @@ #define NANITE_MAX_GROUP_PARTS_MASK ((1 << NANITE_MAX_GROUP_PARTS_BITS) - 1) #define NANITE_MAX_GROUP_PARTS (1 << NANITE_MAX_GROUP_PARTS_BITS) +#define NANITE_FILTER_FLAGS_NUM_BITS (4u) +#define NANITE_IMPOSTER_INDEX_NUM_BITS (32u - NANITE_FILTER_FLAGS_NUM_BITS) +#define NANITE_IMPOSTER_INDEX_MASK ((1u << NANITE_IMPOSTER_INDEX_NUM_BITS) - 1u) +#define NANITE_FILTER_FLAGS_MASK (((1u << NANITE_FILTER_FLAGS_NUM_BITS) - 1u) << NANITE_IMPOSTER_INDEX_NUM_BITS) +#define INVALID_NANITE_IMPOSTER_INDEX (0xFFFFFFFFu) + #define NANITE_MAX_BVH_NODE_FANOUT_BITS 2 #define NANITE_MAX_BVH_NODE_FANOUT_MASK ((1 << NANITE_MAX_BVH_NODE_FANOUT_BITS)-1) #define NANITE_MAX_BVH_NODE_FANOUT (1 << NANITE_MAX_BVH_NODE_FANOUT_BITS) diff --git a/Engine/Source/Runtime/Engine/Private/PrimitiveUniformShaderParameters.cpp b/Engine/Source/Runtime/Engine/Private/PrimitiveUniformShaderParameters.cpp index c042ec8fe9d1..f378641383fc 100644 --- a/Engine/Source/Runtime/Engine/Private/PrimitiveUniformShaderParameters.cpp +++ b/Engine/Source/Runtime/Engine/Private/PrimitiveUniformShaderParameters.cpp @@ -142,6 +142,7 @@ FPrimitiveSceneShaderData::FPrimitiveSceneShaderData(const FPrimitiveSceneProxy* uint32 NaniteResourceID = INDEX_NONE; uint32 NaniteHierarchyOffset = INDEX_NONE; uint32 NaniteImposterIndex = INDEX_NONE; + uint32 NaniteFilterFlags = 0u; bool bHasNaniteImposterData = false; bool bEvaluateWorldPositionOffset = !OptimizedWPO; @@ -149,6 +150,7 @@ FPrimitiveSceneShaderData::FPrimitiveSceneShaderData(const FPrimitiveSceneProxy* if (Proxy->IsNaniteMesh()) { Proxy->GetNaniteResourceInfo(NaniteResourceID, NaniteHierarchyOffset, NaniteImposterIndex); + NaniteFilterFlags = uint32(static_cast(Proxy)->GetFilterFlags()); if (OptimizedWPO) { bEvaluateWorldPositionOffset = static_cast(Proxy)->EvaluateWorldPositionOffset(); @@ -193,6 +195,7 @@ FPrimitiveSceneShaderData::FPrimitiveSceneShaderData(const FPrimitiveSceneProxy* .NaniteResourceID(NaniteResourceID) .NaniteHierarchyOffset(NaniteHierarchyOffset) .NaniteImposterIndex(NaniteImposterIndex) + .NaniteFilterFlags(NaniteFilterFlags) .PrimitiveComponentId(Proxy->GetPrimitiveComponentId().PrimIDValue) .EditorColors(Proxy->GetWireframeColor(), Proxy->GetLevelColor()); @@ -277,7 +280,7 @@ void FPrimitiveSceneShaderData::Setup(const FPrimitiveUniformShaderParameters& P Data[29].X = PrimitiveUniformShaderParameters.WireframeColor.X; Data[29].Y = PrimitiveUniformShaderParameters.WireframeColor.Y; Data[29].Z = PrimitiveUniformShaderParameters.WireframeColor.Z; - Data[29].W = *(const float*)&PrimitiveUniformShaderParameters.NaniteImposterIndex; + Data[29].W = *(const float*)&PrimitiveUniformShaderParameters.NaniteImposterIndexAndFilterFlags; Data[30].X = PrimitiveUniformShaderParameters.LevelColor.X; Data[30].Y = PrimitiveUniformShaderParameters.LevelColor.Y; diff --git a/Engine/Source/Runtime/Engine/Private/Rendering/NaniteResources.cpp b/Engine/Source/Runtime/Engine/Private/Rendering/NaniteResources.cpp index d1d20937f234..10c2bbed7dce 100644 --- a/Engine/Source/Runtime/Engine/Private/Rendering/NaniteResources.cpp +++ b/Engine/Source/Runtime/Engine/Private/Rendering/NaniteResources.cpp @@ -778,11 +778,25 @@ FSceneProxy::FSceneProxy(UInstancedStaticMeshComponent* Component) bHasRayTracingInstances = false; } #endif + + FilterFlags = EFilterFlags::InstancedStaticMesh; } FSceneProxy::FSceneProxy(UHierarchicalInstancedStaticMeshComponent* Component) : FSceneProxy(static_cast(Component)) { + switch (Component->GetViewRelevanceType()) + { + case EHISMViewRelevanceType::Grass: + FilterFlags = EFilterFlags::Grass; + break; + case EHISMViewRelevanceType::Foliage: + FilterFlags = EFilterFlags::Foliage; + break; + default: + FilterFlags = EFilterFlags::InstancedStaticMesh; + break; + } } FSceneProxy::~FSceneProxy() diff --git a/Engine/Source/Runtime/Engine/Public/NaniteSceneProxy.h b/Engine/Source/Runtime/Engine/Public/NaniteSceneProxy.h index c3750a6f5faf..1f6d5a579f0e 100644 --- a/Engine/Source/Runtime/Engine/Public/NaniteSceneProxy.h +++ b/Engine/Source/Runtime/Engine/Public/NaniteSceneProxy.h @@ -74,6 +74,16 @@ ENGINE_API bool IsSupportedBlendMode(EBlendMode Mode); ENGINE_API bool IsSupportedMaterialDomain(EMaterialDomain Domain); ENGINE_API bool IsWorldPositionOffsetSupported(); +enum class EFilterFlags : uint8 +{ + None = 0u, + InstancedStaticMesh = (1u << 0u), + Foliage = (1u << 1u), + Grass = (1u << 2u), +}; + +ENUM_CLASS_FLAGS(EFilterFlags) + class FSceneProxyBase : public FPrimitiveSceneProxy { public: @@ -151,6 +161,11 @@ public: return MaterialMaxIndex; } + inline EFilterFlags GetFilterFlags() const + { + return FilterFlags; + } + #if WITH_EDITOR inline const TConstArrayView GetHitProxyIds() const { @@ -194,6 +209,7 @@ protected: EHitProxyMode HitProxyMode = EHitProxyMode::MaterialSection; #endif int32 MaterialMaxIndex = INDEX_NONE; + EFilterFlags FilterFlags = EFilterFlags::None; uint8 bHasProgrammableRaster : 1; uint8 bEvaluateWorldPositionOffset : 1; }; diff --git a/Engine/Source/Runtime/Engine/Public/PrimitiveUniformShaderParameters.h b/Engine/Source/Runtime/Engine/Public/PrimitiveUniformShaderParameters.h index 91b4ae69accf..60f73985e1eb 100644 --- a/Engine/Source/Runtime/Engine/Public/PrimitiveUniformShaderParameters.h +++ b/Engine/Source/Runtime/Engine/Public/PrimitiveUniformShaderParameters.h @@ -13,6 +13,7 @@ #include "LightmapUniformShaderParameters.h" #include "UnifiedBuffer.h" #include "Containers/StaticArray.h" +#include "NaniteDefinitions.h" /** * The uniform shader parameters associated with a primitive. @@ -51,7 +52,7 @@ BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FPrimitiveUniformShaderParameters,ENGINE_AP SHADER_PARAMETER(FVector3f, InstanceLocalBoundsExtent) SHADER_PARAMETER(uint32, InstancePayloadDataStride) SHADER_PARAMETER(FVector3f, WireframeColor) // Only needed for editor/development - SHADER_PARAMETER(uint32, NaniteImposterIndex) + SHADER_PARAMETER(uint32, NaniteImposterIndexAndFilterFlags) SHADER_PARAMETER(FVector3f, LevelColor) // Only needed for editor/development SHADER_PARAMETER(int32, PersistentPrimitiveIndex) SHADER_PARAMETER_ARRAY(FVector4f, CustomPrimitiveData, [FCustomPrimitiveData::NumCustomPrimitiveDataFloat4s]) // Custom data per primitive that can be accessed through material expression parameters and modified through UStaticMeshComponent @@ -115,6 +116,7 @@ public: bVisibleInSceneCaptureOnly = false; bHiddenInSceneCapture = false; bForceHidden = false; + bHasNaniteImposter = false; // Default colors Parameters.WireframeColor = FVector3f(1.0f, 1.0f, 1.0f); @@ -128,9 +130,9 @@ public: Parameters.PrimitiveComponentId = ~uint32(0u); // Nanite - Parameters.NaniteResourceID = INDEX_NONE; - Parameters.NaniteHierarchyOffset = INDEX_NONE; - Parameters.NaniteImposterIndex = INDEX_NONE; + Parameters.NaniteResourceID = INDEX_NONE; + Parameters.NaniteHierarchyOffset = INDEX_NONE; + Parameters.NaniteImposterIndexAndFilterFlags = NANITE_IMPOSTER_INDEX_MASK; // Instance data Parameters.InstanceSceneDataOffset = INDEX_NONE; @@ -178,7 +180,6 @@ public: PRIMITIVE_UNIFORM_BUILDER_METHOD(uint32, PrimitiveComponentId); PRIMITIVE_UNIFORM_BUILDER_METHOD(uint32, NaniteResourceID); PRIMITIVE_UNIFORM_BUILDER_METHOD(uint32, NaniteHierarchyOffset); - PRIMITIVE_UNIFORM_BUILDER_METHOD(uint32, NaniteImposterIndex); PRIMITIVE_UNIFORM_BUILDER_METHOD(uint32, LightmapUVIndex); PRIMITIVE_UNIFORM_BUILDER_METHOD(uint32, LightmapDataIndex); @@ -283,6 +284,24 @@ public: return *this; } + inline FPrimitiveUniformShaderParametersBuilder& NaniteImposterIndex(uint32 ImposterIndex) + { + bHasNaniteImposter = ImposterIndex != INDEX_NONE; + + check(!bHasNaniteImposter || ImposterIndex < NANITE_IMPOSTER_INDEX_MASK); + Parameters.NaniteImposterIndexAndFilterFlags = (Parameters.NaniteImposterIndexAndFilterFlags & NANITE_FILTER_FLAGS_MASK) | (ImposterIndex & NANITE_IMPOSTER_INDEX_MASK); + + return *this; + } + + inline FPrimitiveUniformShaderParametersBuilder& NaniteFilterFlags(uint32 FilterFlags) + { + check(FilterFlags < (1u << NANITE_FILTER_FLAGS_NUM_BITS)); + Parameters.NaniteImposterIndexAndFilterFlags = (FilterFlags << NANITE_IMPOSTER_INDEX_NUM_BITS) | (Parameters.NaniteImposterIndexAndFilterFlags & NANITE_IMPOSTER_INDEX_MASK); + + return *this; + } + inline const FPrimitiveUniformShaderParameters& Build() { const FLargeWorldRenderPosition AbsoluteWorldPosition(AbsoluteLocalToWorld.GetOrigin()); @@ -361,7 +380,7 @@ public: Parameters.Flags |= ((LightingChannels & 0x1) != 0) ? PRIMITIVE_SCENE_DATA_FLAG_LIGHTING_CHANNEL_0 : 0u; Parameters.Flags |= ((LightingChannels & 0x2) != 0) ? PRIMITIVE_SCENE_DATA_FLAG_LIGHTING_CHANNEL_1 : 0u; Parameters.Flags |= ((LightingChannels & 0x4) != 0) ? PRIMITIVE_SCENE_DATA_FLAG_LIGHTING_CHANNEL_2 : 0u; - Parameters.Flags |= (Parameters.NaniteImposterIndex != INDEX_NONE) ? PRIMITIVE_SCENE_DATA_FLAG_HAS_NANITE_IMPOSTER : 0u; + Parameters.Flags |= bHasNaniteImposter ? PRIMITIVE_SCENE_DATA_FLAG_HAS_NANITE_IMPOSTER : 0u; Parameters.Flags |= bHasInstanceLocalBounds ? PRIMITIVE_SCENE_DATA_FLAG_HAS_INSTANCE_LOCAL_BOUNDS : 0u; Parameters.Flags |= bCastShadow ? PRIMITIVE_SCENE_DATA_FLAG_CAST_SHADOWS : 0u; Parameters.Flags |= bCastContactShadow ? PRIMITIVE_SCENE_DATA_FLAG_HAS_CAST_CONTACT_SHADOW : 0u; @@ -412,6 +431,7 @@ private: uint32 bVisibleInSceneCaptureOnly : 1; uint32 bHiddenInSceneCapture : 1; uint32 bForceHidden : 1; + uint32 bHasNaniteImposter : 1; }; inline TUniformBufferRef CreatePrimitiveUniformBufferImmediate( diff --git a/Engine/Source/Runtime/Renderer/Private/Nanite/NaniteCullRaster.cpp b/Engine/Source/Runtime/Renderer/Private/Nanite/NaniteCullRaster.cpp index 087cd02b3381..3453c1a26a3b 100644 --- a/Engine/Source/Runtime/Renderer/Private/Nanite/NaniteCullRaster.cpp +++ b/Engine/Source/Runtime/Renderer/Private/Nanite/NaniteCullRaster.cpp @@ -2,6 +2,7 @@ #include "NaniteCullRaster.h" #include "NaniteVisualizationData.h" +#include "NaniteSceneProxy.h" #include "RHI.h" #include "SceneUtils.h" #include "ScenePrivate.h" @@ -268,19 +269,6 @@ class FPrimitiveFilter_CS : public FNaniteGlobalShader using FPermutationDomain = TShaderPermutationDomain; - static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) - { - FPermutationDomain PermutationVector(Parameters.PermutationId); - - if (!PermutationVector.Get() && !PermutationVector.Get()) - { - // Don't compile a permutation with both buffers disabled - return false; - } - - return FNaniteGlobalShader::ShouldCompilePermutation(Parameters); - } - static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { FNaniteGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment); @@ -291,6 +279,7 @@ class FPrimitiveFilter_CS : public FNaniteGlobalShader BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER(uint32, NumPrimitives) + SHADER_PARAMETER(uint32, HiddenFilterFlags) SHADER_PARAMETER(uint32, NumHiddenPrimitives) SHADER_PARAMETER(uint32, NumShowOnlyPrimitives) @@ -1374,12 +1363,26 @@ void AddPass_PrimitiveFilter( const uint32 PrimitiveCount = uint32(Scene.Primitives.Num()); const uint32 HiddenPrimitiveCount = SceneView.HiddenPrimitives.Num(); const uint32 ShowOnlyPrimitiveCount = SceneView.ShowOnlyPrimitives.IsSet() ? SceneView.ShowOnlyPrimitives->Num() : 0u; + + EFilterFlags HiddenFilterFlags = EFilterFlags::None; + if (!SceneView.Family->EngineShowFlags.InstancedStaticMeshes) + { + HiddenFilterFlags |= EFilterFlags::InstancedStaticMesh; + } + if (!SceneView.Family->EngineShowFlags.InstancedFoliage) + { + HiddenFilterFlags |= EFilterFlags::Foliage; + } + if (!SceneView.Family->EngineShowFlags.InstancedGrass) + { + HiddenFilterFlags |= EFilterFlags::Grass; + } CullingContext.PrimitiveFilterBuffer = nullptr; CullingContext.HiddenPrimitivesBuffer = nullptr; CullingContext.ShowOnlyPrimitivesBuffer = nullptr; - if (CVarNaniteFilterPrimitives.GetValueOnRenderThread() != 0 && (HiddenPrimitiveCount + ShowOnlyPrimitiveCount) > 0) + if (CVarNaniteFilterPrimitives.GetValueOnRenderThread() != 0 && ((HiddenPrimitiveCount + ShowOnlyPrimitiveCount) > 0 || HiddenFilterFlags != EFilterFlags::None)) { check(PrimitiveCount > 0); const uint32 DWordCount = FMath::DivideAndRoundUp(PrimitiveCount, 32u); // 32 primitive bits per uint32 @@ -1450,6 +1453,7 @@ void AddPass_PrimitiveFilter( FPrimitiveFilter_CS::FParameters* PassParameters = GraphBuilder.AllocParameters(); PassParameters->NumPrimitives = PrimitiveCount; + PassParameters->HiddenFilterFlags = uint32(HiddenFilterFlags); PassParameters->NumHiddenPrimitives = FMath::RoundUpToPowerOfTwo(HiddenPrimitiveCount); PassParameters->NumShowOnlyPrimitives = FMath::RoundUpToPowerOfTwo(ShowOnlyPrimitiveCount); PassParameters->GPUSceneParameters = GPUSceneParameters;