From 0a7aebadfbb3534284546aa3ca8612314c08f136 Mon Sep 17 00:00:00 2001 From: Miguel Costa Date: Tue, 26 Jun 2018 16:56:45 +0200 Subject: Update ANGLE to chromium/3280 Change-Id: I0802c0d7486f772d361f87a544d6c5af937f4ca1 Reviewed-by: Friedemann Kleint --- .../angle/src/gpu_info_util/SystemInfo.cpp | 171 ++++++++++++++ src/3rdparty/angle/src/gpu_info_util/SystemInfo.h | 73 ++++++ .../angle/src/gpu_info_util/SystemInfo_internal.h | 38 ++++ .../angle/src/gpu_info_util/SystemInfo_libpci.cpp | 132 +++++++++++ .../angle/src/gpu_info_util/SystemInfo_linux.cpp | 144 ++++++++++++ .../angle/src/gpu_info_util/SystemInfo_mac.mm | 170 ++++++++++++++ .../angle/src/gpu_info_util/SystemInfo_win.cpp | 251 +++++++++++++++++++++ .../angle/src/gpu_info_util/SystemInfo_x11.cpp | 53 +++++ 8 files changed, 1032 insertions(+) create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo.cpp create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo.h create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_internal.h create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_libpci.cpp create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_linux.cpp create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_mac.mm create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_x11.cpp (limited to 'src/3rdparty/angle/src/gpu_info_util') diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo.cpp b/src/3rdparty/angle/src/gpu_info_util/SystemInfo.cpp new file mode 100644 index 0000000000..f8d744342d --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo.cpp @@ -0,0 +1,171 @@ +// +// 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.cpp: implementation of the system-agnostic parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo.h" + +#include +#include + +#include "common/debug.h" +#include "common/string_utils.h" + +namespace angle +{ + +GPUDeviceInfo::GPUDeviceInfo() = default; + +GPUDeviceInfo::~GPUDeviceInfo() = default; + +GPUDeviceInfo::GPUDeviceInfo(const GPUDeviceInfo &other) = default; + +SystemInfo::SystemInfo() = default; + +SystemInfo::~SystemInfo() = default; + +SystemInfo::SystemInfo(const SystemInfo &other) = default; + +bool IsAMD(VendorID vendorId) +{ + return vendorId == kVendorID_AMD; +} + +bool IsIntel(VendorID vendorId) +{ + return vendorId == kVendorID_Intel; +} + +bool IsNvidia(VendorID vendorId) +{ + return vendorId == kVendorID_Nvidia; +} + +bool IsQualcomm(VendorID vendorId) +{ + return vendorId == kVendorID_Qualcomm; +} + +bool ParseAMDBrahmaDriverVersion(const std::string &content, std::string *version) +{ + const size_t begin = content.find_first_of("0123456789"); + if (begin == std::string::npos) + { + return false; + } + + const size_t end = content.find_first_not_of("0123456789.", begin); + if (end == std::string::npos) + { + *version = content.substr(begin); + } + else + { + *version = content.substr(begin, end - begin); + } + return true; +} + +bool ParseAMDCatalystDriverVersion(const std::string &content, std::string *version) +{ + std::istringstream stream(content); + + std::string line; + while (std::getline(stream, line)) + { + static const char kReleaseVersion[] = "ReleaseVersion="; + if (line.compare(0, std::strlen(kReleaseVersion), kReleaseVersion) != 0) + { + continue; + } + + if (ParseAMDBrahmaDriverVersion(line, version)) + { + return true; + } + } + return false; +} + +bool ParseMacMachineModel(const std::string &identifier, + std::string *type, + int32_t *major, + int32_t *minor) +{ + size_t numberLoc = identifier.find_first_of("0123456789"); + if (numberLoc == std::string::npos) + { + return false; + } + + size_t commaLoc = identifier.find(',', numberLoc); + if (commaLoc == std::string::npos || commaLoc >= identifier.size()) + { + return false; + } + + const char *numberPtr = &identifier[numberLoc]; + const char *commaPtr = &identifier[commaLoc + 1]; + char *endPtr = nullptr; + + int32_t majorTmp = std::strtol(numberPtr, &endPtr, 10); + if (endPtr == numberPtr) + { + return false; + } + + int32_t minorTmp = std::strtol(commaPtr, &endPtr, 10); + if (endPtr == commaPtr) + { + return false; + } + + *major = majorTmp; + *minor = minorTmp; + *type = identifier.substr(0, numberLoc); + + 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()); + + // On dual-GPU systems we assume the non-Intel GPU is the primary one. + int primary = 0; + bool hasIntel = false; + for (size_t i = 0; i < info->gpus.size(); ++i) + { + if (IsIntel(info->gpus[i].vendorId)) + { + hasIntel = true; + } + if (IsIntel(info->gpus[primary].vendorId)) + { + primary = static_cast(i); + } + } + + // Assume that a combination of AMD or Nvidia with Intel means Optimus or AMD Switchable + info->primaryGPUIndex = primary; + info->isOptimus = hasIntel && IsNvidia(info->gpus[primary].vendorId); + info->isAMDSwitchable = hasIntel && IsAMD(info->gpus[primary].vendorId); +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo.h b/src/3rdparty/angle/src/gpu_info_util/SystemInfo.h new file mode 100644 index 0000000000..ada43f0a15 --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo.h @@ -0,0 +1,73 @@ +// +// 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.h: gathers information available without starting a GPU driver. + +#ifndef GPU_INFO_UTIL_SYSTEM_INFO_H_ +#define GPU_INFO_UTIL_SYSTEM_INFO_H_ + +#include +#include +#include + +namespace angle +{ + +using VendorID = uint32_t; +using DeviceID = uint32_t; + +constexpr VendorID kVendorID_AMD = 0x1002; +constexpr VendorID kVendorID_Intel = 0x8086; +constexpr VendorID kVendorID_Nvidia = 0x10DE; +constexpr VendorID kVendorID_Qualcomm = 0x5143; + +struct GPUDeviceInfo +{ + GPUDeviceInfo(); + ~GPUDeviceInfo(); + + GPUDeviceInfo(const GPUDeviceInfo &other); + + VendorID vendorId = 0; + DeviceID deviceId = 0; + + std::string driverVendor; + std::string driverVersion; + std::string driverDate; +}; + +struct SystemInfo +{ + SystemInfo(); + ~SystemInfo(); + + SystemInfo(const SystemInfo &other); + + std::vector gpus; + int primaryGPUIndex = -1; + int activeGPUIndex = -1; + + bool isOptimus = false; + bool isAMDSwitchable = false; + + // Only available on macOS + std::string machineModelName; + std::string machineModelVersion; + + // Only available on Windows, set even on failure. + std::string primaryDisplayDeviceId; +}; + +bool GetSystemInfo(SystemInfo *info); + +bool IsAMD(VendorID vendorId); +bool IsIntel(VendorID vendorId); +bool IsNvidia(VendorID vendorId); +bool IsQualcomm(VendorID vendorId); + +} // namespace angle + +#endif // GPU_INFO_UTIL_SYSTEM_INFO_H_ diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_internal.h b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_internal.h new file mode 100644 index 0000000000..d2f6124662 --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_internal.h @@ -0,0 +1,38 @@ +// +// 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_internal.h: Functions used by the SystemInfo_* files and unittests + +#ifndef GPU_INFO_UTIL_SYSTEM_INFO_INTERNAL_H_ +#define GPU_INFO_UTIL_SYSTEM_INFO_INTERNAL_H_ + +#include "gpu_info_util/SystemInfo.h" + +namespace angle +{ + +// Defined in SystemInfo_libpci when GPU_INFO_USE_LIBPCI is defined. +bool GetPCIDevicesWithLibPCI(std::vector *devices); +// Defined in SystemInfo_x11 when GPU_INFO_USE_X11 is defined. +bool GetNvidiaDriverVersionWithXNVCtrl(std::string *version); + +// Target specific helper functions that can be compiled on all targets +// Live in SystemInfo.cpp +bool ParseAMDBrahmaDriverVersion(const std::string &content, std::string *version); +bool ParseAMDCatalystDriverVersion(const std::string &content, std::string *version); +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 +void FindPrimaryGPU(SystemInfo *info); + +} // namespace angle + +#endif // GPU_INFO_UTIL_SYSTEM_INFO_INTERNAL_H_ diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_libpci.cpp b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_libpci.cpp new file mode 100644 index 0000000000..07c72872ad --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_libpci.cpp @@ -0,0 +1,132 @@ +// +// 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_libpci.cpp: implementation of the libPCI-specific parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo_internal.h" + +#include +#include +#include + +#include "common/angleutils.h" +#include "common/debug.h" + +#if !defined(GPU_INFO_USE_LIBPCI) +#error SystemInfo_libpci.cpp compiled without GPU_INFO_USE_LIBPCI +#endif + +namespace angle +{ + +namespace +{ + +struct LibPCI : private angle::NonCopyable +{ + LibPCI() + { + if (access("/sys/bus/pci/", F_OK) != 0 && access("/sys/bs/pci_express/", F_OK) != 0) + { + return; + } + + mHandle = dlopen("libpci.so.3", RTLD_LAZY); + + if (mHandle == nullptr) + { + mHandle = dlopen("libpci.so", RTLD_LAZY); + } + + if (mHandle == nullptr) + { + return; + } + + mValid = + (Alloc = reinterpret_cast(dlsym(mHandle, "pci_alloc"))) != nullptr && + (Init = reinterpret_cast(dlsym(mHandle, "pci_init"))) != nullptr && + (Cleanup = reinterpret_cast(dlsym(mHandle, "pci_cleanup"))) != + nullptr && + (ScanBus = reinterpret_cast(dlsym(mHandle, "pci_scan_bus"))) != + nullptr && + (FillInfo = reinterpret_cast(dlsym(mHandle, "pci_fill_info"))) != + nullptr && + (LookupName = reinterpret_cast( + dlsym(mHandle, "pci_lookup_name"))) != nullptr; + } + + bool IsValid() const { return mValid; } + + ~LibPCI() + { + if (mHandle != nullptr) + { + dlclose(mHandle); + } + } + + decltype(&::pci_alloc) Alloc = nullptr; + decltype(&::pci_init) Init = nullptr; + decltype(&::pci_cleanup) Cleanup = nullptr; + decltype(&::pci_scan_bus) ScanBus = nullptr; + decltype(&::pci_fill_info) FillInfo = nullptr; + decltype(&::pci_lookup_name) LookupName = nullptr; + + private: + void *mHandle = nullptr; + bool mValid = false; +}; + +} // anonymous namespace + +// Adds an entry per PCI GPU found and fills the device and vendor ID. +bool GetPCIDevicesWithLibPCI(std::vector *devices) +{ + LibPCI pci; + if (!pci.IsValid()) + { + return false; + } + + pci_access *access = pci.Alloc(); + ASSERT(access != nullptr); + pci.Init(access); + pci.ScanBus(access); + + for (pci_dev *device = access->devices; device != nullptr; device = device->next) + { + pci.FillInfo(device, PCI_FILL_IDENT | PCI_FILL_CLASS); + + // Skip non-GPU devices + switch (device->device_class) + { + case PCI_CLASS_DISPLAY_VGA: + case PCI_CLASS_DISPLAY_XGA: + case PCI_CLASS_DISPLAY_3D: + break; + default: + continue; + } + + // Skip unknown devices + if (device->vendor_id == 0 || device->device_id == 0) + { + continue; + } + + GPUDeviceInfo info; + info.vendorId = device->vendor_id; + info.deviceId = device->device_id; + + devices->push_back(info); + } + + pci.Cleanup(access); + + return true; +} +} diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_linux.cpp b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_linux.cpp new file mode 100644 index 0000000000..98f000b069 --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_linux.cpp @@ -0,0 +1,144 @@ +// +// 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_linux.cpp: implementation of the Linux-specific parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo_internal.h" + +#include +#include + +#include "common/angleutils.h" +#include "common/debug.h" + +namespace angle +{ + +namespace +{ + +bool ReadWholeFile(const char *filename, std::string *content) +{ + std::ifstream file(filename); + + if (!file) + { + return false; + } + + *content = std::string(std::istreambuf_iterator(file), std::istreambuf_iterator()); + return true; +} + +// Scan /sys/module/amdgpu/version. +bool GetAMDBrahmaDriverVersion(std::string *version) +{ + *version = ""; + std::string content; + + return ReadWholeFile("/sys/module/amdgpu/version", &content) && + ParseAMDBrahmaDriverVersion(content, version); +} + +// Scan /etc/ati/amdpcsdb.default for "ReleaseVersion". +bool GetAMDCatalystDriverVersion(std::string *version) +{ + *version = ""; + std::string content; + + return ReadWholeFile("/etc/ati/amdpcsdb.default", &content) && + ParseAMDCatalystDriverVersion(content, version); +} + +} // anonymous namespace + +#if !defined(GPU_INFO_USE_X11) +bool GetNvidiaDriverVersionWithXNVCtrl(std::string *version) +{ + return false; +} +#endif + +#if !defined(GPU_INFO_USE_LIBPCI) +bool GetPCIDevicesWithLibPCI(std::vector *devices) +{ + return false; +} +#endif + +bool GetSystemInfo(SystemInfo *info) +{ + if (!GetPCIDevicesWithLibPCI(&(info->gpus))) + { + return false; + } + + if (info->gpus.size() == 0) + { + return false; + } + + FindPrimaryGPU(info); + + for (size_t i = 0; i < info->gpus.size(); ++i) + { + GPUDeviceInfo *gpu = &info->gpus[i]; + + // New GPUs might be added inside this loop, don't query for their driver version again + if (!gpu->driverVendor.empty()) + { + continue; + } + + if (IsAMD(gpu->vendorId)) + { + std::string version; + if (GetAMDBrahmaDriverVersion(&version)) + { + gpu->driverVendor = "AMD (Brahma)"; + gpu->driverVersion = std::move(version); + } + else if (GetAMDCatalystDriverVersion(&version)) + { + gpu->driverVendor = "AMD (Catalyst)"; + gpu->driverVersion = std::move(version); + } + } + + if (IsNvidia(gpu->vendorId)) + { + std::string version; + if (GetNvidiaDriverVersionWithXNVCtrl(&version)) + { + gpu->driverVendor = "Nvidia"; + gpu->driverVersion = std::move(version); + } + } + + // In dual-GPU cases the PCI scan sometimes only gives us the Intel GPU. + // If we are able to query for the Nvidia driver version, it means there + // was hidden Nvidia GPU, so we add it to the list and make it primary. + if (IsIntel(gpu->vendorId) && info->gpus.size() == 1) + { + std::string version; + if (GetNvidiaDriverVersionWithXNVCtrl(&version)) + { + GPUDeviceInfo nvidiaInfo; + nvidiaInfo.vendorId = kVendorID_Nvidia; + nvidiaInfo.deviceId = 0; + gpu->driverVendor = "Nvidia"; + gpu->driverVersion = std::move(version); + + info->gpus.emplace_back(std::move(nvidiaInfo)); + info->isOptimus = true; + } + } + } + + return true; +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_mac.mm b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_mac.mm new file mode 100644 index 0000000000..7a7a62d170 --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_mac.mm @@ -0,0 +1,170 @@ +// +// Copyright (c) 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_mac.cpp: implementation of the Mac-specific parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo_internal.h" + +#import +#import + +namespace angle +{ + +namespace +{ + +std::string GetMachineModel() +{ + io_service_t platformExpert = IOServiceGetMatchingService( + kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); + + if (platformExpert == IO_OBJECT_NULL) + { + return ""; + } + + CFDataRef modelData = static_cast( + IORegistryEntryCreateCFProperty(platformExpert, CFSTR("model"), kCFAllocatorDefault, 0)); + if (modelData == nullptr) + { + IOObjectRelease(platformExpert); + return ""; + } + + std::string result = reinterpret_cast(CFDataGetBytePtr(modelData)); + + IOObjectRelease(platformExpert); + CFRelease(modelData); + + return result; +} + +// Extracts one integer property from a registry entry. +bool GetEntryProperty(io_registry_entry_t entry, CFStringRef name, uint32_t *value) +{ + *value = 0; + + CFDataRef data = static_cast( + IORegistryEntrySearchCFProperty(entry, kIOServicePlane, name, kCFAllocatorDefault, + kIORegistryIterateRecursively | kIORegistryIterateParents)); + + if (data == nullptr) + { + return false; + } + + const uint32_t *valuePtr = reinterpret_cast(CFDataGetBytePtr(data)); + + if (valuePtr == nullptr) + { + CFRelease(data); + return false; + } + + *value = *valuePtr; + CFRelease(data); + return true; +} + +// CGDisplayIOServicePort is deprecated as of macOS 10.9, but has no replacement, see +// https://crbug.com/650837 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +// Find the info of the current GPU. +bool GetActiveGPU(VendorID *vendorId, DeviceID *deviceId) +{ + io_registry_entry_t port = CGDisplayIOServicePort(kCGDirectMainDisplay); + + return GetEntryProperty(port, CFSTR("vendor-id"), vendorId) && + GetEntryProperty(port, CFSTR("device-id"), deviceId); +} + +#pragma clang diagnostic pop + +// Gathers the vendor and device IDs for the PCI GPUs +bool GetPCIDevices(std::vector *devices) +{ + // matchDictionary will be consumed by IOServiceGetMatchingServices, no need to release it. + CFMutableDictionaryRef matchDictionary = IOServiceMatching("IOPCIDevice"); + + io_iterator_t entryIterator; + if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchDictionary, &entryIterator) != + kIOReturnSuccess) + { + return false; + } + + io_registry_entry_t entry = IO_OBJECT_NULL; + + while ((entry = IOIteratorNext(entryIterator)) != IO_OBJECT_NULL) + { + constexpr uint32_t kClassCodeDisplayVGA = 0x30000; + uint32_t classCode; + GPUDeviceInfo info; + + if (GetEntryProperty(entry, CFSTR("class-code"), &classCode) && + classCode == kClassCodeDisplayVGA && + GetEntryProperty(entry, CFSTR("vendor-id"), &info.vendorId) && + GetEntryProperty(entry, CFSTR("device-id"), &info.deviceId)) + { + devices->push_back(info); + } + + IOObjectRelease(entry); + } + IOObjectRelease(entryIterator); + + return true; +} + +} // anonymous namespace + +bool GetSystemInfo(SystemInfo *info) +{ + { + int32_t major = 0; + int32_t minor = 0; + ParseMacMachineModel(GetMachineModel(), &info->machineModelName, &major, &minor); + info->machineModelVersion = std::to_string(major) + "." + std::to_string(minor); + } + + if (!GetPCIDevices(&(info->gpus))) + { + return false; + } + + if (info->gpus.empty()) + { + return false; + } + + // Find the active GPU + { + VendorID activeVendor; + DeviceID activeDevice; + if (!GetActiveGPU(&activeVendor, &activeDevice)) + { + return false; + } + + for (size_t i = 0; i < info->gpus.size(); ++i) + { + if (info->gpus[i].vendorId == activeVendor && info->gpus[i].deviceId == activeDevice) + { + info->activeGPUIndex = i; + break; + } + } + } + + FindPrimaryGPU(info); + + return true; +} + +} // namespace angle 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 + +#if defined(GPU_INFO_USE_SETUPAPI) +// Remove parts of commctrl.h that have compile errors +#define NOTOOLBAR +#define NOTOOLTIPS +#include +#include +#elif defined(GPU_INFO_USE_DXGI) +#include +#include +#else +#error "SystemInfo_win needs at least GPU_INFO_USE_SETUPAPI or GPU_INFO_USE_DXGI defined" +#endif + +#include +#include + +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 value; + DWORD valueSize = sizeof(value); + if (RegQueryValueExA(key, valueName, nullptr, nullptr, reinterpret_cast(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 *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 {}/<4 digit number>. + std::array value; + if (!SetupDiGetDeviceRegistryPropertyW(deviceInfo, &deviceData, SPDRP_DRIVER, nullptr, + reinterpret_cast(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 *devices) +{ + IDXGIFactory *factory; + if (!SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast(&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(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 diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_x11.cpp b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_x11.cpp new file mode 100644 index 0000000000..3513309f36 --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_x11.cpp @@ -0,0 +1,53 @@ +// +// 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_x11.cpp: implementation of the X11-specific parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo_internal.h" + +#include + +#include "common/debug.h" +#include "third_party/libXNVCtrl/NVCtrl.h" +#include "third_party/libXNVCtrl/NVCtrlLib.h" + +#if !defined(GPU_INFO_USE_X11) +#error SystemInfo_x11.cpp compiled without GPU_INFO_USE_X11 +#endif + +namespace angle +{ + +bool GetNvidiaDriverVersionWithXNVCtrl(std::string *version) +{ + *version = ""; + + int eventBase = 0; + int errorBase = 0; + + Display *display = XOpenDisplay(nullptr); + + if (XNVCTRLQueryExtension(display, &eventBase, &errorBase)) + { + int screenCount = ScreenCount(display); + for (int screen = 0; screen < screenCount; ++screen) + { + char *buffer = nullptr; + if (XNVCTRLIsNvScreen(display, screen) && + XNVCTRLQueryStringAttribute(display, screen, 0, + NV_CTRL_STRING_NVIDIA_DRIVER_VERSION, &buffer)) + { + ASSERT(buffer != nullptr); + *version = buffer; + XFree(buffer); + return true; + } + } + } + + return false; +} +} -- cgit v1.2.3