diff options
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.cpp | 251 |
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 |