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

117 lines
3.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "InstanceCullingManager.h"
#include "CoreMinimal.h"
#include "RHI.h"
#include "RendererModule.h"
#include "ShaderParameterMacros.h"
#include "RenderGraphResources.h"
#include "RenderGraphBuilder.h"
#include "RenderGraphUtils.h"
#include "SceneRendering.h"
#include "ScenePrivate.h"
#include "ViewData.h"
#include "ProfilingDebugging/CpuProfilerTrace.h"
#include "InstanceCulling/InstanceCullingContext.h"
static int32 GAllowBatchedBuildRenderingCommands = 1;
static FAutoConsoleVariableRef CVarAllowBatchedBuildRenderingCommands(
TEXT("r.InstanceCulling.AllowBatchedBuildRenderingCommands"),
GAllowBatchedBuildRenderingCommands,
TEXT("Whether to allow batching BuildRenderingCommands for GPU instance culling"),
ECVF_RenderThreadSafe);
FInstanceCullingManager::FInstanceCullingManager(FRDGBuilder& GraphBuilder, const FScene& InScene, FSceneUniformBuffer& InSceneUniforms, FRendererViewDataManager& InViewDataManager)
: Scene(InScene), GPUScene(InScene.GPUScene), SceneUniforms(InSceneUniforms), ViewDataManager(InViewDataManager), bIsEnabled(GPUScene.IsEnabled())
{
DummyUniformBuffer = FInstanceCullingContext::CreateDummyInstanceCullingUniformBuffer(GraphBuilder);
for (FViewInfo *ViewInfo : ViewDataManager.GetRegisteredPrimaryViews())
{
if (ViewInfo->PrevViewInfo.HZB != nullptr)
{
check(IsInRenderingThread());
ViewPrevHZBs.AddUnique(ViewInfo->PrevViewInfo.HZB);
}
}
}
FInstanceCullingManager::~FInstanceCullingManager()
{
}
void FInstanceCullingManager::AllocateViews(int32 NumViews)
{
return ViewDataManager.AllocateViews(NumViews);
}
int32 FInstanceCullingManager::RegisterView(const Nanite::FPackedViewParams& Params)
{
return ViewDataManager.RegisterView(Params);
}
int32 FInstanceCullingManager::GetBinIndex(EBatchProcessingMode Mode, const TRefCountPtr<IPooledRenderTarget>& HZB)
{
if (Mode == EBatchProcessingMode::UnCulled)
{
return 0;
}
int32 BinIndex;
// all contexts without a valid HZB go in the first bin, together with the first view's HZB
if (!HZB.IsValid())
{
return 1;
}
if (!ViewPrevHZBs.Find(HZB, BinIndex))
{
// error: the HZB is not registered correctly
return -1;
}
// bin 0 is used for EBatchProcessingMode::UnCulled batches
BinIndex += 1;
return BinIndex;
}
void FInstanceCullingManager::SetDummyCullingParams(FRDGBuilder& GraphBuilder, FInstanceCullingDrawParams& Parameters)
{
Parameters.Scene = SceneUniforms.GetBuffer(GraphBuilder);
Parameters.InstanceCulling = GetDummyInstanceCullingUniformBuffer();
}
bool FInstanceCullingManager::AllowBatchedBuildRenderingCommands(const FGPUScene& GPUScene)
{
return GPUScene.IsEnabled() && GAllowBatchedBuildRenderingCommands != 0 && !FRDGBuilder::IsImmediateMode();
}
void FInstanceCullingManager::BeginDeferredCulling(FRDGBuilder& GraphBuilder)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FInstanceCullingManager::BeginDeferredCulling);
// We need the dynamic mesh bounds buffer for culling.
Scene.AddGPUSkinCacheAsyncComputeWait(GraphBuilder);
// TODO: is this needed(?)
ViewDataManager.FlushRegisteredViews(GraphBuilder);
// Cannot defer pass execution in immediate mode.
if (!AllowBatchedBuildRenderingCommands(GPUScene))
{
return;
}
// If there are no instances, there can be no work to perform later.
if (GPUScene.GetNumInstances() == 0 || ViewDataManager.GetNumCullingViews() == 0)
{
return;
}
DeferredContext = FInstanceCullingContext::CreateDeferredContext(GraphBuilder, GPUScene, *this);
}