summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/gpu_info_util
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/gpu_info_util')
-rw-r--r--src/3rdparty/angle/src/gpu_info_util/SystemInfo.cpp171
-rw-r--r--src/3rdparty/angle/src/gpu_info_util/SystemInfo.h73
-rw-r--r--src/3rdparty/angle/src/gpu_info_util/SystemInfo_internal.h38
-rw-r--r--src/3rdparty/angle/src/gpu_info_util/SystemInfo_libpci.cpp132
-rw-r--r--src/3rdparty/angle/src/gpu_info_util/SystemInfo_linux.cpp144
-rw-r--r--src/3rdparty/angle/src/gpu_info_util/SystemInfo_mac.mm170
-rw-r--r--src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp251
-rw-r--r--src/3rdparty/angle/src/gpu_info_util/SystemInfo_x11.cpp53
8 files changed, 1032 insertions, 0 deletions
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 <cstring>
+#include <sstream>
+
+#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<int>(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 <cstdint>
+#include <string>
+#include <vector>
+
+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<GPUDeviceInfo> 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<GPUDeviceInfo> *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 <dlfcn.h>
+#include <pci/pci.h>
+#include <unistd.h>
+
+#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<decltype(Alloc)>(dlsym(mHandle, "pci_alloc"))) != nullptr &&
+ (Init = reinterpret_cast<decltype(Init)>(dlsym(mHandle, "pci_init"))) != nullptr &&
+ (Cleanup = reinterpret_cast<decltype(Cleanup)>(dlsym(mHandle, "pci_cleanup"))) !=
+ nullptr &&
+ (ScanBus = reinterpret_cast<decltype(ScanBus)>(dlsym(mHandle, "pci_scan_bus"))) !=
+ nullptr &&
+ (FillInfo = reinterpret_cast<decltype(FillInfo)>(dlsym(mHandle, "pci_fill_info"))) !=
+ nullptr &&
+ (LookupName = reinterpret_cast<decltype(LookupName)>(
+ 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<GPUDeviceInfo> *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 <cstring>
+#include <fstream>
+
+#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<char>(file), std::istreambuf_iterator<char>());
+ 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<GPUDeviceInfo> *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 <Cocoa/Cocoa.h>
+#import <IOKit/IOKitLib.h>
+
+namespace angle
+{
+
+namespace
+{
+
+std::string GetMachineModel()
+{
+ io_service_t platformExpert = IOServiceGetMatchingService(
+ kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
+
+ if (platformExpert == IO_OBJECT_NULL)
+ {
+ return "";
+ }
+
+ CFDataRef modelData = static_cast<CFDataRef>(
+ IORegistryEntryCreateCFProperty(platformExpert, CFSTR("model"), kCFAllocatorDefault, 0));
+ if (modelData == nullptr)
+ {
+ IOObjectRelease(platformExpert);
+ return "";
+ }
+
+ std::string result = reinterpret_cast<const char *>(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<CFDataRef>(
+ IORegistryEntrySearchCFProperty(entry, kIOServicePlane, name, kCFAllocatorDefault,
+ kIORegistryIterateRecursively | kIORegistryIterateParents));
+
+ if (data == nullptr)
+ {
+ return false;
+ }
+
+ const uint32_t *valuePtr = reinterpret_cast<const uint32_t *>(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<GPUDeviceInfo> *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 <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
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 <X11/Xlib.h>
+
+#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;
+}
+}