You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
* Increased limit for GPU profiler events on D3D12. A typical frame with 4 view families would easily exhaust the old limit of 1K events resulting in many events not showing up in the profile -- limit increased to 8K, and confirmed negligible difference in memory. Fixed bug where we were only using half the queries allocated as well (unnecessary multiplication by 2 when calling RHICreateRenderQueryPool). * Added optional "ProfileDescription" to FSceneViewFamily, which is appended to the Unreal Insights profile event names for both CPU and GPU, so you can differentiate view families. * Infrastructure added to CPU profiler to allow a verbose name to be added to a Stat timing block. * Infrastructure added to GPU profiler to allow verbose names to be added to timing blocks in general, both Event and Stat timing blocks. * Added stats display for Display Cluster listing the CPU and GPU cost, and GPU assignment per view family by name, with the goal of allowing clients to tune features enabled per view family to adjust performance, without needing to gather performance information from Unreal Insights. * FSceneRenderer::DoCrossGPUTransfers uses push transfer without lockstep (logic copied from 4.27), which significantly improves perf. #rb zach.bethel marc.audy mihnea.balta #jira none #rnx #preflight 61df4d23484d866ec01f17cf #ROBOMERGE-AUTHOR: jason.hoerner #ROBOMERGE-SOURCE: CL 18591295 in //UE5/Release-5.0/... via CL 18591308 via CL 18591324 #ROBOMERGE-BOT: STARSHIP (Release-Engine-Test -> Main) (v899-18417669) [CL 18591346 by jason hoerner in ue5-main branch]
390 lines
8.6 KiB
C++
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->IsImmediateCommandList())
|
|
{
|
|
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
|