Files
UnrealEngineUWP/Engine/Source/Runtime/RenderCore/Private/RenderGraphEvent.cpp
aleksander netzel 9a8aa76713 Add ERDGPassFlags::NeverParallel to allow RDG passes to stay on render thread.
Both Immediate/AsyncCompute passes are always executed in order on the render thread but other RDG passes can run in parallel.
With my previous change, RayTracingScene pass was changed to Compute/AsyncCompute to have the correct order on the GPU.
But when it was set to Compute (when AsyncCompute was disabled) it was running in parallel with passes it depends on which led to random crashes.
Because the dependency between passes was implicit, we needed a new flag to express the intent and get the desired order between execution lambdas.

On behalf of Zach Bethel.

#rb zach.bethel
#jira UE-141003
#preflight 61fb0d9e923ac18db7015160
#lockdown michal.valient

#ROBOMERGE-AUTHOR: aleksander.netzel
#ROBOMERGE-SOURCE: CL 18841970 in //UE5/Release-5.0/... via CL 18841984 via CL 18842341
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v910-18824042)

[CL 18842374 by aleksander netzel in ue5-main branch]
2022-02-03 09:15:49 -05:00

390 lines
8.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "RenderGraphEvent.h"
#include "RenderGraphBuilder.h"
#include "RenderGraphPrivate.h"
#include "RenderGraphPass.h"
RENDERCORE_API bool GetEmitRDGEvents()
{
#if RDG_EVENTS != RDG_EVENTS_NONE
bool bRDGChannelEnabled = false;
#if RDG_ENABLE_TRACE
bRDGChannelEnabled = UE_TRACE_CHANNELEXPR_IS_ENABLED(RDGChannel);
#endif // RDG_ENABLE_TRACE
return GRDGEmitEvents != 0 || GRDGDebug != 0 || bRDGChannelEnabled != 0;
#else
return false;
#endif
}
#if RDG_EVENTS == RDG_EVENTS_STRING_COPY
FRDGEventName::FRDGEventName(const TCHAR* InEventFormat, ...)
: EventFormat(InEventFormat)
{
check(InEventFormat);
{
va_list VAList;
va_start(VAList, InEventFormat);
TCHAR TempStr[256];
// Build the string in the temp buffer
FCString::GetVarArgs(TempStr, UE_ARRAY_COUNT(TempStr), InEventFormat, VAList);
va_end(VAList);
FormattedEventName = TempStr;
}
}
#endif
#if RDG_GPU_SCOPES
static void GetEventScopePathRecursive(const FRDGEventScope* Root, FString& String)
{
if (Root->ParentScope)
{
GetEventScopePathRecursive(Root->ParentScope, String);
}
if (!String.IsEmpty())
{
String += TEXT(".");
}
String += Root->Name.GetTCHAR();
}
FString FRDGEventScope::GetPath(const FRDGEventName& Event) const
{
FString Path;
GetEventScopePathRecursive(this, Path);
Path += TEXT(".");
Path += Event.GetTCHAR();
return MoveTemp(Path);
}
FRDGEventScopeGuard::FRDGEventScopeGuard(FRDGBuilder& InGraphBuilder, FRDGEventName&& ScopeName, bool InbCondition)
: GraphBuilder(InGraphBuilder)
, bCondition(InbCondition)
{
if (bCondition)
{
GraphBuilder.GPUScopeStacks.BeginEventScope(MoveTemp(ScopeName), GraphBuilder.RHICmdList.GetGPUMask());
}
}
FRDGEventScopeGuard::~FRDGEventScopeGuard()
{
if (bCondition)
{
GraphBuilder.GPUScopeStacks.EndEventScope();
}
}
static void OnPushEvent(FRHIComputeCommandList& RHICmdList, const FRDGEventScope* Scope, bool bRDGEvents)
{
#if RHI_WANT_BREADCRUMB_EVENTS
RHICmdList.PushBreadcrumb(Scope->Name.GetTCHAR());
#endif
if (bRDGEvents)
{
SCOPED_GPU_MASK(RHICmdList, Scope->GPUMask);
RHICmdList.PushEvent(Scope->Name.GetTCHAR(), FColor(0));
}
}
static void OnPopEvent(FRHIComputeCommandList& RHICmdList, const FRDGEventScope* Scope, bool bRDGEvents)
{
if (bRDGEvents)
{
SCOPED_GPU_MASK(RHICmdList, Scope->GPUMask);
RHICmdList.PopEvent();
}
#if RHI_WANT_BREADCRUMB_EVENTS
RHICmdList.PopBreadcrumb();
#endif
}
void FRDGEventScopeOpArray::Execute(FRHIComputeCommandList& RHICmdList)
{
for (int32 Index = 0; Index < Ops.Num(); ++Index)
{
FRDGEventScopeOp Op = Ops[Index];
if (Op.IsScope())
{
if (Op.IsPush())
{
OnPushEvent(RHICmdList, Op.Scope, bRDGEvents);
}
else
{
OnPopEvent(RHICmdList, Op.Scope, bRDGEvents);
}
}
else
{
if (Op.IsPush())
{
RHICmdList.PushEvent(Op.Name, FColor(255, 255, 255));
}
else
{
RHICmdList.PopEvent();
}
}
}
}
#if RHI_WANT_BREADCRUMB_EVENTS
void FRDGEventScopeOpArray::Execute(FRDGBreadcrumbState& State)
{
for (int32 Index = 0; Index < Ops.Num(); ++Index)
{
FRDGEventScopeOp Op = Ops[Index];
if (Op.IsScope())
{
if (Op.IsPush())
{
State.PushBreadcrumb(Op.Scope->Name.GetTCHAR());
State.Version++;
}
else
{
State.PopBreadcrumb();
State.Version++;
}
}
}
}
#endif
FRDGEventScopeOpArray FRDGEventScopeStack::CompilePassPrologue(const FRDGPass* Pass)
{
FRDGEventScopeOpArray Ops(bRDGEvents);
if (IsEnabled())
{
Ops.Ops = ScopeStack.CompilePassPrologue(Pass->GetGPUScopes().Event, GetEmitRDGEvents() ? Pass->GetEventName().GetTCHAR() : nullptr);
}
return MoveTemp(Ops);
}
FRDGEventScopeOpArray FRDGEventScopeStack::CompilePassEpilogue()
{
FRDGEventScopeOpArray Ops(bRDGEvents);
if (IsEnabled())
{
Ops.Ops = ScopeStack.CompilePassEpilogue();
}
return MoveTemp(Ops);
}
FRDGGPUStatScopeGuard::FRDGGPUStatScopeGuard(FRDGBuilder& InGraphBuilder, const FName& Name, const FName& StatName, const TCHAR* Description, int32(*NumDrawCallsPtr)[MAX_NUM_GPUS])
: GraphBuilder(InGraphBuilder)
{
GraphBuilder.GPUScopeStacks.BeginStatScope(Name, StatName, Description, NumDrawCallsPtr);
}
FRDGGPUStatScopeGuard::~FRDGGPUStatScopeGuard()
{
GraphBuilder.GPUScopeStacks.EndStatScope();
}
FRDGGPUStatScopeOpArray::FRDGGPUStatScopeOpArray(TRDGScopeOpArray<FRDGGPUStatScopeOp> InOps, FRHIGPUMask GPUMask)
: Ops(InOps)
, Type(EType::Prologue)
{
#if HAS_GPU_STATS
for (int32 Index = 0; Index < Ops.Num(); ++Index)
{
FRDGGPUStatScopeOp& Op = Ops[Index];
if (Op.IsPush())
{
Op.Query = FRealtimeGPUProfiler::Get()->PushEvent(GPUMask, Op.Scope->Name, Op.Scope->StatName, *Op.Scope->Description);
}
else
{
Op.Query = FRealtimeGPUProfiler::Get()->PopEvent();
}
}
#endif
}
void FRDGGPUStatScopeOpArray::Execute(FRHIComputeCommandList& RHICmdListCompute)
{
#if HAS_GPU_STATS
if (!RHICmdListCompute.IsGraphics())
{
return;
}
FRHICommandList& RHICmdList = static_cast<FRHICommandList&>(RHICmdListCompute);
for (int32 Index = 0; Index < Ops.Num(); ++Index)
{
Ops[Index].Query.Submit(RHICmdList);
}
if (OverrideEventIndex != kInvalidEventIndex)
{
if (Type == EType::Prologue)
{
FRealtimeGPUProfiler::Get()->PushEventOverride(OverrideEventIndex);
}
else
{
FRealtimeGPUProfiler::Get()->PopEventOverride();
}
}
for (int32 Index = Ops.Num() - 1; Index >= 0; --Index)
{
const FRDGGPUStatScopeOp Op = Ops[Index];
const FRDGGPUStatScope* Scope = Op.Scope;
if (Scope->DrawCallCounter != nullptr && (**Scope->DrawCallCounter) != -1)
{
RHICmdList.EnqueueLambda(
[DrawCallCounter = Scope->DrawCallCounter, bPush = Op.IsPush()](auto&)
{
GCurrentNumDrawCallsRHIPtr = bPush ? DrawCallCounter : &GCurrentNumDrawCallsRHI;
});
break;
}
}
#endif
}
FRDGGPUStatScopeOpArray FRDGGPUStatScopeStack::CompilePassPrologue(const FRDGPass* Pass, FRHIGPUMask GPUMask)
{
#if HAS_GPU_STATS
if (IsEnabled() && Pass->GetPipeline() == ERHIPipeline::Graphics)
{
FRDGGPUStatScopeOpArray Ops(ScopeStack.CompilePassPrologue(Pass->GetGPUScopes().Stat), GPUMask);
if (!Pass->IsParallelExecuteAllowed())
{
OverrideEventIndex = FRealtimeGPUProfiler::Get()->GetCurrentEventIndex();
Ops.OverrideEventIndex = OverrideEventIndex;
}
return MoveTemp(Ops);
}
#endif
return {};
}
FRDGGPUStatScopeOpArray FRDGGPUStatScopeStack::CompilePassEpilogue()
{
#if HAS_GPU_STATS
if (OverrideEventIndex != FRDGGPUStatScopeOpArray::kInvalidEventIndex)
{
FRDGGPUStatScopeOpArray Ops;
Ops.OverrideEventIndex = OverrideEventIndex;
OverrideEventIndex = FRDGGPUStatScopeOpArray::kInvalidEventIndex;
return MoveTemp(Ops);
}
#endif
return {};
}
FRDGGPUScopeOpArrays FRDGGPUScopeStacksByPipeline::CompilePassPrologue(const FRDGPass* Pass, FRHIGPUMask GPUMask)
{
return GetScopeStacks(Pass->GetPipeline()).CompilePassPrologue(Pass, GPUMask);
}
FRDGGPUScopeOpArrays FRDGGPUScopeStacksByPipeline::CompilePassEpilogue(const FRDGPass* Pass)
{
return GetScopeStacks(Pass->GetPipeline()).CompilePassEpilogue();
}
#endif
//////////////////////////////////////////////////////////////////////////
// CPU Scopes
//////////////////////////////////////////////////////////////////////////
#if RDG_CPU_SCOPES
#if CSV_PROFILER
FRDGScopedCsvStatExclusive::FRDGScopedCsvStatExclusive(FRDGBuilder& InGraphBuilder, const char* InStatName)
: FScopedCsvStatExclusive(InStatName)
, GraphBuilder(InGraphBuilder)
{
GraphBuilder.CPUScopeStacks.CSV.BeginScope(InStatName);
}
FRDGScopedCsvStatExclusive::~FRDGScopedCsvStatExclusive()
{
GraphBuilder.CPUScopeStacks.CSV.EndScope();
}
FRDGScopedCsvStatExclusiveConditional::FRDGScopedCsvStatExclusiveConditional(FRDGBuilder& InGraphBuilder, const char* InStatName, bool bInCondition)
: FScopedCsvStatExclusiveConditional(InStatName, bInCondition)
, GraphBuilder(InGraphBuilder)
{
if (bCondition)
{
GraphBuilder.CPUScopeStacks.CSV.BeginScope(InStatName);
}
}
FRDGScopedCsvStatExclusiveConditional::~FRDGScopedCsvStatExclusiveConditional()
{
if (bCondition)
{
GraphBuilder.CPUScopeStacks.CSV.EndScope();
}
}
#endif
inline void OnPushCSVStat(const FRDGCSVStatScope* Scope)
{
#if CSV_PROFILER
FCsvProfiler::BeginExclusiveStat(Scope->StatName);
#endif
}
inline void OnPopCSVStat(const FRDGCSVStatScope* Scope)
{
#if CSV_PROFILER
FCsvProfiler::EndExclusiveStat(Scope->StatName);
#endif
}
void FRDGCSVStatScopeOpArray::Execute()
{
for (int32 Index = 0; Index < Ops.Num(); ++Index)
{
FRDGCSVStatScopeOp Op = Ops[Index];
if (Op.IsPush())
{
OnPushCSVStat(Op.Scope);
}
else
{
OnPopCSVStat(Op.Scope);
}
}
}
FRDGCSVStatScopeOpArray FRDGCSVStatScopeStack::CompilePassPrologue(const FRDGPass* Pass)
{
if (IsEnabled())
{
return ScopeStack.CompilePassPrologue(Pass->GetCPUScopes().CSV);
}
return {};
}
#endif