diff --git a/Source/Engine/Graphics/GPUAdapter.h b/Source/Engine/Graphics/GPUAdapter.h
index af235a085..f845d7e7f 100644
--- a/Source/Engine/Graphics/GPUAdapter.h
+++ b/Source/Engine/Graphics/GPUAdapter.h
@@ -2,6 +2,7 @@
#pragma once
+#include "Engine/Core/Types/Version.h"
#include "Engine/Scripting/ScriptingObject.h"
// GPU vendors IDs
@@ -56,6 +57,11 @@ public:
///
API_PROPERTY() virtual String GetDescription() const = 0;
+ ///
+ /// Gets the GPU driver version.
+ ///
+ API_PROPERTY() virtual Version GetDriverVersion() const = 0;
+
public:
// Returns true if adapter's vendor is AMD.
API_PROPERTY() FORCE_INLINE bool IsAMD() const
diff --git a/Source/Engine/Graphics/Graphics.cpp b/Source/Engine/Graphics/Graphics.cpp
index b4fbefb7a..c189b6e50 100644
--- a/Source/Engine/Graphics/Graphics.cpp
+++ b/Source/Engine/Graphics/Graphics.cpp
@@ -182,12 +182,12 @@ bool GraphicsService::Init()
return true;
}
GPUDevice::Instance = device;
- LOG(Info,
- "Graphics Device created! Adapter: \'{0}\', Renderer: {1}, Shader Profile: {2}, Feature Level: {3}",
- device->GetAdapter()->GetDescription(),
+ LOG(Info, "GPU Device created: {}", device->GetAdapter()->GetDescription());
+ LOG(Info, "Renderer: {}, Shader Profile: {}, Feature Level: {}, Driver: {}",
::ToString(device->GetRendererType()),
::ToString(device->GetShaderProfile()),
- ::ToString(device->GetFeatureLevel())
+ ::ToString(device->GetFeatureLevel()),
+ device->GetAdapter()->GetDriverVersion().ToString()
);
// Initialize
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
index ac11989d5..f6dff7b44 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
@@ -296,8 +296,6 @@ GPUDevice* GPUDeviceDX11::Create()
}
}
}
-
- // Validate adapter
if (!selectedAdapter.IsValid())
{
LOG(Error, "Failed to choose valid DirectX adapter!");
@@ -427,7 +425,7 @@ bool GPUDeviceDX11::Init()
// Create DirectX device
D3D_FEATURE_LEVEL createdFeatureLevel = static_cast(0);
- auto targetFeatureLevel = GetD3DFeatureLevel();
+ D3D_FEATURE_LEVEL targetFeatureLevel = _adapter->MaxFeatureLevel;
VALIDATE_DIRECTX_CALL(D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, &targetFeatureLevel, 1, D3D11_SDK_VERSION, &_device, &createdFeatureLevel, &_imContext));
ASSERT(_device);
ASSERT(_imContext);
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
index 65e3f6d83..e646dd650 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
@@ -198,17 +198,14 @@ GPUDevice* GPUDeviceDX12::Create()
}
}
}
-
- // Validate adapter
if (!selectedAdapter.IsValid())
{
LOG(Error, "Failed to choose valid DirectX adapter!");
return nullptr;
}
-
- // Check if selected adapter does not support DirectX 12
- if (!selectedAdapter.IsSupportingDX12())
+ if (selectedAdapter.MaxFeatureLevel < D3D_FEATURE_LEVEL_12_0)
{
+ LOG(Error, "Failed to choose valid DirectX adapter!");
return nullptr;
}
#endif
diff --git a/Source/Engine/GraphicsDevice/DirectX/GPUAdapterDX.h b/Source/Engine/GraphicsDevice/DirectX/GPUAdapterDX.h
index 881d40a17..5a5ef1d69 100644
--- a/Source/Engine/GraphicsDevice/DirectX/GPUAdapterDX.h
+++ b/Source/Engine/GraphicsDevice/DirectX/GPUAdapterDX.h
@@ -14,25 +14,18 @@
class GPUAdapterDX : public GPUAdapter
{
public:
-
int32 Index = INVALID_INDEX;
D3D_FEATURE_LEVEL MaxFeatureLevel;
DXGI_ADAPTER_DESC Description;
+ Version DriverVersion = Version(0, 0);
public:
+ void GetDriverVersion();
- // Returns true if adapter is supporting DirectX 12.
- FORCE_INLINE bool IsSupportingDX12() const
- {
-#if GRAPHICS_API_DIRECTX12
- return MaxFeatureLevel >= D3D_FEATURE_LEVEL_12_0;
-#else
- return false;
-#endif
- }
+private:
+ void SetDriverVersion(Version& ver);
public:
-
// [GPUAdapter]
bool IsValid() const override
{
@@ -50,6 +43,10 @@ public:
{
return Description.Description;
}
+ Version GetDriverVersion() const override
+ {
+ return DriverVersion;
+ }
};
#endif
diff --git a/Source/Engine/GraphicsDevice/DirectX/GPUDeviceDX.h b/Source/Engine/GraphicsDevice/DirectX/GPUDeviceDX.h
index 61b61847e..7fa9087ab 100644
--- a/Source/Engine/GraphicsDevice/DirectX/GPUDeviceDX.h
+++ b/Source/Engine/GraphicsDevice/DirectX/GPUDeviceDX.h
@@ -36,17 +36,10 @@ protected:
: GPUDevice(type, profile)
, _adapter(adapter)
{
+ adapter->GetDriverVersion();
}
public:
- ///
- /// Gets DirectX device feature level.
- ///
- FORCE_INLINE D3D_FEATURE_LEVEL GetD3DFeatureLevel() const
- {
- return _adapter->MaxFeatureLevel;
- }
-
///
/// The video outputs.
///
diff --git a/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp b/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp
index 39a975b74..9832e4a12 100644
--- a/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp
@@ -3,11 +3,24 @@
#if GRAPHICS_API_DIRECTX11 || GRAPHICS_API_DIRECTX12
#include "RenderToolsDX.h"
+#include "GPUAdapterDX.h"
#include "GPUDeviceDX.h"
+#include "Engine/Core/Types/DateTime.h"
#include "Engine/Core/Types/StringBuilder.h"
#include "Engine/Graphics/GPUDevice.h"
+#include "IncludeDirectXHeaders.h"
#include
+#define GPU_DRIVER_DETECTION_WIN32_REGISTRY (PLATFORM_WINDOWS)
+#define GPU_DRIVER_DETECTION_WIN32_SETUPAPI (PLATFORM_WINDOWS)
+
+#if GPU_DRIVER_DETECTION_WIN32_SETUPAPI
+#define _SETUPAPI_VER WINVER
+typedef void* LPCDLGTEMPLATE;
+#include
+#pragma comment(lib, "SetupAPI.lib")
+#endif
+
namespace Windows
{
typedef struct _devicemodeW
@@ -304,7 +317,7 @@ void FormatD3DErrorString(HRESULT errorCode, StringBuilder& sb, HRESULT& removed
default:
sb.AppendFormat(TEXT("0x{0:x}"), static_cast(errorCode));
- break;
+ break;
}
#undef D3DERR
@@ -439,6 +452,140 @@ LPCSTR RenderToolsDX::GetVertexInputSemantic(VertexElement::Types type, UINT& se
return "";
}
}
+
+void GPUAdapterDX::GetDriverVersion()
+{
+#if GPU_DRIVER_DETECTION_WIN32_REGISTRY
+ {
+ // Reference: https://github.com/GameTechDev/gpudetect/blob/master/GPUDetect.cpp
+
+ // Fetch registry data
+ HKEY dxKeyHandle = nullptr;
+ DWORD numOfAdapters = 0;
+ LSTATUS returnCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\DirectX"), 0, KEY_READ, &dxKeyHandle);
+ if (returnCode == S_OK)
+ {
+ // Find all sub keys
+ DWORD subKeyMaxLength = 0;
+ returnCode = RegQueryInfoKeyW(dxKeyHandle, 0, 0, 0, &numOfAdapters, &subKeyMaxLength, 0, 0, 0, 0, 0, 0);
+ if (returnCode == S_OK && subKeyMaxLength < 100)
+ {
+ subKeyMaxLength += 1;
+ uint64_t driverVersionRaw = 0;
+ TCHAR subKeyName[100];
+ for (DWORD i = 0; i < numOfAdapters; i++)
+ {
+ DWORD subKeyLength = subKeyMaxLength;
+ returnCode = RegEnumKeyExW(dxKeyHandle, i, subKeyName, &subKeyLength, 0, 0, 0, 0);
+ if (returnCode == S_OK)
+ {
+ LUID adapterLUID = {};
+ DWORD qwordSize = sizeof(uint64_t);
+ returnCode = RegGetValueW(dxKeyHandle, subKeyName, TEXT("AdapterLuid"), RRF_RT_QWORD, 0, &adapterLUID, &qwordSize);
+ if (returnCode == S_OK && adapterLUID.HighPart == Description.AdapterLuid.HighPart && adapterLUID.LowPart == Description.AdapterLuid.LowPart)
+ {
+ // Get driver version
+ returnCode = RegGetValueW(dxKeyHandle, subKeyName, TEXT("DriverVersion"), RRF_RT_QWORD, 0, &driverVersionRaw, &qwordSize);
+ if (returnCode == S_OK)
+ {
+ Version driverVersion(
+ (int32)((driverVersionRaw & 0xFFFF000000000000) >> 16 * 3),
+ (int32)((driverVersionRaw & 0x0000FFFF00000000) >> 16 * 2),
+ (int32)((driverVersionRaw & 0x00000000FFFF0000) >> 16 * 1),
+ (int32)((driverVersionRaw & 0x000000000000FFFF)));
+ SetDriverVersion(driverVersion);
+ }
+ break;
+ }
+ }
+ }
+ }
+ RegCloseKey(dxKeyHandle);
+ }
+
+ if (DriverVersion != Version(0, 0))
+ return;
+ }
+#endif
+
+#if GPU_DRIVER_DETECTION_WIN32_SETUPAPI
+ {
+ // Reference: https://gist.github.com/LxLasso/eccee4d71c2e49492f2cbf01a966fa73
+
+ // Copied from devguid.h and devpkey.h
+#define MAKE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#define MAKE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) const DEVPROPKEY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
+ MAKE_GUID(GUID_DEVCLASS_DISPLAY, 0x4d36e968L, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18);
+ MAKE_DEVPROPKEY(DEVPKEY_Device_DriverDate, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 2);
+ MAKE_DEVPROPKEY(DEVPKEY_Device_DriverVersion, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3);
+#undef MAKE_DEVPROPKEY
+#undef MAKE_GUID
+
+ HDEVINFO deviceInfoList = SetupDiGetClassDevs(&GUID_DEVCLASS_DISPLAY, NULL, NULL, DIGCF_PRESENT);
+ if (deviceInfoList != INVALID_HANDLE_VALUE)
+ {
+ SP_DEVINFO_DATA deviceInfo;
+ ZeroMemory(&deviceInfo, sizeof(deviceInfo));
+ deviceInfo.cbSize = sizeof(SP_DEVINFO_DATA);
+
+ wchar_t searchBuffer[128];
+ swprintf(searchBuffer, sizeof(searchBuffer) / 2, L"PCI\\VEN_%04X&DEV_%04X&SUBSYS_%04X", Description.VendorId, Description.DeviceId, Description.SubSysId);
+ size_t searchBufferLen = wcslen(searchBuffer);
+
+ DWORD deviceIndex = 0;
+ DEVPROPTYPE propertyType;
+ wchar_t buffer[300];
+ while (SetupDiEnumDeviceInfo(deviceInfoList, deviceIndex, &deviceInfo))
+ {
+ DWORD deviceIdSize;
+ if (SetupDiGetDeviceInstanceId(deviceInfoList, &deviceInfo, buffer, sizeof(buffer), &deviceIdSize) &&
+ wcsncmp(buffer, searchBuffer, searchBufferLen) == 0)
+ {
+ // Get driver version
+ if (SetupDiGetDeviceProperty(deviceInfoList, &deviceInfo, &DEVPKEY_Device_DriverVersion, &propertyType, (PBYTE)buffer, sizeof(buffer), NULL, 0) &&
+ propertyType == DEVPROP_TYPE_STRING)
+ {
+ //ParseDriverVersionBuffer(buffer);
+ Version driverVersion;
+ String bufferStr(buffer);
+ if (!Version::Parse(bufferStr, &driverVersion))
+ SetDriverVersion(driverVersion);
+ }
+
+#if 0
+ // Get driver date
+ DEVPROPTYPE propertyType;
+ if (SetupDiGetDeviceProperty(deviceInfoList, &deviceInfo, &DEVPKEY_Device_DriverDate, &propertyType, (PBYTE)buffer, sizeof(FILETIME), NULL, 0) &&
+ propertyType == DEVPROP_TYPE_FILETIME)
+ {
+ SYSTEMTIME deviceDriverSystemTime;
+ FileTimeToSystemTime((FILETIME*)buffer, &deviceDriverSystemTime);
+ DriverDate = DateTime(deviceDriverSystemTime.wYear, deviceDriverSystemTime.wMonth, deviceDriverSystemTime.wDay, deviceDriverSystemTime.wHour, deviceDriverSystemTime.wMinute, deviceDriverSystemTime.wSecond, deviceDriverSystemTime.wMilliseconds);
+ }
+#endif
+ }
+ deviceIndex++;
+ }
+
+ SetupDiDestroyDeviceInfoList(deviceInfoList);
+ }
+
+ if (DriverVersion != Version(0, 0))
+ return;
+ }
+#endif
+}
+
+void GPUAdapterDX::SetDriverVersion(Version& ver)
+{
+ if (IsNVIDIA() && ver.Build() > 0 && ver.Revision() > 99)
+ {
+ // Convert NVIDIA version from 32.0.15.7247 into 572.47
+ ver = Version((ver.Build() % 10) * 100 + ver.Revision() / 100, ver.Revision() % 100);
+ }
+ DriverVersion = ver;
+}
+
void GPUDeviceDX::UpdateOutputs(IDXGIAdapter* adapter)
{
#if PLATFORM_WINDOWS
diff --git a/Source/Engine/GraphicsDevice/Null/GPUAdapterNull.h b/Source/Engine/GraphicsDevice/Null/GPUAdapterNull.h
index 28cbac304..8f2fe49e8 100644
--- a/Source/Engine/GraphicsDevice/Null/GPUAdapterNull.h
+++ b/Source/Engine/GraphicsDevice/Null/GPUAdapterNull.h
@@ -29,6 +29,10 @@ public:
{
return TEXT("Null");
}
+ Version GetDriverVersion() const override
+ {
+ return Version(0, 0);
+ }
};
#endif
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUAdapterVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUAdapterVulkan.h
index e109293a6..66b9256fd 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUAdapterVulkan.h
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUAdapterVulkan.h
@@ -70,6 +70,27 @@ public:
{
return Description;
}
+ Version GetDriverVersion() const override
+ {
+ Version version(VK_VERSION_MAJOR(GpuProps.driverVersion), VK_VERSION_MINOR(GpuProps.driverVersion), VK_VERSION_PATCH(GpuProps.driverVersion));
+ if (IsNVIDIA())
+ {
+ union NvidiaDriverVersion
+ {
+ struct
+ {
+ uint32 Tertiary : 6;
+ uint32 Secondary : 8;
+ uint32 Minor : 8;
+ uint32 Major : 10;
+ };
+ uint32 Packed;
+ } NvidiaVersion;
+ NvidiaVersion.Packed = GpuProps.driverVersion;
+ version = Version(NvidiaVersion.Major, NvidiaVersion.Minor);
+ }
+ return version;
+ }
};
#endif