Add improved GPU crashes reporting
This commit is contained in:
@@ -130,7 +130,7 @@ DXGI_FORMAT RenderToolsDX::ToDxgiFormat(PixelFormat format)
|
||||
return PixelFormatToDXGIFormat[(int32)format];
|
||||
}
|
||||
|
||||
const Char* RenderToolsDX::GetFeatureLevelString(const D3D_FEATURE_LEVEL featureLevel)
|
||||
const Char* RenderToolsDX::GetFeatureLevelString(D3D_FEATURE_LEVEL 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
|
||||
switch (errorCode)
|
||||
{
|
||||
@@ -184,6 +197,8 @@ String RenderToolsDX::GetD3DErrorString(HRESULT errorCode)
|
||||
// DirectX 11
|
||||
D3DERR(D3D11_ERROR_FILE_NOT_FOUND);
|
||||
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
|
||||
//D3DERR(D3D12_ERROR_FILE_NOT_FOUND);
|
||||
@@ -221,22 +236,20 @@ String RenderToolsDX::GetD3DErrorString(HRESULT errorCode)
|
||||
#endif
|
||||
|
||||
default:
|
||||
{
|
||||
sb.AppendFormat(TEXT("0x{0:x}"), static_cast<unsigned int>(errorCode));
|
||||
}
|
||||
break;
|
||||
}
|
||||
#undef D3DERR
|
||||
|
||||
if (errorCode == DXGI_ERROR_DEVICE_REMOVED || errorCode == DXGI_ERROR_DEVICE_RESET || errorCode == DXGI_ERROR_DRIVER_INTERNAL_ERROR)
|
||||
{
|
||||
HRESULT reason = S_OK;
|
||||
const RendererType rendererType = GPUDevice::Instance ? GPUDevice::Instance->GetRendererType() : RendererType::Unknown;
|
||||
void* nativePtr = GPUDevice::Instance ? GPUDevice::Instance->GetNativePtr() : nullptr;
|
||||
GPUDevice* device = GPUDevice::Instance;
|
||||
const RendererType rendererType = device ? device->GetRendererType() : RendererType::Unknown;
|
||||
void* nativePtr = device ? device->GetNativePtr() : nullptr;
|
||||
#if GRAPHICS_API_DIRECTX12
|
||||
if (rendererType == RendererType::DirectX12 && nativePtr)
|
||||
{
|
||||
reason = ((ID3D12Device*)nativePtr)->GetDeviceRemovedReason();
|
||||
removedReason = ((ID3D12Device*)nativePtr)->GetDeviceRemovedReason();
|
||||
}
|
||||
#endif
|
||||
#if GRAPHICS_API_DIRECTX11
|
||||
@@ -244,11 +257,11 @@ String RenderToolsDX::GetD3DErrorString(HRESULT errorCode)
|
||||
rendererType == RendererType::DirectX10_1 ||
|
||||
rendererType == RendererType::DirectX10) && nativePtr)
|
||||
{
|
||||
reason = ((ID3D11Device*)nativePtr)->GetDeviceRemovedReason();
|
||||
removedReason = ((ID3D11Device*)nativePtr)->GetDeviceRemovedReason();
|
||||
}
|
||||
#endif
|
||||
const Char* reasonStr = nullptr;
|
||||
switch (reason)
|
||||
switch (removedReason)
|
||||
{
|
||||
case DXGI_ERROR_DEVICE_HUNG:
|
||||
reasonStr = TEXT("HUNG");
|
||||
@@ -269,8 +282,35 @@ String RenderToolsDX::GetD3DErrorString(HRESULT errorCode)
|
||||
if (reasonStr != nullptr)
|
||||
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)
|
||||
|
||||
@@ -17,12 +17,6 @@
|
||||
namespace RenderToolsDX
|
||||
{
|
||||
#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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
switch (usage)
|
||||
@@ -56,82 +45,26 @@ namespace RenderToolsDX
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
FORCE_INLINE uint32 CalcSubresourceIndex(uint32 mipSlice, uint32 arraySlice, uint32 mipLevels)
|
||||
{
|
||||
return mipSlice + arraySlice * mipLevels;
|
||||
}
|
||||
|
||||
inline uint32 CountAdapterOutputs(IDXGIAdapter* adapter)
|
||||
{
|
||||
uint32 count = 0;
|
||||
while (true)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
DXGI_FORMAT ToDxgiFormat(PixelFormat format);
|
||||
const Char* GetFeatureLevelString(D3D_FEATURE_LEVEL featureLevel);
|
||||
uint32 CountAdapterOutputs(IDXGIAdapter* adapter);
|
||||
void LogD3DResult(HRESULT result, const char* file = nullptr, uint32 line = 0, bool fatal = false);
|
||||
LPCSTR GetVertexInputSemantic(VertexElement::Types type, UINT& semanticIndex);
|
||||
};
|
||||
|
||||
#if GPU_ENABLE_ASSERTION
|
||||
|
||||
// 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_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
|
||||
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
@@ -165,15 +98,15 @@ inline void SetDebugObjectName(IDXGIObject* resource, const char (&name)[NameLen
|
||||
#if GRAPHICS_API_DIRECTX11
|
||||
|
||||
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>
|
||||
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
|
||||
@@ -196,15 +129,15 @@ inline void SetDebugObjectName(ID3D12DeviceChild* resource, const char (&name)[N
|
||||
#if GRAPHICS_API_DIRECTX11
|
||||
|
||||
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>
|
||||
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
|
||||
@@ -241,7 +174,7 @@ inline void SetDebugObjectName(T* resource, const Char* data, UINT size)
|
||||
#else
|
||||
char* ansi = (char*)Allocator::Allocate(size + 1);
|
||||
StringUtils::ConvertUTF162ANSI(data, ansi, size);
|
||||
ansi[size] ='\0';
|
||||
ansi[size] = '\0';
|
||||
SetDebugObjectName(resource, ansi, size);
|
||||
Allocator::Free(ansi);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user