summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp')
-rw-r--r--src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp251
1 files changed, 251 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp
new file mode 100644
index 0000000000..041fdad34d
--- /dev/null
+++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp
@@ -0,0 +1,251 @@
+//
+// Copyright (c) 2013-2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// SystemInfo_win.cpp: implementation of the Windows-specific parts of SystemInfo.h
+
+#include "gpu_info_util/SystemInfo_internal.h"
+
+#include "common/debug.h"
+#include "common/string_utils.h"
+
+// Windows.h needs to be included first
+#include <windows.h>
+
+#if defined(GPU_INFO_USE_SETUPAPI)
+// Remove parts of commctrl.h that have compile errors
+#define NOTOOLBAR
+#define NOTOOLTIPS
+#include <cfgmgr32.h>
+#include <setupapi.h>
+#elif defined(GPU_INFO_USE_DXGI)
+#include <dxgi.h>
+#include <d3d10.h>
+#else
+#error "SystemInfo_win needs at least GPU_INFO_USE_SETUPAPI or GPU_INFO_USE_DXGI defined"
+#endif
+
+#include <array>
+#include <sstream>
+
+namespace angle
+{
+
+namespace
+{
+
+// Returns the CM device ID of the primary GPU.
+std::string GetPrimaryDisplayDeviceId()
+{
+ DISPLAY_DEVICEA displayDevice;
+ displayDevice.cb = sizeof(DISPLAY_DEVICEA);
+
+ for (int i = 0; EnumDisplayDevicesA(nullptr, i, &displayDevice, 0); ++i)
+ {
+ if (displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
+ {
+ return displayDevice.DeviceID;
+ }
+ }
+
+ return "";
+}
+
+#if defined(GPU_INFO_USE_SETUPAPI)
+
+std::string GetRegistryStringValue(HKEY key, const char *valueName)
+{
+ std::array<char, 255> value;
+ DWORD valueSize = sizeof(value);
+ if (RegQueryValueExA(key, valueName, nullptr, nullptr, reinterpret_cast<LPBYTE>(value.data()),
+ &valueSize) == ERROR_SUCCESS)
+ {
+ return value.data();
+ }
+ return "";
+}
+
+// Gathers information about the devices from the registry. The reason why we aren't using
+// a dedicated API such as DXGI is that we need information like the driver vendor and date.
+// DXGI doesn't provide a way to know the device registry key from an IDXGIAdapter.
+bool GetDevicesFromRegistry(std::vector<GPUDeviceInfo> *devices)
+{
+ // Display adapter class GUID from
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff553426%28v=vs.85%29.aspx
+ GUID displayClass = {
+ 0x4d36e968, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
+
+ HDEVINFO deviceInfo = SetupDiGetClassDevsW(&displayClass, nullptr, nullptr, DIGCF_PRESENT);
+
+ if (deviceInfo == INVALID_HANDLE_VALUE)
+ {
+ return false;
+ }
+
+ // This iterates over the devices of the "Display adapter" class
+ DWORD deviceIndex = 0;
+ SP_DEVINFO_DATA deviceData;
+ deviceData.cbSize = sizeof(deviceData);
+ while (SetupDiEnumDeviceInfo(deviceInfo, deviceIndex++, &deviceData))
+ {
+ // The device and vendor IDs can be gathered directly, but information about the driver
+ // requires some registry digging
+ char fullDeviceID[MAX_DEVICE_ID_LEN];
+ if (CM_Get_Device_IDA(deviceData.DevInst, fullDeviceID, MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS)
+ {
+ continue;
+ }
+
+ GPUDeviceInfo device;
+
+ if (!CMDeviceIDToDeviceAndVendorID(fullDeviceID, &device.vendorId, &device.deviceId))
+ {
+ continue;
+ }
+
+ // The driver key will end with something like {<displayClass>}/<4 digit number>.
+ std::array<WCHAR, 255> value;
+ if (!SetupDiGetDeviceRegistryPropertyW(deviceInfo, &deviceData, SPDRP_DRIVER, nullptr,
+ reinterpret_cast<PBYTE>(value.data()), sizeof(value),
+ nullptr))
+ {
+ continue;
+ }
+
+ std::wstring driverKey = L"System\\CurrentControlSet\\Control\\Class\\";
+ driverKey += value.data();
+
+ HKEY key;
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, driverKey.c_str(), 0, KEY_QUERY_VALUE, &key) !=
+ ERROR_SUCCESS)
+ {
+ continue;
+ }
+
+ device.driverVersion = GetRegistryStringValue(key, "DriverVersion");
+ device.driverDate = GetRegistryStringValue(key, "DriverDate");
+ device.driverVendor = GetRegistryStringValue(key, "ProviderName");
+
+ RegCloseKey(key);
+
+ devices->push_back(device);
+ }
+
+ SetupDiDestroyDeviceInfoList(deviceInfo);
+
+ return true;
+}
+
+#elif defined(GPU_INFO_USE_DXGI)
+
+bool GetDevicesFromDXGI(std::vector<GPUDeviceInfo> *devices)
+{
+ IDXGIFactory *factory;
+ if (!SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&factory))))
+ {
+ return false;
+ }
+
+ UINT i = 0;
+ IDXGIAdapter *adapter = nullptr;
+ while (factory->EnumAdapters(i++, &adapter) != DXGI_ERROR_NOT_FOUND)
+ {
+ DXGI_ADAPTER_DESC desc;
+ adapter->GetDesc(&desc);
+
+ LARGE_INTEGER umdVersion;
+ if (adapter->CheckInterfaceSupport(__uuidof(ID3D10Device), &umdVersion) ==
+ DXGI_ERROR_UNSUPPORTED)
+ {
+ adapter->Release();
+ continue;
+ }
+
+ // The UMD driver version here is the same as in the registry except for the last number.
+ uint64_t intVersion = umdVersion.QuadPart;
+ std::ostringstream o;
+
+ const uint64_t kMask = 0xFF;
+ o << ((intVersion >> 48) & kMask) << ".";
+ o << ((intVersion >> 32) & kMask) << ".";
+ o << ((intVersion >> 16) & kMask) << ".";
+ o << (intVersion & kMask);
+
+ GPUDeviceInfo device;
+ device.vendorId = desc.VendorId;
+ device.deviceId = desc.DeviceId;
+ device.driverVersion = o.str();
+
+ devices->push_back(device);
+
+ adapter->Release();
+ }
+
+ factory->Release();
+
+ return true;
+}
+
+#else
+#error
+#endif
+
+} // anonymous namespace
+
+bool GetSystemInfo(SystemInfo *info)
+{
+ // Get the CM device ID first so that it is returned even in error cases.
+ info->primaryDisplayDeviceId = GetPrimaryDisplayDeviceId();
+
+#if defined(GPU_INFO_USE_SETUPAPI)
+ if (!GetDevicesFromRegistry(&info->gpus))
+ {
+ return false;
+ }
+#elif defined(GPU_INFO_USE_DXGI)
+ if (!GetDevicesFromDXGI(&info->gpus))
+ {
+ return false;
+ }
+#else
+#error
+#endif
+
+ if (info->gpus.size() == 0)
+ {
+ return false;
+ }
+
+ FindPrimaryGPU(info);
+
+ // Override the primary GPU index with what we gathered from EnumDisplayDevices
+ uint32_t primaryVendorId = 0;
+ uint32_t primaryDeviceId = 0;
+
+ if (!CMDeviceIDToDeviceAndVendorID(info->primaryDisplayDeviceId, &primaryVendorId,
+ &primaryDeviceId))
+ {
+ return false;
+ }
+
+ bool foundPrimary = false;
+ for (size_t i = 0; i < info->gpus.size(); ++i)
+ {
+ if (info->gpus[i].vendorId == primaryVendorId && info->gpus[i].deviceId == primaryDeviceId)
+ {
+ info->primaryGPUIndex = static_cast<int>(i);
+ foundPrimary = true;
+ }
+ }
+ ASSERT(foundPrimary);
+
+ // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
+ HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
+ info->isOptimus = nvd3d9wrap != nullptr;
+
+ return true;
+}
+
+} // namespace angle