summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/gpu_info_util
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/gpu_info_util')
-rw-r--r--gfx/angle/checkout/src/gpu_info_util/SystemInfo.cpp418
-rw-r--r--gfx/angle/checkout/src/gpu_info_util/SystemInfo.h179
-rw-r--r--gfx/angle/checkout/src/gpu_info_util/SystemInfo_internal.h42
-rw-r--r--gfx/angle/checkout/src/gpu_info_util/SystemInfo_vulkan.cpp284
-rw-r--r--gfx/angle/checkout/src/gpu_info_util/SystemInfo_vulkan.h23
-rw-r--r--gfx/angle/checkout/src/gpu_info_util/SystemInfo_win.cpp117
6 files changed, 1063 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/gpu_info_util/SystemInfo.cpp b/gfx/angle/checkout/src/gpu_info_util/SystemInfo.cpp
new file mode 100644
index 0000000000..b2149c9f63
--- /dev/null
+++ b/gfx/angle/checkout/src/gpu_info_util/SystemInfo.cpp
@@ -0,0 +1,418 @@
+//
+// Copyright 2013 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 <iostream>
+#include <sstream>
+
+#include "anglebase/no_destructor.h"
+#include "common/debug.h"
+#include "common/string_utils.h"
+#include "common/system_utils.h"
+
+namespace angle
+{
+namespace
+{
+constexpr char kANGLEPreferredDeviceEnv[] = "ANGLE_PREFERRED_DEVICE";
+}
+
+std::string VendorName(VendorID vendor)
+{
+ switch (vendor)
+ {
+ case kVendorID_AMD:
+ return "AMD";
+ case kVendorID_ARM:
+ return "ARM";
+ case kVendorID_Broadcom:
+ return "Broadcom";
+ case kVendorID_GOOGLE:
+ return "Google";
+ case kVendorID_ImgTec:
+ return "ImgTec";
+ case kVendorID_Intel:
+ return "Intel";
+ case kVendorID_Kazan:
+ return "Kazan";
+ case kVendorID_NVIDIA:
+ return "NVIDIA";
+ case kVendorID_Qualcomm:
+ return "Qualcomm";
+ case kVendorID_VeriSilicon:
+ return "VeriSilicon";
+ case kVendorID_Vivante:
+ return "Vivante";
+ case kVendorID_VMWare:
+ return "VMWare";
+ case kVendorID_Apple:
+ return "Apple";
+ case kVendorID_Microsoft:
+ return "Microsoft";
+ default:
+ return "Unknown (" + std::to_string(vendor) + ")";
+ }
+}
+
+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 SystemInfo::hasNVIDIAGPU() const
+{
+ for (const GPUDeviceInfo &gpu : gpus)
+ {
+ if (IsNVIDIA(gpu.vendorId))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SystemInfo::hasIntelGPU() const
+{
+ for (const GPUDeviceInfo &gpu : gpus)
+ {
+ if (IsIntel(gpu.vendorId))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SystemInfo::hasAMDGPU() const
+{
+ for (const GPUDeviceInfo &gpu : gpus)
+ {
+ if (IsAMD(gpu.vendorId))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::optional<size_t> SystemInfo::getPreferredGPUIndex() const
+{
+ std::string device = GetPreferredDeviceString();
+ if (!device.empty())
+ {
+ for (size_t i = 0; i < gpus.size(); ++i)
+ {
+ std::string vendor = VendorName(gpus[i].vendorId);
+ ToLower(&vendor);
+ if (vendor == device)
+ return i;
+ }
+ }
+ return std::nullopt;
+}
+
+bool IsAMD(VendorID vendorId)
+{
+ return vendorId == kVendorID_AMD;
+}
+
+bool IsARM(VendorID vendorId)
+{
+ return vendorId == kVendorID_ARM;
+}
+
+bool IsBroadcom(VendorID vendorId)
+{
+ return vendorId == kVendorID_Broadcom;
+}
+
+bool IsImgTec(VendorID vendorId)
+{
+ return vendorId == kVendorID_ImgTec;
+}
+
+bool IsKazan(VendorID vendorId)
+{
+ return vendorId == kVendorID_Kazan;
+}
+
+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 IsGoogle(VendorID vendorId)
+{
+ return vendorId == kVendorID_GOOGLE;
+}
+
+bool IsVeriSilicon(VendorID vendorId)
+{
+ return vendorId == kVendorID_VeriSilicon;
+}
+
+bool IsVMWare(VendorID vendorId)
+{
+ return vendorId == kVendorID_VMWare;
+}
+
+bool IsVivante(VendorID vendorId)
+{
+ return vendorId == kVendorID_Vivante;
+}
+
+bool IsApple(VendorID vendorId)
+{
+ return vendorId == kVendorID_Apple;
+}
+
+bool IsMicrosoft(VendorID vendorId)
+{
+ return vendorId == kVendorID_Microsoft;
+}
+
+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 = static_cast<int32_t>(std::strtol(numberPtr, &endPtr, 10));
+ if (endPtr == numberPtr)
+ {
+ return false;
+ }
+
+ int32_t minorTmp = static_cast<int32_t>(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 GetDualGPUInfo(SystemInfo *info)
+{
+ ASSERT(!info->gpus.empty());
+
+ // On dual-GPU systems we assume the non-Intel GPU is the graphics one.
+ // TODO: this is incorrect and problematic. activeGPUIndex must be removed if it cannot be
+ // determined correctly. A potential solution is to create an OpenGL context and parse
+ // GL_VENDOR. Currently, our test infrastructure is relying on this information and incorrectly
+ // applies test expectations on dual-GPU systems when the Intel GPU is active.
+ // http://anglebug.com/6174.
+ int active = 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[active].vendorId))
+ {
+ active = static_cast<int>(i);
+ }
+ }
+
+ // Assume that a combination of NVIDIA or AMD with Intel means Optimus or AMD Switchable
+ info->activeGPUIndex = active;
+ info->isOptimus = hasIntel && IsNVIDIA(info->gpus[active].vendorId);
+ info->isAMDSwitchable = hasIntel && IsAMD(info->gpus[active].vendorId);
+}
+
+void PrintSystemInfo(const SystemInfo &info)
+{
+ std::cout << info.gpus.size() << " GPUs:\n";
+
+ for (size_t i = 0; i < info.gpus.size(); i++)
+ {
+ const auto &gpu = info.gpus[i];
+
+ std::cout << " " << i << " - " << VendorName(gpu.vendorId) << " device id: 0x" << std::hex
+ << std::uppercase << gpu.deviceId << std::dec << ", revision id: 0x" << std::hex
+ << std::uppercase << gpu.revisionId << std::dec << ", system device id: 0x"
+ << std::hex << std::uppercase << gpu.systemDeviceId << std::dec << "\n";
+ if (!gpu.driverVendor.empty())
+ {
+ std::cout << " Driver Vendor: " << gpu.driverVendor << "\n";
+ }
+ if (!gpu.driverVersion.empty())
+ {
+ std::cout << " Driver Version: " << gpu.driverVersion << "\n";
+ }
+ if (!gpu.driverDate.empty())
+ {
+ std::cout << " Driver Date: " << gpu.driverDate << "\n";
+ }
+ if (gpu.detailedDriverVersion.major != 0 || gpu.detailedDriverVersion.minor != 0 ||
+ gpu.detailedDriverVersion.subMinor != 0 || gpu.detailedDriverVersion.patch != 0)
+ {
+ std::cout << " Detailed Driver Version:\n"
+ << " major: " << gpu.detailedDriverVersion.major
+ << " minor: " << gpu.detailedDriverVersion.minor
+ << " subMinor: " << gpu.detailedDriverVersion.subMinor
+ << " patch: " << gpu.detailedDriverVersion.patch << "\n";
+ }
+ }
+
+ std::cout << "\n";
+ std::cout << "Active GPU: " << info.activeGPUIndex << "\n";
+
+ std::cout << "\n";
+ std::cout << "Optimus: " << (info.isOptimus ? "true" : "false") << "\n";
+ std::cout << "AMD Switchable: " << (info.isAMDSwitchable ? "true" : "false") << "\n";
+ std::cout << "Mac Switchable: " << (info.isMacSwitchable ? "true" : "false") << "\n";
+ std::cout << "Needs EAGL on Mac: " << (info.needsEAGLOnMac ? "true" : "false") << "\n";
+
+ std::cout << "\n";
+ if (!info.machineManufacturer.empty())
+ {
+ std::cout << "Machine Manufacturer: " << info.machineManufacturer << "\n";
+ }
+ if (info.androidSdkLevel != 0)
+ {
+ std::cout << "Android SDK Level: " << info.androidSdkLevel << "\n";
+ }
+ if (!info.machineModelName.empty())
+ {
+ std::cout << "Machine Model: " << info.machineModelName << "\n";
+ }
+ if (!info.machineModelVersion.empty())
+ {
+ std::cout << "Machine Model Version: " << info.machineModelVersion << "\n";
+ }
+ std::cout << std::endl;
+}
+
+VersionInfo ParseNvidiaDriverVersion(uint32_t version)
+{
+ return {
+ version >> 22, // major
+ version >> 14 & 0xff, // minor
+ version >> 6 & 0xff, // subMinor
+ version & 0x3f // patch
+ };
+}
+
+uint64_t GetSystemDeviceIdFromParts(uint32_t highPart, uint32_t lowPart)
+{
+ return (static_cast<uint64_t>(highPart) << 32) | lowPart;
+}
+
+uint32_t GetSystemDeviceIdHighPart(uint64_t systemDeviceId)
+{
+ return (systemDeviceId >> 32) & 0xffffffff;
+}
+
+uint32_t GetSystemDeviceIdLowPart(uint64_t systemDeviceId)
+{
+ return systemDeviceId & 0xffffffff;
+}
+
+std::string GetPreferredDeviceString()
+{
+ std::string device = angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv);
+ ToLower(&device);
+ return device;
+}
+
+} // namespace angle
diff --git a/gfx/angle/checkout/src/gpu_info_util/SystemInfo.h b/gfx/angle/checkout/src/gpu_info_util/SystemInfo.h
new file mode 100644
index 0000000000..7347404ae7
--- /dev/null
+++ b/gfx/angle/checkout/src/gpu_info_util/SystemInfo.h
@@ -0,0 +1,179 @@
+//
+// Copyright 2013 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 <optional>
+#include <string>
+#include <vector>
+
+namespace angle
+{
+
+using VendorID = uint32_t;
+using DeviceID = uint32_t;
+using RevisionID = uint32_t;
+using SystemDeviceID = uint64_t;
+using DriverID = uint32_t;
+
+struct VersionInfo
+{
+ uint32_t major = 0;
+ uint32_t minor = 0;
+ uint32_t subMinor = 0;
+ uint32_t patch = 0;
+};
+
+struct GPUDeviceInfo
+{
+ GPUDeviceInfo();
+ ~GPUDeviceInfo();
+
+ GPUDeviceInfo(const GPUDeviceInfo &other);
+
+ VendorID vendorId = 0;
+ DeviceID deviceId = 0;
+ RevisionID revisionId = 0;
+ SystemDeviceID systemDeviceId = 0;
+
+ std::string driverVendor;
+ std::string driverVersion;
+ std::string driverDate;
+
+ // Fields only available via GetSystemInfoVulkan:
+ VersionInfo detailedDriverVersion;
+ DriverID driverId = 0;
+ uint32_t driverApiVersion = 0;
+};
+
+struct SystemInfo
+{
+ SystemInfo();
+ ~SystemInfo();
+
+ SystemInfo(const SystemInfo &other);
+
+ bool hasNVIDIAGPU() const;
+ bool hasIntelGPU() const;
+ bool hasAMDGPU() const;
+
+ // Returns the index to `gpus` if the entry matches the preferred device string.
+ std::optional<size_t> getPreferredGPUIndex() const;
+
+ std::vector<GPUDeviceInfo> gpus;
+
+ // Index of the GPU expected to be used for 3D graphics. Based on a best-guess heuristic on
+ // some platforms. On Windows, this is accurate. Note `gpus` must be checked for empty before
+ // indexing.
+ int activeGPUIndex = 0;
+
+ bool isOptimus = false;
+ bool isAMDSwitchable = false;
+ // Only true on dual-GPU Mac laptops.
+ bool isMacSwitchable = false;
+ // Only true on Apple Silicon Macs when running in macCatalyst.
+ bool needsEAGLOnMac = false;
+
+ // Only available on Android
+ std::string machineManufacturer;
+ int androidSdkLevel = 0;
+
+ // Only available on macOS and Android
+ std::string machineModelName;
+
+ // Only available on macOS
+ std::string machineModelVersion;
+};
+
+// Gathers information about the system without starting a GPU driver and returns them in `info`.
+// Returns true if all info was gathered, false otherwise. Even when false is returned, `info` will
+// be filled with partial information.
+bool GetSystemInfo(SystemInfo *info);
+
+// Vulkan-specific info collection.
+bool GetSystemInfoVulkan(SystemInfo *info);
+
+// Known PCI vendor IDs
+constexpr VendorID kVendorID_AMD = 0x1002;
+constexpr VendorID kVendorID_ARM = 0x13B5;
+constexpr VendorID kVendorID_Broadcom = 0x14E4;
+constexpr VendorID kVendorID_GOOGLE = 0x1AE0;
+constexpr VendorID kVendorID_ImgTec = 0x1010;
+constexpr VendorID kVendorID_Intel = 0x8086;
+constexpr VendorID kVendorID_NVIDIA = 0x10DE;
+constexpr VendorID kVendorID_Qualcomm = 0x5143;
+constexpr VendorID kVendorID_VMWare = 0x15ad;
+constexpr VendorID kVendorID_Apple = 0x106B;
+constexpr VendorID kVendorID_Microsoft = 0x1414;
+
+// Known non-PCI (i.e. Khronos-registered) vendor IDs
+constexpr VendorID kVendorID_Vivante = 0x10001;
+constexpr VendorID kVendorID_VeriSilicon = 0x10002;
+constexpr VendorID kVendorID_Kazan = 0x10003;
+constexpr VendorID kVendorID_CodePlay = 0x10004;
+constexpr VendorID kVendorID_Mesa = 0x10005;
+constexpr VendorID kVendorID_PoCL = 0x10006;
+
+// Known device IDs
+constexpr DeviceID kDeviceID_Swiftshader = 0xC0DE;
+constexpr DeviceID kDeviceID_Adreno540 = 0x5040001;
+constexpr DeviceID kDeviceID_UHD630Mobile = 0x3E9B;
+
+// Predicates on vendor IDs
+bool IsAMD(VendorID vendorId);
+bool IsARM(VendorID vendorId);
+bool IsBroadcom(VendorID vendorId);
+bool IsImgTec(VendorID vendorId);
+bool IsIntel(VendorID vendorId);
+bool IsKazan(VendorID vendorId);
+bool IsNVIDIA(VendorID vendorId);
+bool IsQualcomm(VendorID vendorId);
+bool IsGoogle(VendorID vendorId);
+bool IsSwiftshader(VendorID vendorId);
+bool IsVeriSilicon(VendorID vendorId);
+bool IsVMWare(VendorID vendorId);
+bool IsVivante(VendorID vendorId);
+bool IsApple(VendorID vendorId);
+bool IsMicrosoft(VendorID vendorId);
+
+// Returns a readable vendor name given the VendorID
+std::string VendorName(VendorID vendor);
+
+// Use a heuristic to attempt to find the GPU used for 3D graphics. Sets activeGPUIndex,
+// isOptimus, and isAMDSwitchable.
+// Always assumes the non-Intel GPU is active on dual-GPU machines.
+void GetDualGPUInfo(SystemInfo *info);
+
+// Dumps the system info to stdout.
+void PrintSystemInfo(const SystemInfo &info);
+
+VersionInfo ParseNvidiaDriverVersion(uint32_t version);
+
+#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
+// Helper to get the active GPU ID from a given Core Graphics display ID.
+uint64_t GetGpuIDFromDisplayID(uint32_t displayID);
+
+// Helper to get the active GPU ID from an OpenGL display mask.
+uint64_t GetGpuIDFromOpenGLDisplayMask(uint32_t displayMask);
+
+// Get VendorID from metal device's registry ID
+VendorID GetVendorIDFromMetalDeviceRegistryID(uint64_t registryID);
+#endif
+
+uint64_t GetSystemDeviceIdFromParts(uint32_t highPart, uint32_t lowPart);
+uint32_t GetSystemDeviceIdHighPart(uint64_t systemDeviceId);
+uint32_t GetSystemDeviceIdLowPart(uint64_t systemDeviceId);
+
+// Returns lower-case of ANGLE_PREFERRED_DEVICE environment variable contents.
+std::string GetPreferredDeviceString();
+
+} // namespace angle
+
+#endif // GPU_INFO_UTIL_SYSTEM_INFO_H_
diff --git a/gfx/angle/checkout/src/gpu_info_util/SystemInfo_internal.h b/gfx/angle/checkout/src/gpu_info_util/SystemInfo_internal.h
new file mode 100644
index 0000000000..d300bd81a9
--- /dev/null
+++ b/gfx/angle/checkout/src/gpu_info_util/SystemInfo_internal.h
@@ -0,0 +1,42 @@
+//
+// Copyright 2013 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);
+
+#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
+bool GetSystemInfo_mac(SystemInfo *info);
+#endif
+
+#if defined(ANGLE_PLATFORM_IOS) || (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
+bool GetSystemInfo_ios(SystemInfo *info);
+#endif
+
+} // namespace angle
+
+#endif // GPU_INFO_UTIL_SYSTEM_INFO_INTERNAL_H_
diff --git a/gfx/angle/checkout/src/gpu_info_util/SystemInfo_vulkan.cpp b/gfx/angle/checkout/src/gpu_info_util/SystemInfo_vulkan.cpp
new file mode 100644
index 0000000000..96b6019fd3
--- /dev/null
+++ b/gfx/angle/checkout/src/gpu_info_util/SystemInfo_vulkan.cpp
@@ -0,0 +1,284 @@
+//
+// Copyright 2020 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_vulkan.cpp: Generic vulkan implementation of SystemInfo.h
+// TODO: Use VK_KHR_driver_properties. http://anglebug.com/5103
+
+#include "gpu_info_util/SystemInfo_vulkan.h"
+
+#include <vulkan/vulkan.h>
+#include "gpu_info_util/SystemInfo_internal.h"
+
+#include <cstring>
+#include <fstream>
+
+#include "common/angleutils.h"
+#include "common/debug.h"
+#include "common/system_utils.h"
+#include "common/vulkan/libvulkan_loader.h"
+
+namespace angle
+{
+class VulkanLibrary final : NonCopyable
+{
+ public:
+ VulkanLibrary() = default;
+
+ ~VulkanLibrary()
+ {
+ if (mInstance != VK_NULL_HANDLE)
+ {
+ auto pfnDestroyInstance = getProc<PFN_vkDestroyInstance>("vkDestroyInstance");
+ if (pfnDestroyInstance)
+ {
+ pfnDestroyInstance(mInstance, nullptr);
+ }
+ }
+
+ CloseSystemLibrary(mLibVulkan);
+ }
+
+ VkInstance getVulkanInstance()
+ {
+ mLibVulkan = vk::OpenLibVulkan();
+ if (!mLibVulkan)
+ {
+ // If Vulkan doesn't exist, bail-out early:
+ return VK_NULL_HANDLE;
+ }
+
+ // Determine the available Vulkan instance version:
+ uint32_t instanceVersion = VK_API_VERSION_1_0;
+#if defined(VK_VERSION_1_1)
+ auto pfnEnumerateInstanceVersion =
+ getProc<PFN_vkEnumerateInstanceVersion>("vkEnumerateInstanceVersion");
+ if (!pfnEnumerateInstanceVersion ||
+ pfnEnumerateInstanceVersion(&instanceVersion) != VK_SUCCESS)
+ {
+ instanceVersion = VK_API_VERSION_1_0;
+ }
+#endif // VK_VERSION_1_1
+
+ // Create a Vulkan instance:
+ VkApplicationInfo appInfo;
+ appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ appInfo.pNext = nullptr;
+ appInfo.pApplicationName = "";
+ appInfo.applicationVersion = 1;
+ appInfo.pEngineName = "";
+ appInfo.engineVersion = 1;
+ appInfo.apiVersion = instanceVersion;
+
+ VkInstanceCreateInfo createInstanceInfo;
+ createInstanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ createInstanceInfo.pNext = nullptr;
+ createInstanceInfo.flags = 0;
+ createInstanceInfo.pApplicationInfo = &appInfo;
+ createInstanceInfo.enabledLayerCount = 0;
+ createInstanceInfo.ppEnabledLayerNames = nullptr;
+ createInstanceInfo.enabledExtensionCount = 0;
+ createInstanceInfo.ppEnabledExtensionNames = nullptr;
+
+ auto pfnCreateInstance = getProc<PFN_vkCreateInstance>("vkCreateInstance");
+ if (!pfnCreateInstance ||
+ pfnCreateInstance(&createInstanceInfo, nullptr, &mInstance) != VK_SUCCESS)
+ {
+ return VK_NULL_HANDLE;
+ }
+
+ return mInstance;
+ }
+
+ template <typename Func>
+ Func getProc(const char *fn) const
+ {
+ return reinterpret_cast<Func>(angle::GetLibrarySymbol(mLibVulkan, fn));
+ }
+
+ private:
+ void *mLibVulkan = nullptr;
+ VkInstance mInstance = VK_NULL_HANDLE;
+};
+
+ANGLE_FORMAT_PRINTF(1, 2)
+std::string FormatString(const char *fmt, ...)
+{
+ va_list vararg;
+ va_start(vararg, fmt);
+
+ std::vector<char> buffer;
+ size_t len = FormatStringIntoVector(fmt, vararg, buffer);
+ va_end(vararg);
+
+ return std::string(&buffer[0], len);
+}
+
+bool GetSystemInfoVulkan(SystemInfo *info)
+{
+ return GetSystemInfoVulkanWithICD(info, vk::ICD::Default);
+}
+
+bool GetSystemInfoVulkanWithICD(SystemInfo *info, vk::ICD preferredICD)
+{
+ const bool enableValidationLayers = false;
+ vk::ScopedVkLoaderEnvironment scopedEnvironment(enableValidationLayers, preferredICD);
+
+ // This implementation builds on top of the Vulkan API, but cannot assume the existence of the
+ // Vulkan library. ANGLE can be installed on versions of Android as old as Ice Cream Sandwich.
+ // Therefore, we need to use dlopen()/dlsym() in order to see if Vulkan is installed on the
+ // system, and if so, to use it:
+ VulkanLibrary vkLibrary;
+ VkInstance instance = vkLibrary.getVulkanInstance();
+ if (instance == VK_NULL_HANDLE)
+ {
+ // If Vulkan doesn't exist, bail-out early:
+ return false;
+ }
+
+ // Enumerate the Vulkan physical devices, which are ANGLE gpus:
+ auto pfnEnumeratePhysicalDevices =
+ vkLibrary.getProc<PFN_vkEnumeratePhysicalDevices>("vkEnumeratePhysicalDevices");
+ auto pfnGetPhysicalDeviceProperties =
+ vkLibrary.getProc<PFN_vkGetPhysicalDeviceProperties>("vkGetPhysicalDeviceProperties");
+ auto pfnGetPhysicalDeviceProperties2 =
+ vkLibrary.getProc<PFN_vkGetPhysicalDeviceProperties2>("vkGetPhysicalDeviceProperties2");
+ uint32_t physicalDeviceCount = 0;
+ if (!pfnEnumeratePhysicalDevices || !pfnGetPhysicalDeviceProperties ||
+ pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr) != VK_SUCCESS)
+ {
+ return false;
+ }
+ std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
+ if (pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data()) !=
+ VK_SUCCESS)
+ {
+ return false;
+ }
+
+ // If we get to here, we will likely provide a valid answer (unless an unknown vendorID):
+ info->gpus.resize(physicalDeviceCount);
+
+ for (uint32_t i = 0; i < physicalDeviceCount; i++)
+ {
+ VkPhysicalDeviceDriverProperties driverProperties = {};
+ driverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
+
+ VkPhysicalDeviceProperties2 properties2 = {};
+ properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ properties2.pNext = &driverProperties;
+
+ VkPhysicalDeviceProperties &properties = properties2.properties;
+ pfnGetPhysicalDeviceProperties(physicalDevices[i], &properties);
+
+ // vkGetPhysicalDeviceProperties2() is supported since 1.1
+ // Use vkGetPhysicalDeviceProperties2() to get driver information.
+ if (properties.apiVersion >= VK_API_VERSION_1_1)
+ {
+ pfnGetPhysicalDeviceProperties2(physicalDevices[i], &properties2);
+ }
+
+ // Fill in data for a given physical device (a.k.a. gpu):
+ GPUDeviceInfo &gpu = info->gpus[i];
+ gpu.vendorId = properties.vendorID;
+ gpu.deviceId = properties.deviceID;
+ // Need to parse/re-format properties.driverVersion.
+ //
+ // TODO(ianelliott): Determine the formatting used for each vendor
+ // (http://anglebug.com/2677)
+ // TODO(http://anglebug.com/7677): Use driverID instead of the hardware vendorID to detect
+ // driveVendor, etc.
+ switch (properties.vendorID)
+ {
+ case kVendorID_AMD:
+ gpu.driverVendor = "Advanced Micro Devices, Inc";
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ break;
+ case kVendorID_ARM:
+ gpu.driverVendor = "Arm Holdings";
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ break;
+ case kVendorID_Broadcom:
+ gpu.driverVendor = "Broadcom";
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ break;
+ case kVendorID_GOOGLE:
+ gpu.driverVendor = "Google";
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ break;
+ case kVendorID_ImgTec:
+ gpu.driverVendor = "Imagination Technologies Limited";
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ break;
+ case kVendorID_Intel:
+ gpu.driverVendor = "Intel Corporation";
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ break;
+ case kVendorID_Kazan:
+ gpu.driverVendor = "Kazan Software";
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ break;
+ case kVendorID_NVIDIA:
+ gpu.driverVendor = "NVIDIA Corporation";
+ gpu.driverVersion = FormatString("%d.%d.%d.%d", properties.driverVersion >> 22,
+ (properties.driverVersion >> 14) & 0XFF,
+ (properties.driverVersion >> 6) & 0XFF,
+ properties.driverVersion & 0x3F);
+ gpu.detailedDriverVersion.major = properties.driverVersion >> 22;
+ gpu.detailedDriverVersion.minor = (properties.driverVersion >> 14) & 0xFF;
+ gpu.detailedDriverVersion.subMinor = (properties.driverVersion >> 6) & 0xFF;
+ gpu.detailedDriverVersion.patch = properties.driverVersion & 0x3F;
+ break;
+ case kVendorID_Qualcomm:
+ gpu.driverVendor = "Qualcomm Technologies, Inc";
+ if (properties.driverVersion & 0x80000000)
+ {
+ gpu.driverVersion = FormatString("%d.%d.%d", properties.driverVersion >> 22,
+ (properties.driverVersion >> 12) & 0X3FF,
+ properties.driverVersion & 0xFFF);
+ gpu.detailedDriverVersion.major = properties.driverVersion >> 22;
+ gpu.detailedDriverVersion.minor = (properties.driverVersion >> 12) & 0x3FF;
+ gpu.detailedDriverVersion.subMinor = properties.driverVersion & 0xFFF;
+ }
+ else
+ {
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ }
+ break;
+ case kVendorID_VeriSilicon:
+ gpu.driverVendor = "VeriSilicon";
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ break;
+ case kVendorID_Vivante:
+ gpu.driverVendor = "Vivante";
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ break;
+ case kVendorID_Mesa:
+ gpu.driverVendor = "Mesa";
+ gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
+ gpu.detailedDriverVersion.major = properties.driverVersion;
+ break;
+ default:
+ return false;
+ }
+ gpu.driverId = static_cast<DriverID>(driverProperties.driverID);
+ gpu.driverApiVersion = properties.apiVersion;
+ gpu.driverDate = "";
+ }
+
+ return true;
+}
+
+} // namespace angle
diff --git a/gfx/angle/checkout/src/gpu_info_util/SystemInfo_vulkan.h b/gfx/angle/checkout/src/gpu_info_util/SystemInfo_vulkan.h
new file mode 100644
index 0000000000..10c7d69295
--- /dev/null
+++ b/gfx/angle/checkout/src/gpu_info_util/SystemInfo_vulkan.h
@@ -0,0 +1,23 @@
+//
+// Copyright 2020 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_vulkan.h: Reusable Vulkan implementation for SystemInfo.h
+
+#ifndef GPU_INFO_UTIL_SYSTEM_INFO_VULKAN_H_
+#define GPU_INFO_UTIL_SYSTEM_INFO_VULKAN_H_
+
+#include "common/vulkan/vulkan_icd.h"
+
+namespace angle
+{
+struct SystemInfo;
+
+// Reusable vulkan implementation of GetSystemInfo(). See SystemInfo.h.
+bool GetSystemInfoVulkan(SystemInfo *info);
+bool GetSystemInfoVulkanWithICD(SystemInfo *info, vk::ICD preferredICD);
+} // namespace angle
+
+#endif // GPU_INFO_UTIL_SYSTEM_INFO_VULKAN_H_
diff --git a/gfx/angle/checkout/src/gpu_info_util/SystemInfo_win.cpp b/gfx/angle/checkout/src/gpu_info_util/SystemInfo_win.cpp
new file mode 100644
index 0000000000..291acc1ef0
--- /dev/null
+++ b/gfx/angle/checkout/src/gpu_info_util/SystemInfo_win.cpp
@@ -0,0 +1,117 @@
+//
+// Copyright 2013 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>
+
+#include <dxgi.h>
+
+#include <array>
+#include <sstream>
+
+namespace angle
+{
+
+namespace
+{
+
+bool GetDevicesFromDXGI(std::vector<GPUDeviceInfo> *devices)
+{
+#if defined(ANGLE_ENABLE_WINDOWS_UWP)
+ IDXGIFactory1 *factory;
+ if (!SUCCEEDED(
+ CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void **>(&factory))))
+ {
+ return false;
+ }
+#else
+ IDXGIFactory *factory;
+ if (!SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&factory))))
+ {
+ return false;
+ }
+#endif
+
+ 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(IDXGIDevice), &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;
+
+ constexpr uint64_t kMask16 = std::numeric_limits<uint16_t>::max();
+ o << ((intVersion >> 48) & kMask16) << ".";
+ o << ((intVersion >> 32) & kMask16) << ".";
+ o << ((intVersion >> 16) & kMask16) << ".";
+ o << (intVersion & kMask16);
+
+ GPUDeviceInfo device;
+ device.vendorId = desc.VendorId;
+ device.deviceId = desc.DeviceId;
+ device.driverVersion = o.str();
+ device.systemDeviceId =
+ GetSystemDeviceIdFromParts(desc.AdapterLuid.HighPart, desc.AdapterLuid.LowPart);
+
+ devices->push_back(device);
+
+ adapter->Release();
+ }
+
+ factory->Release();
+
+ return (i > 0);
+}
+
+} // anonymous namespace
+
+bool GetSystemInfo(SystemInfo *info)
+{
+ if (!GetDevicesFromDXGI(&info->gpus))
+ {
+ return false;
+ }
+
+ if (info->gpus.size() == 0)
+ {
+ return false;
+ }
+
+ // Call GetDualGPUInfo to populate activeGPUIndex, isOptimus, and isAMDSwitchable.
+ GetDualGPUInfo(info);
+
+ // Override activeGPUIndex. The first index returned by EnumAdapters is the active GPU. We
+ // can override the heuristic to find the active GPU
+ info->activeGPUIndex = 0;
+
+#if !defined(ANGLE_ENABLE_WINDOWS_UWP)
+ // Override isOptimus. nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
+ HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
+ info->isOptimus = nvd3d9wrap != nullptr;
+#endif
+
+ return true;
+}
+
+} // namespace angle