// // 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 #include "gpu_info_util/SystemInfo_internal.h" #include #include #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("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("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("vkCreateInstance"); if (!pfnCreateInstance || pfnCreateInstance(&createInstanceInfo, nullptr, &mInstance) != VK_SUCCESS) { return VK_NULL_HANDLE; } return mInstance; } template Func getProc(const char *fn) const { return reinterpret_cast(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 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("vkEnumeratePhysicalDevices"); auto pfnGetPhysicalDeviceProperties = vkLibrary.getProc("vkGetPhysicalDeviceProperties"); auto pfnGetPhysicalDeviceProperties2 = vkLibrary.getProc("vkGetPhysicalDeviceProperties2"); uint32_t physicalDeviceCount = 0; if (!pfnEnumeratePhysicalDevices || !pfnGetPhysicalDeviceProperties || pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr) != VK_SUCCESS) { return false; } std::vector 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(driverProperties.driverID); gpu.driverApiVersion = properties.apiVersion; gpu.driverDate = ""; } return true; } } // namespace angle