Add improved GPU crashes reporting
This commit is contained in:
@@ -604,7 +604,7 @@ namespace Math
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
static T AlignUpWithMask(T value, T mask)
|
static T AlignUpWithMask(T value, T mask)
|
||||||
{
|
{
|
||||||
return (T)(value + mask & ~mask);
|
return (T)((value + mask) & ~mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -623,7 +623,7 @@ namespace Math
|
|||||||
static T AlignUp(T value, T alignment)
|
static T AlignUp(T value, T alignment)
|
||||||
{
|
{
|
||||||
T mask = alignment - 1;
|
T mask = alignment - 1;
|
||||||
return (T)(value + mask & ~mask);
|
return (T)((value + mask) & ~mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -648,7 +648,7 @@ namespace Math
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
static bool IsAligned(T value, T alignment)
|
static bool IsAligned(T value, T alignment)
|
||||||
{
|
{
|
||||||
return 0 == (value & alignment - 1);
|
return 0 == (value & (alignment - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "RenderTools.h"
|
#include "RenderTools.h"
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
#include "Shaders/GPUShader.h"
|
#include "Shaders/GPUShader.h"
|
||||||
|
#include "Shaders/GPUVertexLayout.h"
|
||||||
#include "Async/DefaultGPUTasksExecutor.h"
|
#include "Async/DefaultGPUTasksExecutor.h"
|
||||||
#include "Async/GPUTasksManager.h"
|
#include "Async/GPUTasksManager.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
@@ -26,8 +27,6 @@
|
|||||||
#include "Engine/Renderer/RenderList.h"
|
#include "Engine/Renderer/RenderList.h"
|
||||||
#include "Engine/Scripting/Enums.h"
|
#include "Engine/Scripting/Enums.h"
|
||||||
|
|
||||||
#include "Shaders/GPUVertexLayout.h"
|
|
||||||
|
|
||||||
GPUResourcePropertyBase::~GPUResourcePropertyBase()
|
GPUResourcePropertyBase::~GPUResourcePropertyBase()
|
||||||
{
|
{
|
||||||
const auto e = _resource;
|
const auto e = _resource;
|
||||||
@@ -311,6 +310,16 @@ struct GPUDevice::PrivateData
|
|||||||
|
|
||||||
GPUDevice* GPUDevice::Instance = nullptr;
|
GPUDevice* GPUDevice::Instance = nullptr;
|
||||||
|
|
||||||
|
void GPUDevice::OnRequestingExit()
|
||||||
|
{
|
||||||
|
if (Engine::FatalError != FatalErrorType::GPUCrash &&
|
||||||
|
Engine::FatalError != FatalErrorType::GPUHang &&
|
||||||
|
Engine::FatalError != FatalErrorType::GPUOutOfMemory)
|
||||||
|
return;
|
||||||
|
// TODO: get and log actual GPU memory used by the engine (API-specific)
|
||||||
|
DumpResourcesToLog();
|
||||||
|
}
|
||||||
|
|
||||||
GPUDevice::GPUDevice(RendererType type, ShaderProfile profile)
|
GPUDevice::GPUDevice(RendererType type, ShaderProfile profile)
|
||||||
: ScriptingObject(SpawnParams(Guid::New(), TypeInitializer))
|
: ScriptingObject(SpawnParams(Guid::New(), TypeInitializer))
|
||||||
, _state(DeviceState::Missing)
|
, _state(DeviceState::Missing)
|
||||||
@@ -354,6 +363,7 @@ bool GPUDevice::Init()
|
|||||||
LOG(Info, "Total graphics memory: {0}", Utilities::BytesToText(TotalGraphicsMemory));
|
LOG(Info, "Total graphics memory: {0}", Utilities::BytesToText(TotalGraphicsMemory));
|
||||||
if (!Limits.HasCompute)
|
if (!Limits.HasCompute)
|
||||||
LOG(Warning, "Compute Shaders are not supported");
|
LOG(Warning, "Compute Shaders are not supported");
|
||||||
|
Engine::RequestingExit.Bind<GPUDevice, &GPUDevice::OnRequestingExit>(this);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,9 +460,23 @@ void GPUDevice::DumpResourcesToLog() const
|
|||||||
output.AppendLine();
|
output.AppendLine();
|
||||||
output.AppendLine();
|
output.AppendLine();
|
||||||
|
|
||||||
|
const bool printTypes[(int32)GPUResourceType::MAX] =
|
||||||
|
{
|
||||||
|
true, // RenderTarget
|
||||||
|
true, // Texture
|
||||||
|
true, // CubeTexture
|
||||||
|
true, // VolumeTexture
|
||||||
|
true, // Buffer
|
||||||
|
true, // Shader
|
||||||
|
false, // PipelineState
|
||||||
|
false, // Descriptor
|
||||||
|
false, // Query
|
||||||
|
false, // Sampler
|
||||||
|
};
|
||||||
for (int32 typeIndex = 0; typeIndex < (int32)GPUResourceType::MAX; typeIndex++)
|
for (int32 typeIndex = 0; typeIndex < (int32)GPUResourceType::MAX; typeIndex++)
|
||||||
{
|
{
|
||||||
const auto type = static_cast<GPUResourceType>(typeIndex);
|
const auto type = static_cast<GPUResourceType>(typeIndex);
|
||||||
|
const auto printType = printTypes[typeIndex];
|
||||||
|
|
||||||
output.AppendFormat(TEXT("Group: {0}s"), ScriptingEnum::ToString(type));
|
output.AppendFormat(TEXT("Group: {0}s"), ScriptingEnum::ToString(type));
|
||||||
output.AppendLine();
|
output.AppendLine();
|
||||||
@@ -462,12 +486,12 @@ void GPUDevice::DumpResourcesToLog() const
|
|||||||
for (int32 i = 0; i < _resources.Count(); i++)
|
for (int32 i = 0; i < _resources.Count(); i++)
|
||||||
{
|
{
|
||||||
const GPUResource* resource = _resources[i];
|
const GPUResource* resource = _resources[i];
|
||||||
if (resource->GetResourceType() == type)
|
if (resource->GetResourceType() == type && resource->GetMemoryUsage() != 0)
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
memUsage += resource->GetMemoryUsage();
|
memUsage += resource->GetMemoryUsage();
|
||||||
auto str = resource->ToString();
|
auto str = resource->ToString();
|
||||||
if (str.HasChars())
|
if (str.HasChars() && printType)
|
||||||
{
|
{
|
||||||
output.Append(TEXT('\t'));
|
output.Append(TEXT('\t'));
|
||||||
output.Append(str);
|
output.Append(str);
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ protected:
|
|||||||
Array<GPUResource*> _resources;
|
Array<GPUResource*> _resources;
|
||||||
CriticalSection _resourcesLock;
|
CriticalSection _resourcesLock;
|
||||||
|
|
||||||
|
void OnRequestingExit();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="GPUDevice"/> class.
|
/// Initializes a new instance of the <see cref="GPUDevice"/> class.
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ DXGI_FORMAT RenderToolsDX::ToDxgiFormat(PixelFormat format)
|
|||||||
return PixelFormatToDXGIFormat[(int32)format];
|
return PixelFormatToDXGIFormat[(int32)format];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Char* RenderToolsDX::GetFeatureLevelString(const D3D_FEATURE_LEVEL featureLevel)
|
const Char* RenderToolsDX::GetFeatureLevelString(D3D_FEATURE_LEVEL featureLevel)
|
||||||
{
|
{
|
||||||
switch (featureLevel)
|
switch (featureLevel)
|
||||||
{
|
{
|
||||||
@@ -159,11 +159,24 @@ const Char* RenderToolsDX::GetFeatureLevelString(const D3D_FEATURE_LEVEL feature
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String RenderToolsDX::GetD3DErrorString(HRESULT errorCode)
|
uint32 RenderToolsDX::CountAdapterOutputs(IDXGIAdapter* adapter)
|
||||||
{
|
{
|
||||||
StringBuilder sb(256);
|
uint32 count = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
IDXGIOutput* output;
|
||||||
|
HRESULT hr = adapter->EnumOutputs(count, &output);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
// Switch error code
|
void FormatD3DErrorString(HRESULT errorCode, StringBuilder& sb, HRESULT& removedReason)
|
||||||
|
{
|
||||||
#define D3DERR(x) case x: sb.Append(TEXT(#x)); break
|
#define D3DERR(x) case x: sb.Append(TEXT(#x)); break
|
||||||
switch (errorCode)
|
switch (errorCode)
|
||||||
{
|
{
|
||||||
@@ -184,6 +197,8 @@ String RenderToolsDX::GetD3DErrorString(HRESULT errorCode)
|
|||||||
// DirectX 11
|
// DirectX 11
|
||||||
D3DERR(D3D11_ERROR_FILE_NOT_FOUND);
|
D3DERR(D3D11_ERROR_FILE_NOT_FOUND);
|
||||||
D3DERR(D3D11_ERROR_TOO_MANY_UNIQUE_STATE_OBJECTS);
|
D3DERR(D3D11_ERROR_TOO_MANY_UNIQUE_STATE_OBJECTS);
|
||||||
|
D3DERR(D3D11_ERROR_TOO_MANY_UNIQUE_VIEW_OBJECTS);
|
||||||
|
D3DERR(D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD);
|
||||||
|
|
||||||
// DirectX 12
|
// DirectX 12
|
||||||
//D3DERR(D3D12_ERROR_FILE_NOT_FOUND);
|
//D3DERR(D3D12_ERROR_FILE_NOT_FOUND);
|
||||||
@@ -221,22 +236,20 @@ String RenderToolsDX::GetD3DErrorString(HRESULT errorCode)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
|
||||||
sb.AppendFormat(TEXT("0x{0:x}"), static_cast<unsigned int>(errorCode));
|
sb.AppendFormat(TEXT("0x{0:x}"), static_cast<unsigned int>(errorCode));
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#undef D3DERR
|
#undef D3DERR
|
||||||
|
|
||||||
if (errorCode == DXGI_ERROR_DEVICE_REMOVED || errorCode == DXGI_ERROR_DEVICE_RESET || errorCode == DXGI_ERROR_DRIVER_INTERNAL_ERROR)
|
if (errorCode == DXGI_ERROR_DEVICE_REMOVED || errorCode == DXGI_ERROR_DEVICE_RESET || errorCode == DXGI_ERROR_DRIVER_INTERNAL_ERROR)
|
||||||
{
|
{
|
||||||
HRESULT reason = S_OK;
|
GPUDevice* device = GPUDevice::Instance;
|
||||||
const RendererType rendererType = GPUDevice::Instance ? GPUDevice::Instance->GetRendererType() : RendererType::Unknown;
|
const RendererType rendererType = device ? device->GetRendererType() : RendererType::Unknown;
|
||||||
void* nativePtr = GPUDevice::Instance ? GPUDevice::Instance->GetNativePtr() : nullptr;
|
void* nativePtr = device ? device->GetNativePtr() : nullptr;
|
||||||
#if GRAPHICS_API_DIRECTX12
|
#if GRAPHICS_API_DIRECTX12
|
||||||
if (rendererType == RendererType::DirectX12 && nativePtr)
|
if (rendererType == RendererType::DirectX12 && nativePtr)
|
||||||
{
|
{
|
||||||
reason = ((ID3D12Device*)nativePtr)->GetDeviceRemovedReason();
|
removedReason = ((ID3D12Device*)nativePtr)->GetDeviceRemovedReason();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if GRAPHICS_API_DIRECTX11
|
#if GRAPHICS_API_DIRECTX11
|
||||||
@@ -244,11 +257,11 @@ String RenderToolsDX::GetD3DErrorString(HRESULT errorCode)
|
|||||||
rendererType == RendererType::DirectX10_1 ||
|
rendererType == RendererType::DirectX10_1 ||
|
||||||
rendererType == RendererType::DirectX10) && nativePtr)
|
rendererType == RendererType::DirectX10) && nativePtr)
|
||||||
{
|
{
|
||||||
reason = ((ID3D11Device*)nativePtr)->GetDeviceRemovedReason();
|
removedReason = ((ID3D11Device*)nativePtr)->GetDeviceRemovedReason();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
const Char* reasonStr = nullptr;
|
const Char* reasonStr = nullptr;
|
||||||
switch (reason)
|
switch (removedReason)
|
||||||
{
|
{
|
||||||
case DXGI_ERROR_DEVICE_HUNG:
|
case DXGI_ERROR_DEVICE_HUNG:
|
||||||
reasonStr = TEXT("HUNG");
|
reasonStr = TEXT("HUNG");
|
||||||
@@ -269,8 +282,35 @@ String RenderToolsDX::GetD3DErrorString(HRESULT errorCode)
|
|||||||
if (reasonStr != nullptr)
|
if (reasonStr != nullptr)
|
||||||
sb.AppendFormat(TEXT(", Device Removed Reason: {0}"), reasonStr);
|
sb.AppendFormat(TEXT(", Device Removed Reason: {0}"), reasonStr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
void RenderToolsDX::LogD3DResult(HRESULT result, const char* file, uint32 line, bool fatal)
|
||||||
|
{
|
||||||
|
ASSERT_LOW_LAYER(FAILED(result));
|
||||||
|
|
||||||
|
// Process error and format message
|
||||||
|
StringBuilder sb;
|
||||||
|
HRESULT removedReason = S_OK;
|
||||||
|
sb.Append(TEXT("DirectX error: "));
|
||||||
|
FormatD3DErrorString(result, sb, removedReason);
|
||||||
|
if (file)
|
||||||
|
sb.Append(TEXT(" at ")).Append(file).Append(':').Append(line);
|
||||||
|
const StringView msg(sb.ToStringView());
|
||||||
|
|
||||||
|
// Handle error
|
||||||
|
FatalErrorType errorType = FatalErrorType::None;
|
||||||
|
if (result == E_OUTOFMEMORY)
|
||||||
|
errorType = FatalErrorType::GPUOutOfMemory;
|
||||||
|
else if (removedReason != S_OK)
|
||||||
|
{
|
||||||
|
errorType = FatalErrorType::GPUCrash;
|
||||||
|
if (removedReason == DXGI_ERROR_DEVICE_HUNG)
|
||||||
|
errorType = FatalErrorType::GPUHang;
|
||||||
|
}
|
||||||
|
if (errorType != FatalErrorType::None)
|
||||||
|
Platform::Fatal(msg, nullptr, errorType);
|
||||||
|
else
|
||||||
|
Log::Logger::Write(fatal ? LogType::Fatal : LogType::Error, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
LPCSTR RenderToolsDX::GetVertexInputSemantic(VertexElement::Types type, UINT& semanticIndex)
|
LPCSTR RenderToolsDX::GetVertexInputSemantic(VertexElement::Types type, UINT& semanticIndex)
|
||||||
|
|||||||
@@ -17,12 +17,6 @@
|
|||||||
namespace RenderToolsDX
|
namespace RenderToolsDX
|
||||||
{
|
{
|
||||||
#if GRAPHICS_API_DIRECTX11
|
#if GRAPHICS_API_DIRECTX11
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts Flax GPUResourceUsage to DirectX 11 resource D3D11_USAGE enum type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="usage">The Flax resource usage.</param>
|
|
||||||
/// <returns>The DirectX 11 resource usage.</returns>
|
|
||||||
inline D3D11_USAGE ToD3D11Usage(const GPUResourceUsage usage)
|
inline D3D11_USAGE ToD3D11Usage(const GPUResourceUsage usage)
|
||||||
{
|
{
|
||||||
switch (usage)
|
switch (usage)
|
||||||
@@ -37,11 +31,6 @@ namespace RenderToolsDX
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the cpu access flags from the resource usage.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="usage">The Flax resource usage.</param>
|
|
||||||
/// <returns>The DirectX 11 resource CPU usage.</returns>
|
|
||||||
inline UINT GetDX11CpuAccessFlagsFromUsage(const GPUResourceUsage usage)
|
inline UINT GetDX11CpuAccessFlagsFromUsage(const GPUResourceUsage usage)
|
||||||
{
|
{
|
||||||
switch (usage)
|
switch (usage)
|
||||||
@@ -56,82 +45,26 @@ namespace RenderToolsDX
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts Flax Pixel Format to the DXGI Format.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="format">The Flax Pixel Format.</param>
|
|
||||||
/// <returns>The DXGI Format</returns>
|
|
||||||
extern DXGI_FORMAT ToDxgiFormat(PixelFormat format);
|
|
||||||
|
|
||||||
// Aligns location to the next multiple of align value.
|
|
||||||
template<typename T>
|
|
||||||
T Align(T location, T align)
|
|
||||||
{
|
|
||||||
ASSERT(!((0 == align) || (align & (align - 1))));
|
|
||||||
return ((location + (align - 1)) & ~(align - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
extern const Char* GetFeatureLevelString(const D3D_FEATURE_LEVEL featureLevel);
|
|
||||||
|
|
||||||
// Calculate a subresource index for a texture
|
// Calculate a subresource index for a texture
|
||||||
FORCE_INLINE uint32 CalcSubresourceIndex(uint32 mipSlice, uint32 arraySlice, uint32 mipLevels)
|
FORCE_INLINE uint32 CalcSubresourceIndex(uint32 mipSlice, uint32 arraySlice, uint32 mipLevels)
|
||||||
{
|
{
|
||||||
return mipSlice + arraySlice * mipLevels;
|
return mipSlice + arraySlice * mipLevels;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32 CountAdapterOutputs(IDXGIAdapter* adapter)
|
DXGI_FORMAT ToDxgiFormat(PixelFormat format);
|
||||||
{
|
const Char* GetFeatureLevelString(D3D_FEATURE_LEVEL featureLevel);
|
||||||
uint32 count = 0;
|
uint32 CountAdapterOutputs(IDXGIAdapter* adapter);
|
||||||
while (true)
|
void LogD3DResult(HRESULT result, const char* file = nullptr, uint32 line = 0, bool fatal = false);
|
||||||
{
|
|
||||||
IDXGIOutput* output;
|
|
||||||
HRESULT hr = adapter->EnumOutputs(count, &output);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern String GetD3DErrorString(HRESULT errorCode);
|
|
||||||
|
|
||||||
inline void ValidateD3DResult(HRESULT result, const char* file = "", uint32 line = 0)
|
|
||||||
{
|
|
||||||
ASSERT(FAILED(result));
|
|
||||||
const String& errorString = GetD3DErrorString(result);
|
|
||||||
LOG(Fatal, "DirectX error: {0} at {1}:{2}", errorString, String(file), line);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void LogD3DResult(HRESULT result, const char* file = "", uint32 line = 0)
|
|
||||||
{
|
|
||||||
ASSERT(FAILED(result));
|
|
||||||
const String& errorString = GetD3DErrorString(result);
|
|
||||||
LOG(Error, "DirectX error: {0} at {1}:{2}", errorString, String(file), line);
|
|
||||||
}
|
|
||||||
|
|
||||||
LPCSTR GetVertexInputSemantic(VertexElement::Types type, UINT& semanticIndex);
|
LPCSTR GetVertexInputSemantic(VertexElement::Types type, UINT& semanticIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
#if GPU_ENABLE_ASSERTION
|
|
||||||
|
|
||||||
// DirectX results validation
|
// DirectX results validation
|
||||||
#define VALIDATE_DIRECTX_CALL(x) { HRESULT result = x; if (FAILED(result)) RenderToolsDX::ValidateD3DResult(result, __FILE__, __LINE__); }
|
#define VALIDATE_DIRECTX_CALL(x) { HRESULT result = x; if (FAILED(result)) RenderToolsDX::LogD3DResult(result, __FILE__, __LINE__, true); }
|
||||||
#define LOG_DIRECTX_RESULT(result) if (FAILED(result)) RenderToolsDX::LogD3DResult(result, __FILE__, __LINE__)
|
#define LOG_DIRECTX_RESULT(result) if (FAILED(result)) RenderToolsDX::LogD3DResult(result, __FILE__, __LINE__)
|
||||||
#define LOG_DIRECTX_RESULT_WITH_RETURN(result, returnValue) if (FAILED(result)) { RenderToolsDX::LogD3DResult(result, __FILE__, __LINE__); return returnValue; }
|
#define LOG_DIRECTX_RESULT_WITH_RETURN(result, returnValue) if (FAILED(result)) { RenderToolsDX::LogD3DResult(result, __FILE__, __LINE__); return returnValue; }
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define VALIDATE_DIRECTX_CALL(x) x
|
|
||||||
#define LOG_DIRECTX_RESULT(result) if(FAILED(result)) RenderToolsDX::LogD3DResult(result)
|
|
||||||
#define LOG_DIRECTX_RESULT_WITH_RETURN(result, returnValue) if(FAILED(result)) { RenderToolsDX::LogD3DResult(result); return returnValue; }
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if GPU_ENABLE_DIAGNOSTICS || COMPILE_WITH_SHADER_COMPILER || GPU_ENABLE_RESOURCE_NAMING
|
#if GPU_ENABLE_DIAGNOSTICS || COMPILE_WITH_SHADER_COMPILER || GPU_ENABLE_RESOURCE_NAMING
|
||||||
|
|
||||||
#include "Engine/Utilities/StringConverter.h"
|
#include "Engine/Utilities/StringConverter.h"
|
||||||
@@ -165,15 +98,15 @@ inline void SetDebugObjectName(IDXGIObject* resource, const char (&name)[NameLen
|
|||||||
#if GRAPHICS_API_DIRECTX11
|
#if GRAPHICS_API_DIRECTX11
|
||||||
|
|
||||||
template<uint32 NameLength>
|
template<uint32 NameLength>
|
||||||
inline void SetDebugObjectName(ID3D10DeviceChild* resource, const char(&name)[NameLength])
|
inline void SetDebugObjectName(ID3D10DeviceChild* resource, const char (&name)[NameLength])
|
||||||
{
|
{
|
||||||
SetDebugObjectName(resource, name, NameLength - 1);
|
SetDebugObjectName(resource, name, NameLength - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint32 NameLength>
|
template<uint32 NameLength>
|
||||||
inline void SetDebugObjectName(ID3D11DeviceChild* resource, const char(&name)[NameLength])
|
inline void SetDebugObjectName(ID3D11DeviceChild* resource, const char (&name)[NameLength])
|
||||||
{
|
{
|
||||||
SetDebugObjectName(resource, name, NameLength - 1);
|
SetDebugObjectName(resource, name, NameLength - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -196,15 +129,15 @@ inline void SetDebugObjectName(ID3D12DeviceChild* resource, const char (&name)[N
|
|||||||
#if GRAPHICS_API_DIRECTX11
|
#if GRAPHICS_API_DIRECTX11
|
||||||
|
|
||||||
template<uint32 NameLength>
|
template<uint32 NameLength>
|
||||||
inline void SetDebugObjectName(ID3D10Resource* resource, const char(&name)[NameLength])
|
inline void SetDebugObjectName(ID3D10Resource* resource, const char (&name)[NameLength])
|
||||||
{
|
{
|
||||||
resource->SetPrivateData(WKPDID_D3DDebugObjectName, NameLength - 1, name);
|
resource->SetPrivateData(WKPDID_D3DDebugObjectName, NameLength - 1, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint32 NameLength>
|
template<uint32 NameLength>
|
||||||
inline void SetDebugObjectName(ID3D11Resource* resource, const char(&name)[NameLength])
|
inline void SetDebugObjectName(ID3D11Resource* resource, const char (&name)[NameLength])
|
||||||
{
|
{
|
||||||
resource->SetPrivateData(WKPDID_D3DDebugObjectName, NameLength - 1, name);
|
resource->SetPrivateData(WKPDID_D3DDebugObjectName, NameLength - 1, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -241,7 +174,7 @@ inline void SetDebugObjectName(T* resource, const Char* data, UINT size)
|
|||||||
#else
|
#else
|
||||||
char* ansi = (char*)Allocator::Allocate(size + 1);
|
char* ansi = (char*)Allocator::Allocate(size + 1);
|
||||||
StringUtils::ConvertUTF162ANSI(data, ansi, size);
|
StringUtils::ConvertUTF162ANSI(data, ansi, size);
|
||||||
ansi[size] ='\0';
|
ansi[size] = '\0';
|
||||||
SetDebugObjectName(resource, ansi, size);
|
SetDebugObjectName(resource, ansi, size);
|
||||||
Allocator::Free(ansi);
|
Allocator::Free(ansi);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ void RenderToolsVulkan::SetObjectName(VkDevice device, uint64 objectHandle, VkOb
|
|||||||
|
|
||||||
String RenderToolsVulkan::GetVkErrorString(VkResult result)
|
String RenderToolsVulkan::GetVkErrorString(VkResult result)
|
||||||
{
|
{
|
||||||
StringBuilder sb(256);
|
StringBuilder sb(64);
|
||||||
|
|
||||||
// Switch error code
|
// Switch error code
|
||||||
switch (result)
|
switch (result)
|
||||||
@@ -228,33 +228,30 @@ String RenderToolsVulkan::GetVkErrorString(VkResult result)
|
|||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderToolsVulkan::ValidateVkResult(VkResult result, const char* file, uint32 line)
|
void RenderToolsVulkan::LogVkResult(VkResult result, const char* file, uint32 line, bool fatal)
|
||||||
{
|
{
|
||||||
// Ensure result if invalid
|
|
||||||
ASSERT(result != VK_SUCCESS);
|
ASSERT(result != VK_SUCCESS);
|
||||||
|
|
||||||
// Get error string
|
// Process error and format message
|
||||||
const String& errorString = GetVkErrorString(result);
|
StringBuilder sb;
|
||||||
|
sb.Append(TEXT("Vulkan error: "));
|
||||||
|
sb.Append(GetVkErrorString(result));
|
||||||
|
if (file)
|
||||||
|
sb.Append(TEXT(" at ")).Append(file).Append(':').Append(line);
|
||||||
|
const StringView msg(sb.ToStringView());
|
||||||
|
|
||||||
// Send error
|
// Handle error
|
||||||
LOG(Fatal, "Vulkan error: {0} at {1}:{2}", errorString, String(file), line);
|
FatalErrorType errorType = FatalErrorType::None;
|
||||||
}
|
if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_ERROR_OUT_OF_DEVICE_MEMORY || result == VK_ERROR_OUT_OF_POOL_MEMORY)
|
||||||
|
errorType = FatalErrorType::GPUOutOfMemory;
|
||||||
void RenderToolsVulkan::LogVkResult(VkResult result, const char* file, uint32 line)
|
else if (result == VK_TIMEOUT)
|
||||||
{
|
errorType = FatalErrorType::GPUHang;
|
||||||
// Ensure result if invalid
|
else if (result == VK_ERROR_DEVICE_LOST || result == VK_ERROR_SURFACE_LOST_KHR || result == VK_ERROR_MEMORY_MAP_FAILED)
|
||||||
ASSERT(result != VK_SUCCESS);
|
errorType = FatalErrorType::GPUCrash;
|
||||||
|
if (errorType != FatalErrorType::None)
|
||||||
// Get error string
|
Platform::Fatal(msg, nullptr, errorType);
|
||||||
const String& errorString = GetVkErrorString(result);
|
else
|
||||||
|
Log::Logger::Write(fatal ? LogType::Fatal : LogType::Error, msg);
|
||||||
// Send error
|
|
||||||
LOG(Error, "Vulkan error: {0} at {1}:{2}", errorString, String(file), line);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderToolsVulkan::LogVkResult(VkResult result)
|
|
||||||
{
|
|
||||||
LogVkResult(result, "", 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderToolsVulkan::HasExtension(const Array<const char*>& extensions, const char* name)
|
bool RenderToolsVulkan::HasExtension(const Array<const char*>& extensions, const char* name)
|
||||||
|
|||||||
@@ -11,21 +11,13 @@
|
|||||||
|
|
||||||
#if GRAPHICS_API_VULKAN
|
#if GRAPHICS_API_VULKAN
|
||||||
|
|
||||||
#if GPU_ENABLE_ASSERTION
|
#define VALIDATE_VULKAN_RESULT(x) { VkResult result = x; if (result != VK_SUCCESS) RenderToolsVulkan::LogVkResult(result, __FILE__, __LINE__, true); }
|
||||||
|
|
||||||
// Vulkan results validation
|
|
||||||
#define VALIDATE_VULKAN_RESULT(x) { VkResult result = x; if (result != VK_SUCCESS) RenderToolsVulkan::ValidateVkResult(result, __FILE__, __LINE__); }
|
|
||||||
#define LOG_VULKAN_RESULT(result) if (result != VK_SUCCESS) RenderToolsVulkan::LogVkResult(result, __FILE__, __LINE__)
|
#define LOG_VULKAN_RESULT(result) if (result != VK_SUCCESS) RenderToolsVulkan::LogVkResult(result, __FILE__, __LINE__)
|
||||||
#define LOG_VULKAN_RESULT_WITH_RETURN(result) if (result != VK_SUCCESS) { RenderToolsVulkan::LogVkResult(result, __FILE__, __LINE__); return true; }
|
#define LOG_VULKAN_RESULT_WITH_RETURN(result) if (result != VK_SUCCESS) { RenderToolsVulkan::LogVkResult(result, __FILE__, __LINE__); return true; }
|
||||||
|
#if GPU_ENABLE_ASSERTION
|
||||||
#define VK_SET_DEBUG_NAME(device, handle, type, name) RenderToolsVulkan::SetObjectName(device->Device, (uint64)handle, type, name)
|
#define VK_SET_DEBUG_NAME(device, handle, type, name) RenderToolsVulkan::SetObjectName(device->Device, (uint64)handle, type, name)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define VALIDATE_VULKAN_RESULT(x) x
|
|
||||||
#define LOG_VULKAN_RESULT(result) if (result != VK_SUCCESS) RenderToolsVulkan::LogVkResult(result)
|
|
||||||
#define LOG_VULKAN_RESULT_WITH_RETURN(result) if (result != VK_SUCCESS) { RenderToolsVulkan::LogVkResult(result); return true; }
|
|
||||||
#define VK_SET_DEBUG_NAME(device, handle, type, name)
|
#define VK_SET_DEBUG_NAME(device, handle, type, name)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -46,9 +38,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static String GetVkErrorString(VkResult result);
|
static String GetVkErrorString(VkResult result);
|
||||||
static void ValidateVkResult(VkResult result, const char* file, uint32 line);
|
static void LogVkResult(VkResult result, const char* file = nullptr, uint32 line = 0, bool fatal = false);
|
||||||
static void LogVkResult(VkResult result, const char* file, uint32 line);
|
|
||||||
static void LogVkResult(VkResult result);
|
|
||||||
|
|
||||||
static inline VkPipelineStageFlags GetBufferBarrierFlags(VkAccessFlags accessFlags)
|
static inline VkPipelineStageFlags GetBufferBarrierFlags(VkAccessFlags accessFlags)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -348,8 +348,8 @@ void PlatformBase::Fatal(const StringView& msg, void* context, FatalErrorType er
|
|||||||
LOG(Error, "Used Physical Memory: {0} ({1}%)", Utilities::BytesToText(memoryStats.UsedPhysicalMemory), (int32)(100 * memoryStats.UsedPhysicalMemory / memoryStats.TotalPhysicalMemory));
|
LOG(Error, "Used Physical Memory: {0} ({1}%)", Utilities::BytesToText(memoryStats.UsedPhysicalMemory), (int32)(100 * memoryStats.UsedPhysicalMemory / memoryStats.TotalPhysicalMemory));
|
||||||
LOG(Error, "Used Virtual Memory: {0} ({1}%)", Utilities::BytesToText(memoryStats.UsedVirtualMemory), (int32)(100 * memoryStats.UsedVirtualMemory / memoryStats.TotalVirtualMemory));
|
LOG(Error, "Used Virtual Memory: {0} ({1}%)", Utilities::BytesToText(memoryStats.UsedVirtualMemory), (int32)(100 * memoryStats.UsedVirtualMemory / memoryStats.TotalVirtualMemory));
|
||||||
const ProcessMemoryStats processMemoryStats = Platform::GetProcessMemoryStats();
|
const ProcessMemoryStats processMemoryStats = Platform::GetProcessMemoryStats();
|
||||||
LOG(Error, "Process Used Physical Memory: {0}", Utilities::BytesToText(processMemoryStats.UsedPhysicalMemory));
|
LOG(Error, "Process Used Physical Memory: {0} ({1}%)", Utilities::BytesToText(processMemoryStats.UsedPhysicalMemory), (int32)(100 * processMemoryStats.UsedPhysicalMemory / memoryStats.TotalPhysicalMemory));
|
||||||
LOG(Error, "Process Used Virtual Memory: {0}", Utilities::BytesToText(processMemoryStats.UsedVirtualMemory));
|
LOG(Error, "Process Used Virtual Memory: {0} ({1}%)", Utilities::BytesToText(processMemoryStats.UsedVirtualMemory), (int32)(100 * processMemoryStats.UsedVirtualMemory / memoryStats.TotalVirtualMemory));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Log::Logger::LogFilePath.HasChars())
|
if (Log::Logger::LogFilePath.HasChars())
|
||||||
|
|||||||
@@ -140,6 +140,12 @@ API_ENUM() enum class FatalErrorType
|
|||||||
Assertion,
|
Assertion,
|
||||||
// Program run out of memory to allocate.
|
// Program run out of memory to allocate.
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
|
// The graphics device crashed, has been removed or restarted.
|
||||||
|
GPUCrash,
|
||||||
|
// The graphics device stopped responding (eg. incorrect rendering code or bug in driver).
|
||||||
|
GPUHang,
|
||||||
|
// The graphics device run out of video memory to allocate.
|
||||||
|
GPUOutOfMemory,
|
||||||
};
|
};
|
||||||
|
|
||||||
API_INJECT_CODE(cpp, "#include \"Engine/Platform/Platform.h\"");
|
API_INJECT_CODE(cpp, "#include \"Engine/Platform/Platform.h\"");
|
||||||
|
|||||||
Reference in New Issue
Block a user