Files
UnrealEngine/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandBuffer.h
2025-05-18 13:04:45 +08:00

154 lines
3.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "MetalThirdParty.h"
#include "MetalResources.h"
#include "MetalShaderResources.h"
#include "RHIBreadcrumbs.h"
#include "MetalProfiler.h"
#include "MetalCommandQueue.h"
class FMetalCommandBufferTimer;
struct FMetalCounterSample;
class FMetalEventNode;
class FMetalCommandBuffer
{
public:
FMetalCommandBuffer(MTL::CommandBuffer* InCommandBuffer, FMetalCommandQueue& Queue)
#if RHI_NEW_GPU_PROFILER
: EventStream(Queue.GetProfilerQueue())
#endif
{
CommandBuffer = InCommandBuffer;
CommandBuffer->retain();
}
~FMetalCommandBuffer()
{
CommandBuffer->release();
}
FORCEINLINE MTL::CommandBuffer*& GetMTLCmdBuffer() {return CommandBuffer;}
#if RHI_NEW_GPU_PROFILER == 0
FORCEINLINE void SetTimer(FMetalCommandBufferTimer* InTimer)
{
Timer = InTimer;
}
FORCEINLINE FMetalCommandBufferTimer* GetTimer()
{
return Timer;
}
#endif
#if WITH_RHI_BREADCRUMBS
#if RHI_NEW_GPU_PROFILER
void BeginBreadcrumb(FRHIBreadcrumbNode* Node)
{
FMetalBreadcrumbTrackerObject TrackerObject;
TrackerObject.Type = EMetalBreadcrumbTrackerType::Begin;
TrackerObject.CmdBuffer = this;
TrackerObject.Node = Node;
BreadcrumbTrackerStream.Add(TrackerObject);
}
void EndBreadcrumb(FRHIBreadcrumbNode* Node)
{
FMetalBreadcrumbTrackerObject TrackerObject;
TrackerObject.Type = EMetalBreadcrumbTrackerType::End;
TrackerObject.CmdBuffer = this;
TrackerObject.Node = Node;
BreadcrumbTrackerStream.Add(TrackerObject);
}
#endif
#endif
void AddCounterSample(FMetalCounterSamplePtr CounterSample)
{
#if RHI_NEW_GPU_PROFILER == 0
for(FMetalEventNode* Node : ActiveEventNodes)
{
if(EventSampleCounters.Contains(Node))
{
EventSampleCounters[Node].Add(CounterSample);
}
else
{
EventSampleCounters.Add(Node, {CounterSample});
}
}
#elif WITH_RHI_BREADCRUMBS
FMetalBreadcrumbTrackerObject TrackerObject;
TrackerObject.Type = EMetalBreadcrumbTrackerType::Encode;
TrackerObject.CmdBuffer = this;
TrackerObject.CounterSample = CounterSample;
BreadcrumbTrackerStream.Add(TrackerObject);
#endif
CounterSamples.Add(CounterSample);
}
#if RHI_NEW_GPU_PROFILER
void SetBeginWorkTimestamp(uint64_t* Timestamp)
{
BeginWorkTimestamp = Timestamp;
}
void SetEndWorkTimestamp(uint64_t* Timestamp)
{
EndWorkTimestamp = Timestamp;
}
template <typename TEventType, typename... TArgs>
TEventType& EmplaceProfilerEvent(TArgs&&... Args)
{
TEventType& Data = EventStream.Emplace<TEventType>(Forward<TArgs>(Args)...);
if constexpr (std::is_same_v<UE::RHI::GPUProfiler::FEvent::FBeginWork, TEventType>)
{
// Store BeginEvents in a separate array as the CPUTimestamp field needs updating at submit time.
BeginEvents.Add(&Data);
}
// Not sure what to do here, ask Luke!
return Data;
}
void FlushProfilerEvents(UE::RHI::GPUProfiler::FEventStream& Destination, uint64 CPUTimestamp)
{
for (UE::RHI::GPUProfiler::FEvent::FBeginWork* BeginEvent : BeginEvents)
{
BeginEvent->CPUTimestamp = CPUTimestamp;
}
BeginEvents.Reset();
Destination.Append(MoveTemp(EventStream));
}
#endif
TArray<FMetalRHIRenderQuery*> TimestampQueries;
TArray<FMetalRHIRenderQuery*> OcclusionQueries;
TArray<FMetalCounterSamplePtr> CounterSamples;
#if RHI_NEW_GPU_PROFILER == 0
TMap<FMetalEventNode*, TArray<FMetalCounterSamplePtr>> EventSampleCounters;
TArray<FMetalEventNode*> ActiveEventNodes;
#else
UE::RHI::GPUProfiler::FEventStream EventStream;
TArray<UE::RHI::GPUProfiler::FEvent::FBeginWork*, TInlineAllocator<8>> BeginEvents;
#if WITH_RHI_BREADCRUMBS
TArray<FMetalBreadcrumbTrackerObject> BreadcrumbTrackerStream;
#endif
uint64_t* BeginWorkTimestamp;
uint64_t* EndWorkTimestamp;
#endif
private:
MTL::CommandBuffer* CommandBuffer;
FMetalCommandBufferTimer* Timer = nullptr;
};