218 lines
5.4 KiB
C++
218 lines
5.4 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
VulkanGPUProfiler.h: Vulkan Utility definitions.
|
|
=============================================================================*/
|
|
|
|
#pragma once
|
|
|
|
#include "Containers/Queue.h"
|
|
#include "GPUProfiler.h"
|
|
#include "VulkanConfiguration.h"
|
|
|
|
class FVulkanCommandBuffer;
|
|
class FVulkanContextCommon;
|
|
class FVulkanDevice;
|
|
|
|
#if (RHI_NEW_GPU_PROFILER == 0)
|
|
|
|
using FVulkanSyncPoint = FGraphEvent;
|
|
using FVulkanSyncPointRef = TRefCountPtr<FVulkanSyncPoint>;
|
|
|
|
class FVulkanGPUTiming : public FGPUTiming
|
|
{
|
|
public:
|
|
FVulkanGPUTiming(FVulkanContextCommon* InContext, FVulkanDevice* InDevice)
|
|
: Device(InDevice)
|
|
, Context(InContext)
|
|
, bIsTiming(false)
|
|
, bEndTimestampIssued(false)
|
|
{
|
|
}
|
|
|
|
~FVulkanGPUTiming();
|
|
|
|
/**
|
|
* Start a GPU timing measurement.
|
|
*/
|
|
void StartTiming(FVulkanContextCommon* InContext = nullptr);
|
|
|
|
/**
|
|
* End a GPU timing measurement.
|
|
* The timing for this particular measurement will be resolved at a later time by the GPU.
|
|
*/
|
|
void EndTiming(FVulkanContextCommon* InContext = nullptr);
|
|
|
|
/**
|
|
* Retrieves the most recently resolved timing measurement.
|
|
* The unit is the same as for FPlatformTime::Cycles(). Returns 0 if there are no resolved measurements.
|
|
*
|
|
* @return Value of the most recently resolved timing, or 0 if no measurements have been resolved by the GPU yet.
|
|
*/
|
|
uint64 GetTiming(bool bGetCurrentResultsAndBlock = false);
|
|
|
|
/**
|
|
* Initializes all Vulkan resources.
|
|
*/
|
|
void Initialize(uint32 PoolSize = 8);
|
|
|
|
/**
|
|
* Releases all Vulkan resources.
|
|
*/
|
|
void Release();
|
|
|
|
bool IsComplete() const
|
|
{
|
|
check(bEndTimestampIssued);
|
|
return true;
|
|
}
|
|
|
|
bool IsTiming() const
|
|
{
|
|
return bIsTiming;
|
|
}
|
|
|
|
static void CalibrateTimers(FVulkanDevice& Device);
|
|
|
|
private:
|
|
|
|
void DiscardOldestQuery();
|
|
|
|
/**
|
|
* Initializes the static variables, if necessary.
|
|
*/
|
|
static void PlatformStaticInitialize(void* UserData);
|
|
|
|
FVulkanDevice* Device = nullptr;
|
|
FVulkanContextCommon* Context = nullptr;
|
|
|
|
/** Whether we are currently timing the GPU: between StartTiming() and EndTiming(). */
|
|
bool bIsTiming;
|
|
bool bEndTimestampIssued;
|
|
uint64 LastTime = 0;
|
|
|
|
struct FPendingQuery
|
|
{
|
|
FVulkanSyncPointRef StartSyncPoint;
|
|
uint64 StartResult = 0;
|
|
FVulkanSyncPointRef EndSyncPoint;
|
|
uint64 EndResult = 0;
|
|
};
|
|
const uint32 MaxPendingQueries = 4;
|
|
uint32 NumPendingQueries = 0;
|
|
TQueue<FPendingQuery*> PendingQueries;
|
|
FPendingQuery* ActiveQuery = nullptr;
|
|
};
|
|
|
|
/** A single perf event node, which tracks information about a appBeginDrawEvent/appEndDrawEvent range. */
|
|
class FVulkanEventNode : public FGPUProfilerEventNode
|
|
{
|
|
public:
|
|
FVulkanEventNode(const TCHAR* InName, FGPUProfilerEventNode* InParent, FVulkanContextCommon* InContext, FVulkanDevice* InDevice) :
|
|
FGPUProfilerEventNode(InName, InParent),
|
|
Timing(InContext, InDevice)
|
|
{
|
|
// Initialize Buffered timestamp queries
|
|
Timing.Initialize();
|
|
}
|
|
|
|
virtual ~FVulkanEventNode()
|
|
{
|
|
Timing.Release();
|
|
}
|
|
|
|
/**
|
|
* Returns the time in ms that the GPU spent in this draw event.
|
|
* This blocks the CPU if necessary, so can cause hitching.
|
|
*/
|
|
virtual float GetTiming() override final;
|
|
|
|
|
|
virtual void StartTiming() override final
|
|
{
|
|
Timing.StartTiming();
|
|
}
|
|
|
|
virtual void StopTiming() override final
|
|
{
|
|
Timing.EndTiming();
|
|
}
|
|
|
|
FVulkanGPUTiming Timing;
|
|
};
|
|
|
|
/** An entire frame of perf event nodes, including ancillary timers. */
|
|
class FVulkanEventNodeFrame : public FGPUProfilerEventNodeFrame
|
|
{
|
|
public:
|
|
|
|
FVulkanEventNodeFrame(FVulkanContextCommon* InContext, FVulkanDevice* InDevice)
|
|
: RootEventTiming(InContext, InDevice)
|
|
{
|
|
RootEventTiming.Initialize();
|
|
}
|
|
|
|
~FVulkanEventNodeFrame()
|
|
{
|
|
RootEventTiming.Release();
|
|
}
|
|
|
|
/** Start this frame of per tracking */
|
|
virtual void StartFrame() override final;
|
|
|
|
/** End this frame of per tracking, but do not block yet */
|
|
virtual void EndFrame() override final;
|
|
|
|
/** Calculates root timing base frequency (if needed by this RHI) */
|
|
virtual float GetRootTimingResults() override final;
|
|
|
|
virtual bool PlatformDisablesVSync() const { return true; }
|
|
|
|
/** Timer tracking inclusive time spent in the root nodes. */
|
|
FVulkanGPUTiming RootEventTiming;
|
|
};
|
|
|
|
/**
|
|
* Encapsulates GPU profiling logic and data.
|
|
* There's only one global instance of this struct so it should only contain global data, nothing specific to a frame.
|
|
*/
|
|
struct FVulkanGPUProfiler : public FGPUProfiler
|
|
{
|
|
/** GPU hitch profile histories */
|
|
TIndirectArray<FVulkanEventNodeFrame> GPUHitchEventNodeFrames;
|
|
|
|
FVulkanGPUProfiler(FVulkanContextCommon* InContext, FVulkanDevice* InDevice);
|
|
|
|
virtual ~FVulkanGPUProfiler();
|
|
|
|
virtual FGPUProfilerEventNode* CreateEventNode(const TCHAR* InName, FGPUProfilerEventNode* InParent) override final
|
|
{
|
|
FVulkanEventNode* EventNode = new FVulkanEventNode(InName, InParent, CmdContext, Device);
|
|
return EventNode;
|
|
}
|
|
|
|
void BeginFrame();
|
|
|
|
void EndFrameBeforeSubmit();
|
|
void EndFrame();
|
|
|
|
bool bCommandlistSubmitted;
|
|
FVulkanDevice* Device;
|
|
FVulkanContextCommon* CmdContext;
|
|
|
|
#if VULKAN_SUPPORTS_GPU_CRASH_DUMPS
|
|
void PrepareCrashMarkerkBuffer();
|
|
void PushMarkerForCrash(FVulkanCommandBuffer* CmdBuffer, VkBuffer DestBuffer, const TCHAR* Name);
|
|
void PopMarkerForCrash(FVulkanCommandBuffer* CmdBuffer, VkBuffer DestBuffer);
|
|
void DumpCrashMarkers(void* BufferData);
|
|
#endif
|
|
|
|
// For crash/marker tracking
|
|
TMap<uint32, FString> CachedStrings;
|
|
TArray<uint32> PushPopStack;
|
|
|
|
TArray<uint64> CrashMarkers;
|
|
bool bBeginFrame;
|
|
};
|
|
|
|
#endif // (RHI_NEW_GPU_PROFILER == 0)
|