7437b69d52
Add new `Total/GPU` category to memory profiler. Implement for D3D12 and Vulkan with allocators.
565 lines
17 KiB
C++
565 lines
17 KiB
C++
// Copyright (c) Wojciech Figat. All rights reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Engine/Platform/Platform.h"
|
|
#include "Engine/Platform/CriticalSection.h"
|
|
#include "Engine/Core/NonCopyable.h"
|
|
#include "Engine/Core/Collections/Array.h"
|
|
#include "Engine/Scripting/ScriptingObject.h"
|
|
#include "GPUAdapter.h"
|
|
#include "GPULimits.h"
|
|
#include "Enums.h"
|
|
#include "Config.h"
|
|
|
|
class ITextureOwner;
|
|
class RenderTask;
|
|
class GPUResource;
|
|
class GPUContext;
|
|
class GPUShader;
|
|
class GPUTimerQuery;
|
|
class GPUTexture;
|
|
class GPUBuffer;
|
|
class GPUSampler;
|
|
class GPUPipelineState;
|
|
class GPUConstantBuffer;
|
|
class GPUVertexLayout;
|
|
class GPUTasksContext;
|
|
class GPUTasksExecutor;
|
|
class GPUSwapChain;
|
|
class GPUTasksManager;
|
|
class Shader;
|
|
class Model;
|
|
class Material;
|
|
class MaterialBase;
|
|
|
|
/// <summary>
|
|
/// Contains information about current GPU memory usage and budget.
|
|
/// </summary>
|
|
API_STRUCT(NoDefault) struct GPUMemoryStats
|
|
{
|
|
DECLARE_SCRIPTING_TYPE_MINIMAL(GPUMemoryStats);
|
|
|
|
/// <summary>
|
|
/// Amount of used dedicated video memory in bytes. Memory local to the device, and represents the fastest available memory to the GPU.
|
|
/// </summary>
|
|
API_FIELD() uint64 UsedDedicatedMemory = 0;
|
|
|
|
/// <summary>
|
|
/// Total amount of dedicated memory budget in bytes. Memory local to the device, and represents the fastest available memory to the GPU.
|
|
/// </summary>
|
|
API_FIELD() uint64 TotalDedicatedMemory = 0;
|
|
|
|
/// <summary>
|
|
/// Amount of used system video memory in bytes. Memory non-local to the device, and may have slower performance than the dedicated/local.
|
|
/// </summary>
|
|
API_FIELD() uint64 UsedSystemMemory = 0;
|
|
|
|
/// <summary>
|
|
/// Total amount of system memory budget in bytes. Memory non-local to the device, and may have slower performance than the dedicated/local.
|
|
/// </summary>
|
|
API_FIELD() uint64 TotalSystemMemory = 0;
|
|
};
|
|
|
|
/// <summary>
|
|
/// Graphics device object for rendering on GPU.
|
|
/// </summary>
|
|
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API GPUDevice : public ScriptingObject
|
|
{
|
|
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUDevice);
|
|
public:
|
|
/// <summary>
|
|
/// Graphics Device states that describe its lifetime.
|
|
/// </summary>
|
|
enum class DeviceState
|
|
{
|
|
Missing = 0,
|
|
Created,
|
|
Ready,
|
|
Removed,
|
|
Disposing,
|
|
Disposed
|
|
};
|
|
|
|
/// <summary>
|
|
/// Describes a video output display (monitor).
|
|
/// </summary>
|
|
API_STRUCT() struct VideoOutput
|
|
{
|
|
DECLARE_SCRIPTING_TYPE_NO_SPAWN(VideoOutputMode);
|
|
|
|
/// <summary>
|
|
/// The display name.
|
|
/// </summary>
|
|
API_FIELD() String Name;
|
|
|
|
/// <summary>
|
|
/// The native screen resolution width (in pixel).
|
|
/// </summary>
|
|
API_FIELD() uint32 Width = 0;
|
|
|
|
/// <summary>
|
|
/// The native screen resolution height (in pixel).
|
|
/// </summary>
|
|
API_FIELD() uint32 Height = 0;
|
|
|
|
/// <summary>
|
|
/// The maximum screen refresh rate (in hertz).
|
|
/// </summary>
|
|
API_FIELD() float RefreshRate = 0;
|
|
|
|
/// <summary>
|
|
/// Flag that indicates that monitor supports displaying High Dynamic Range colors.
|
|
/// </summary>
|
|
API_FIELD() bool HDR = false;
|
|
};
|
|
|
|
/// <summary>
|
|
/// Describes a video output display mode (monitor screen mode).
|
|
/// </summary>
|
|
API_STRUCT() struct VideoOutputMode
|
|
{
|
|
DECLARE_SCRIPTING_TYPE_NO_SPAWN(VideoOutputMode);
|
|
|
|
/// <summary>
|
|
/// The resolution width (in pixel).
|
|
/// </summary>
|
|
API_FIELD() uint32 Width;
|
|
|
|
/// <summary>
|
|
/// The resolution height (in pixel).
|
|
/// </summary>
|
|
API_FIELD() uint32 Height;
|
|
|
|
/// <summary>
|
|
/// The screen refresh rate (in hertz).
|
|
/// </summary>
|
|
API_FIELD() float RefreshRate;
|
|
|
|
/// <summary>
|
|
/// The index of the VideoOutput from the device monitors list.
|
|
/// </summary>
|
|
API_FIELD() int32 VideoOutputIndex;
|
|
};
|
|
|
|
/// <summary>
|
|
/// The singleton instance of the graphics device.
|
|
/// </summary>
|
|
API_FIELD(ReadOnly) static GPUDevice* Instance;
|
|
|
|
protected:
|
|
// State
|
|
DeviceState _state;
|
|
bool _isRendering;
|
|
bool _wasVSyncUsed;
|
|
int32 _drawGpuEventIndex;
|
|
RendererType _rendererType;
|
|
ShaderProfile _shaderProfile;
|
|
FeatureLevel _featureLevel;
|
|
|
|
// Private resources (hidden with declaration)
|
|
struct PrivateData;
|
|
PrivateData* _res;
|
|
Array<GPUResource*> _resources;
|
|
CriticalSection _resourcesLock;
|
|
|
|
void OnRequestingExit();
|
|
|
|
protected:
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="GPUDevice"/> class.
|
|
/// </summary>
|
|
/// <param name="type">The renderer type.</param>
|
|
/// <param name="profile">The shader profile.</param>
|
|
GPUDevice(RendererType type, ShaderProfile profile);
|
|
|
|
public:
|
|
/// <summary>
|
|
/// Finalizes an instance of the <see cref="GPUDevice"/> class.
|
|
/// </summary>
|
|
virtual ~GPUDevice();
|
|
|
|
public:
|
|
/// <summary>
|
|
/// The graphics device locking mutex.
|
|
/// </summary>
|
|
CriticalSection Locker;
|
|
|
|
/// <summary>
|
|
/// The total amount of graphics memory in bytes.
|
|
/// </summary>
|
|
API_FIELD(ReadOnly) uint64 TotalGraphicsMemory;
|
|
|
|
/// <summary>
|
|
/// Indicates that debug tool is profiling device (eg. RenderDoc).
|
|
/// </summary>
|
|
API_FIELD(ReadOnly) bool IsDebugToolAttached;
|
|
|
|
/// <summary>
|
|
/// The GPU limits.
|
|
/// </summary>
|
|
API_FIELD(ReadOnly) GPULimits Limits;
|
|
|
|
/// <summary>
|
|
/// The available video outputs (monitors).
|
|
/// </summary>
|
|
API_FIELD(ReadOnly) Array<VideoOutput> VideoOutputs;
|
|
|
|
/// <summary>
|
|
/// The available video output modes.
|
|
/// </summary>
|
|
API_FIELD(ReadOnly) Array<VideoOutputMode> VideoOutputModes;
|
|
|
|
/// <summary>
|
|
/// Quad rendering shader
|
|
/// </summary>
|
|
API_FIELD(ReadOnly) GPUShader* QuadShader;
|
|
|
|
/// <summary>
|
|
/// The current task being executed.
|
|
/// </summary>
|
|
RenderTask* CurrentTask;
|
|
|
|
/// <summary>
|
|
/// The supported features for the specified format (index is the pixel format value).
|
|
/// </summary>
|
|
FormatFeatures FeaturesPerFormat[static_cast<int32>(PixelFormat::MAX)];
|
|
|
|
/// <summary>
|
|
/// Gets the supported features for the specified format (index is the pixel format value).
|
|
/// </summary>
|
|
/// <param name="format">The format.</param>
|
|
/// <returns>The format features flags.</returns>
|
|
API_FUNCTION() FormatFeatures GetFormatFeatures(const PixelFormat format) const
|
|
{
|
|
return FeaturesPerFormat[(int32)format];
|
|
}
|
|
|
|
public:
|
|
/// <summary>
|
|
/// Gets current device state.
|
|
/// </summary>
|
|
FORCE_INLINE DeviceState GetState() const
|
|
{
|
|
return _state;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if device is during rendering state, otherwise false.
|
|
/// </summary>
|
|
API_PROPERTY() FORCE_INLINE bool IsRendering() const
|
|
{
|
|
return _isRendering;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if VSync was used during the last frame present.
|
|
/// </summary>
|
|
FORCE_INLINE bool WasVSyncUsed() const
|
|
{
|
|
return _wasVSyncUsed;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the device renderer type.
|
|
/// </summary>
|
|
API_PROPERTY() FORCE_INLINE RendererType GetRendererType() const
|
|
{
|
|
return _rendererType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets device shader profile type.
|
|
/// </summary>
|
|
API_PROPERTY() FORCE_INLINE ShaderProfile GetShaderProfile() const
|
|
{
|
|
return _shaderProfile;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets device feature level type.
|
|
/// </summary>
|
|
API_PROPERTY() FORCE_INLINE FeatureLevel GetFeatureLevel() const
|
|
{
|
|
return _featureLevel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the main GPU context.
|
|
/// </summary>
|
|
API_PROPERTY() virtual GPUContext* GetMainContext() = 0;
|
|
|
|
/// <summary>
|
|
/// Gets the adapter device.
|
|
/// </summary>
|
|
API_PROPERTY() virtual GPUAdapter* GetAdapter() const = 0;
|
|
|
|
/// <summary>
|
|
/// Gets the native pointer to the underlying graphics device. It's a low-level platform-specific handle.
|
|
/// </summary>
|
|
API_PROPERTY() virtual void* GetNativePtr() const = 0;
|
|
|
|
/// <summary>
|
|
/// Gets the amount of memory usage by all the GPU resources (in bytes). Returned value is estimated based on resources created by the engine and might not be accurate. Use GPUMemoryStats for more detailed memory budget usage.
|
|
/// </summary>
|
|
API_PROPERTY() uint64 GetMemoryUsage() const;
|
|
|
|
/// <summary>
|
|
/// Gets the current GPU memory stats.
|
|
/// </summary>
|
|
API_PROPERTY() virtual GPUMemoryStats GetMemoryStats();
|
|
|
|
/// <summary>
|
|
/// Gets the list with all active GPU resources.
|
|
/// </summary>
|
|
Array<GPUResource*> GetResources() const;
|
|
|
|
/// <summary>
|
|
/// Gets the GPU asynchronous work manager.
|
|
/// </summary>
|
|
GPUTasksManager* GetTasksManager() const;
|
|
|
|
/// <summary>
|
|
/// Gets the default material.
|
|
/// </summary>
|
|
API_PROPERTY() MaterialBase* GetDefaultMaterial() const;
|
|
|
|
/// <summary>
|
|
/// Gets the default material (Deformable domain).
|
|
/// </summary>
|
|
MaterialBase* GetDefaultDeformableMaterial() const;
|
|
|
|
/// <summary>
|
|
/// Gets the default normal map texture.
|
|
/// </summary>
|
|
GPUTexture* GetDefaultNormalMap() const;
|
|
|
|
/// <summary>
|
|
/// Gets the default solid white texture.
|
|
/// </summary>
|
|
API_PROPERTY() GPUTexture* GetDefaultWhiteTexture() const;
|
|
|
|
/// <summary>
|
|
/// Gets the default solid black texture.
|
|
/// </summary>
|
|
API_PROPERTY() GPUTexture* GetDefaultBlackTexture() const;
|
|
|
|
/// <summary>
|
|
/// Gets the shader pipeline state object for linear, fullscreen texture copy.
|
|
/// </summary>
|
|
GPUPipelineState* GetCopyLinearPS() const;
|
|
|
|
/// <summary>
|
|
/// Gets the shader pipeline state object for solid-color texture clear.
|
|
/// </summary>
|
|
GPUPipelineState* GetClearPS() const;
|
|
|
|
/// <summary>
|
|
/// Gets the shader pipeline state object for YUY2 frame decoding to RGBA.
|
|
/// </summary>
|
|
GPUPipelineState* GetDecodeYUY2PS() const;
|
|
|
|
/// <summary>
|
|
/// Gets the shader pipeline state object for NV12 frame decoding to RGBA.
|
|
/// </summary>
|
|
GPUPipelineState* GetDecodeNV12PS() const;
|
|
|
|
/// <summary>
|
|
/// Gets the fullscreen-triangle vertex buffer.
|
|
/// </summary>
|
|
GPUBuffer* GetFullscreenTriangleVB() const;
|
|
|
|
public:
|
|
/// <summary>
|
|
/// Init device resources
|
|
/// </summary>
|
|
/// <returns>True if cannot init, otherwise false.</returns>
|
|
virtual bool Init();
|
|
|
|
/// <summary>
|
|
/// Load private device content (called when Content Pool is created)
|
|
/// </summary>
|
|
/// <returns>True if cannot load data in a proper way, otherwise false.</returns>
|
|
virtual bool LoadContent();
|
|
|
|
/// <summary>
|
|
/// Checks if GPU can render frame now (all data is ready), otherwise will skip frame rendering.
|
|
/// </summary>
|
|
/// <returns>True if skip rendering, otherwise false.</returns>
|
|
virtual bool CanDraw();
|
|
|
|
/// <summary>
|
|
/// Call frame rendering and process data using GPU
|
|
/// </summary>
|
|
virtual void Draw();
|
|
|
|
/// <summary>
|
|
/// Clean all allocated data by device
|
|
/// </summary>
|
|
virtual void Dispose();
|
|
|
|
/// <summary>
|
|
/// Wait for GPU end doing submitted work
|
|
/// </summary>
|
|
virtual void WaitForGPU() = 0;
|
|
|
|
/// <summary>
|
|
/// Reads the query result from the GPU. Timer queries return time in microseconds (1/1000 ms).
|
|
/// </summary>
|
|
/// <remarks>GPU query results are short-lived, meaning that in the frame that results are ready, they won't be available in the next frame, as queries are reused.</remarks>
|
|
/// <param name="queryID">Query identifier returned by GPUContext::BeginQuery.</param>
|
|
/// <param name="result">The output result data of the query. Valid only when function returns true.</param>
|
|
/// <param name="wait">True if wait for the GPU to end processing commands for sync data ready. Otherwise, if query is incomplete then function will return value of false without result.</param>
|
|
/// <returns>True if got valid query result, otherwise false. If called with wait enabled then device failed to readback the query data.</returns>
|
|
virtual bool GetQueryResult(uint64 queryID, uint64& result, bool wait = false) = 0;
|
|
|
|
public:
|
|
void AddResource(GPUResource* resource);
|
|
void RemoveResource(GPUResource* resource);
|
|
|
|
/// <summary>
|
|
/// Dumps all GPU resources information to the log.
|
|
/// </summary>
|
|
void DumpResourcesToLog() const;
|
|
|
|
/// <summary>
|
|
/// Dumps all GPU resources information to the log.
|
|
/// </summary>
|
|
API_FUNCTION(Attributes="DebugCommand") static void DumpResources();
|
|
|
|
protected:
|
|
virtual void preDispose();
|
|
|
|
/// <summary>
|
|
/// Called during Draw method before any frame rendering initialization. Cannot be used to submit commands to GPU.
|
|
/// </summary>
|
|
virtual void DrawBegin();
|
|
|
|
/// <summary>
|
|
/// Called during Draw method after rendering. Cannot be used to submit commands to GPU.
|
|
/// </summary>
|
|
virtual void DrawEnd();
|
|
|
|
/// <summary>
|
|
/// Called during Draw method after rendering begin. Can be used to submit commands to the GPU after opening GPU command list.
|
|
/// </summary>
|
|
virtual void RenderBegin();
|
|
|
|
/// <summary>
|
|
/// Called during Draw method before rendering end. Can be used to submit commands to the GPU before closing GPU command list.
|
|
/// </summary>
|
|
virtual void RenderEnd();
|
|
|
|
/// <summary>
|
|
/// Called when program crashed due to GPU error (out of memory, hang, error - see Engine::FatalError). By default, it logs all GPU resources to the log. Can be used to update platform-specific stats or extract crash-info.
|
|
/// </summary>
|
|
virtual void OnCrash();
|
|
|
|
public:
|
|
/// <summary>
|
|
/// Creates the texture.
|
|
/// </summary>
|
|
/// <param name="name">The resource name.</param>
|
|
/// <returns>The texture.</returns>
|
|
API_FUNCTION() virtual GPUTexture* CreateTexture(const StringView& name = StringView::Empty) = 0;
|
|
|
|
/// <summary>
|
|
/// Creates the shader.
|
|
/// </summary>
|
|
/// <param name="name">The resource name.</param>
|
|
/// <returns>The shader.</returns>
|
|
virtual GPUShader* CreateShader(const StringView& name = StringView::Empty) = 0;
|
|
|
|
/// <summary>
|
|
/// Creates the GPU pipeline state object.
|
|
/// </summary>
|
|
/// <returns>The pipeline state.</returns>
|
|
virtual GPUPipelineState* CreatePipelineState() = 0;
|
|
|
|
/// <summary>
|
|
/// Creates the timer query object.
|
|
/// [Deprecated in v1.12]
|
|
/// </summary>
|
|
/// <returns>The timer query.</returns>
|
|
DEPRECATED("Use new BeginQuery/EndQuery on GPUContext to insert queries and GetQueryResult on GPUDevice to read the results.") virtual GPUTimerQuery* CreateTimerQuery() = 0;
|
|
|
|
/// <summary>
|
|
/// Creates the buffer.
|
|
/// </summary>
|
|
/// <param name="name">The resource name.</param>
|
|
/// <returns>The buffer.</returns>
|
|
API_FUNCTION() virtual GPUBuffer* CreateBuffer(const StringView& name = StringView::Empty) = 0;
|
|
|
|
/// <summary>
|
|
/// Creates the texture sampler.
|
|
/// </summary>
|
|
/// <returns>The sampler.</returns>
|
|
API_FUNCTION() virtual GPUSampler* CreateSampler() = 0;
|
|
|
|
/// <summary>
|
|
/// Creates the vertex buffer layout.
|
|
/// </summary>
|
|
/// <returns>The vertex buffer layout.</returns>
|
|
API_FUNCTION() virtual GPUVertexLayout* CreateVertexLayout(const Array<struct VertexElement, FixedAllocation<GPU_MAX_VS_ELEMENTS>>& elements, bool explicitOffsets = false) = 0;
|
|
typedef Array<VertexElement, FixedAllocation<GPU_MAX_VS_ELEMENTS>> VertexElements;
|
|
|
|
/// <summary>
|
|
/// Creates the native window swap chain.
|
|
/// </summary>
|
|
/// <param name="window">The output window.</param>
|
|
/// <returns>The native window swap chain.</returns>
|
|
virtual GPUSwapChain* CreateSwapChain(Window* window) = 0;
|
|
|
|
/// <summary>
|
|
/// Creates the constant buffer.
|
|
/// </summary>
|
|
/// <param name="name">The resource name.</param>
|
|
/// <param name="size">The buffer size (in bytes).</param>
|
|
/// <returns>The constant buffer.</returns>
|
|
virtual GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name = StringView::Empty) = 0;
|
|
|
|
/// <summary>
|
|
/// Creates the GPU tasks context.
|
|
/// </summary>
|
|
/// <returns>The GPU tasks context.</returns>
|
|
virtual GPUTasksContext* CreateTasksContext();
|
|
|
|
/// <summary>
|
|
/// Creates the GPU tasks executor.
|
|
/// </summary>
|
|
/// <returns>The GPU tasks executor.</returns>
|
|
virtual GPUTasksExecutor* CreateTasksExecutor();
|
|
|
|
private:
|
|
// Internal bindings
|
|
#if !COMPILE_WITHOUT_CSHARP
|
|
API_FUNCTION(NoProxy) void* GetResourcesInternal();
|
|
#endif
|
|
};
|
|
|
|
/// <summary>
|
|
/// Utility structure to safety graphics device locking.
|
|
/// </summary>
|
|
struct FLAXENGINE_API GPUDeviceLock : NonCopyable
|
|
{
|
|
const GPUDevice* Device;
|
|
|
|
GPUDeviceLock(const GPUDevice* device)
|
|
: Device(device)
|
|
{
|
|
Device->Locker.Lock();
|
|
}
|
|
|
|
~GPUDeviceLock()
|
|
{
|
|
Device->Locker.Unlock();
|
|
}
|
|
};
|
|
|
|
// Utility to get GPU resource name (StringView) from the AssetInfo. Supports cooked builds with enabled debug resource naming that resolves original file path from the project to boost debugging experience.
|
|
#if GPU_ENABLE_RESOURCE_NAMING && !USE_EDITOR
|
|
#define GPU_GET_RESOURCE_NAME_FROM_ASSET(assetInfo) Content::GetRegistry()->GetEditorAssetPath(info->ID)
|
|
#else
|
|
#define GPU_GET_RESOURCE_NAME_FROM_ASSET(assetInfo) info->Path
|
|
#endif
|