gpu_info_util: Implement GetSystemInfo on Windows

BUG=angleproject:1874

Change-Id: I97a02d2c8b1f7ecb530684464fc02f528d34de7c
Reviewed-on: https://chromium-review.googlesource.com/458965
Reviewed-by: Austin Kinross <aukinros@microsoft.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2017-03-24 11:58:59 -07:00 коммит произвёл Commit Bot
Родитель 2d62ab7279
Коммит 8f77e5d323
8 изменённых файлов: 304 добавлений и 1 удалений

Просмотреть файл

@ -214,6 +214,13 @@ static_library("angle_gpu_info_util") {
libs = []
defines = []
if (is_win) {
sources +=
rebase_path(gles_gypi.libangle_gpu_info_util_win_sources, ".", "src")
libs += [ "setupapi.lib" ]
defines += [ "GPU_INFO_USE_SETUPAPI" ]
}
if (is_linux) {
sources +=
rebase_path(gles_gypi.libangle_gpu_info_util_linux_sources, ".", "src")

Просмотреть файл

@ -225,6 +225,52 @@
},
'conditions':
[
['OS=="win"',
{
'sources':
[
'<@(libangle_gpu_info_util_win_sources)',
],
}],
['OS=="win" and angle_build_winrt==0',
{
'link_settings':
{
'msvs_settings':
{
'VCLinkerTool':
{
'AdditionalDependencies':
[
'setupapi.lib'
]
}
}
},
'defines':
[
'GPU_INFO_USE_SETUPAPI',
],
},
{
'link_settings':
{
'msvs_settings':
{
'VCLinkerTool':
{
'AdditionalDependencies':
[
'dxgi.lib'
]
}
}
},
'defines':
[
'GPU_INFO_USE_DXGI',
],
}],
['OS=="linux"',
{
'sources':

Просмотреть файл

@ -12,6 +12,7 @@
#include <sstream>
#include "common/debug.h"
#include "common/string_utils.h"
namespace angle
{
@ -117,6 +118,19 @@ bool ParseMacMachineModel(const std::string &identifier,
return true;
}
bool CMDeviceIDToDeviceAndVendorID(const std::string &id, uint32_t *vendorId, uint32_t *deviceId)
{
unsigned int vendor = 0;
unsigned int device = 0;
bool success = id.length() >= 21 && HexStringToUInt(id.substr(8, 4), &vendor) &&
HexStringToUInt(id.substr(17, 4), &device);
*vendorId = vendor;
*deviceId = device;
return success;
}
void FindPrimaryGPU(SystemInfo *info)
{
ASSERT(!info->gpus.empty());

Просмотреть файл

@ -27,6 +27,7 @@ bool ParseMacMachineModel(const std::string &identifier,
std::string *type,
int32_t *major,
int32_t *minor);
bool CMDeviceIDToDeviceAndVendorID(const std::string &id, uint32_t *vendorId, uint32_t *deviceId);
// In the case there are multiple GPUs, this finds the primary one and sets Optimus or AMD
// Switchable

Просмотреть файл

@ -100,4 +100,32 @@ TEST(SystemInfoTest, MacMachineModelParsing)
EXPECT_EQ(2, minor);
}
// Test Windows CM Device ID parsing
TEST(SystemInfoTest, CMDeviceIDToDeviceAndVendorID)
{
uint32_t vendor = 0;
uint32_t device = 0;
// Test on a real-life CM Device ID
EXPECT_TRUE(CMDeviceIDToDeviceAndVendorID(
"PCI\\VEN_10DE&DEV_0FFA&SUBSYS_094B10DE&REV_A1\\4&95673C&0&0018", &vendor, &device));
EXPECT_EQ(0x10deu, vendor);
EXPECT_EQ(0x0ffau, device);
// Test on a stripped-down but valid CM Device ID string
EXPECT_TRUE(CMDeviceIDToDeviceAndVendorID("PCI\\VEN_10DE&DEV_0FFA", &vendor, &device));
EXPECT_EQ(0x10deu, vendor);
EXPECT_EQ(0x0ffau, device);
// Test on a string that is too small
EXPECT_FALSE(CMDeviceIDToDeviceAndVendorID("\\VEN_10DE&DEV_0FFA", &vendor, &device));
EXPECT_EQ(0u, vendor);
EXPECT_EQ(0u, device);
// Test with invalid number
EXPECT_FALSE(CMDeviceIDToDeviceAndVendorID("PCI\\VEN_XXXX&DEV_XXXX", &vendor, &device));
EXPECT_EQ(0u, vendor);
EXPECT_EQ(0u, device);
}
} // anonymous namespace

Просмотреть файл

@ -0,0 +1,202 @@
//
// 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"
// Windows.h needs to be included first
#include <windows.h>
#if defined(GPU_INFO_USE_SETUPAPI)
#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
{
#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);
}
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)
{
#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);
// 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

Просмотреть файл

@ -69,6 +69,10 @@
'gpu_info_util/SystemInfo.h',
'gpu_info_util/SystemInfo_internal.h',
],
'libangle_gpu_info_util_win_sources':
[
'gpu_info_util/SystemInfo_win.cpp',
],
'libangle_gpu_info_util_linux_sources':
[
'gpu_info_util/SystemInfo_linux.cpp',

Просмотреть файл

@ -19,7 +19,8 @@ using namespace angle;
namespace
{
#if defined(ANGLE_PLATFORM_LINUX) || defined(ANGLE_PLATFORM_APPLE)
#if defined(ANGLE_PLATFORM_WINDOWS) || defined(ANGLE_PLATFORM_LINUX) || \
defined(ANGLE_PLATFORM_APPLE)
#define SYSTEM_INFO_IMPLEMENTED
#endif