diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /gfx/angle/checkout/src/gpu_info_util | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/angle/checkout/src/gpu_info_util')
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 |