зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
2d62ab7279
Коммит
8f77e5d323
7
BUILD.gn
7
BUILD.gn
|
@ -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
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче