SystemInfo_vulkan.cpp (12058B)
1 // 2 // Copyright 2020 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // SystemInfo_vulkan.cpp: Generic vulkan implementation of SystemInfo.h 8 // TODO: Use VK_KHR_driver_properties. http://anglebug.com/5103 9 10 #include "gpu_info_util/SystemInfo_vulkan.h" 11 12 #include <vulkan/vulkan.h> 13 #include "gpu_info_util/SystemInfo_internal.h" 14 15 #include <cstring> 16 #include <fstream> 17 18 #include "common/angleutils.h" 19 #include "common/debug.h" 20 #include "common/system_utils.h" 21 #include "common/vulkan/libvulkan_loader.h" 22 23 namespace angle 24 { 25 class VulkanLibrary final : NonCopyable 26 { 27 public: 28 VulkanLibrary() = default; 29 30 ~VulkanLibrary() 31 { 32 if (mInstance != VK_NULL_HANDLE) 33 { 34 auto pfnDestroyInstance = getProc<PFN_vkDestroyInstance>("vkDestroyInstance"); 35 if (pfnDestroyInstance) 36 { 37 pfnDestroyInstance(mInstance, nullptr); 38 } 39 } 40 41 CloseSystemLibrary(mLibVulkan); 42 } 43 44 VkInstance getVulkanInstance() 45 { 46 mLibVulkan = vk::OpenLibVulkan(); 47 if (!mLibVulkan) 48 { 49 // If Vulkan doesn't exist, bail-out early: 50 return VK_NULL_HANDLE; 51 } 52 53 // Determine the available Vulkan instance version: 54 uint32_t instanceVersion = VK_API_VERSION_1_0; 55 #if defined(VK_VERSION_1_1) 56 auto pfnEnumerateInstanceVersion = 57 getProc<PFN_vkEnumerateInstanceVersion>("vkEnumerateInstanceVersion"); 58 if (!pfnEnumerateInstanceVersion || 59 pfnEnumerateInstanceVersion(&instanceVersion) != VK_SUCCESS) 60 { 61 instanceVersion = VK_API_VERSION_1_0; 62 } 63 #endif // VK_VERSION_1_1 64 65 // Create a Vulkan instance: 66 VkApplicationInfo appInfo; 67 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 68 appInfo.pNext = nullptr; 69 appInfo.pApplicationName = ""; 70 appInfo.applicationVersion = 1; 71 appInfo.pEngineName = ""; 72 appInfo.engineVersion = 1; 73 appInfo.apiVersion = instanceVersion; 74 75 VkInstanceCreateInfo createInstanceInfo; 76 createInstanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 77 createInstanceInfo.pNext = nullptr; 78 createInstanceInfo.flags = 0; 79 createInstanceInfo.pApplicationInfo = &appInfo; 80 createInstanceInfo.enabledLayerCount = 0; 81 createInstanceInfo.ppEnabledLayerNames = nullptr; 82 createInstanceInfo.enabledExtensionCount = 0; 83 createInstanceInfo.ppEnabledExtensionNames = nullptr; 84 85 auto pfnCreateInstance = getProc<PFN_vkCreateInstance>("vkCreateInstance"); 86 if (!pfnCreateInstance || 87 pfnCreateInstance(&createInstanceInfo, nullptr, &mInstance) != VK_SUCCESS) 88 { 89 return VK_NULL_HANDLE; 90 } 91 92 return mInstance; 93 } 94 95 template <typename Func> 96 Func getProc(const char *fn) const 97 { 98 return reinterpret_cast<Func>(angle::GetLibrarySymbol(mLibVulkan, fn)); 99 } 100 101 private: 102 void *mLibVulkan = nullptr; 103 VkInstance mInstance = VK_NULL_HANDLE; 104 }; 105 106 ANGLE_FORMAT_PRINTF(1, 2) 107 std::string FormatString(const char *fmt, ...) 108 { 109 va_list vararg; 110 va_start(vararg, fmt); 111 112 std::vector<char> buffer; 113 size_t len = FormatStringIntoVector(fmt, vararg, buffer); 114 va_end(vararg); 115 116 return std::string(&buffer[0], len); 117 } 118 119 bool GetSystemInfoVulkan(SystemInfo *info) 120 { 121 return GetSystemInfoVulkanWithICD(info, vk::ICD::Default); 122 } 123 124 bool GetSystemInfoVulkanWithICD(SystemInfo *info, vk::ICD preferredICD) 125 { 126 const bool enableValidationLayers = false; 127 vk::ScopedVkLoaderEnvironment scopedEnvironment(enableValidationLayers, preferredICD); 128 129 // This implementation builds on top of the Vulkan API, but cannot assume the existence of the 130 // Vulkan library. ANGLE can be installed on versions of Android as old as Ice Cream Sandwich. 131 // Therefore, we need to use dlopen()/dlsym() in order to see if Vulkan is installed on the 132 // system, and if so, to use it: 133 VulkanLibrary vkLibrary; 134 VkInstance instance = vkLibrary.getVulkanInstance(); 135 if (instance == VK_NULL_HANDLE) 136 { 137 // If Vulkan doesn't exist, bail-out early: 138 return false; 139 } 140 141 // Enumerate the Vulkan physical devices, which are ANGLE gpus: 142 auto pfnEnumeratePhysicalDevices = 143 vkLibrary.getProc<PFN_vkEnumeratePhysicalDevices>("vkEnumeratePhysicalDevices"); 144 auto pfnGetPhysicalDeviceProperties = 145 vkLibrary.getProc<PFN_vkGetPhysicalDeviceProperties>("vkGetPhysicalDeviceProperties"); 146 auto pfnGetPhysicalDeviceProperties2 = 147 vkLibrary.getProc<PFN_vkGetPhysicalDeviceProperties2>("vkGetPhysicalDeviceProperties2"); 148 uint32_t physicalDeviceCount = 0; 149 if (!pfnEnumeratePhysicalDevices || !pfnGetPhysicalDeviceProperties || 150 pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr) != VK_SUCCESS) 151 { 152 return false; 153 } 154 std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount); 155 if (pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data()) != 156 VK_SUCCESS) 157 { 158 return false; 159 } 160 161 // If we get to here, we will likely provide a valid answer (unless an unknown vendorID): 162 info->gpus.resize(physicalDeviceCount); 163 164 for (uint32_t i = 0; i < physicalDeviceCount; i++) 165 { 166 VkPhysicalDeviceDriverProperties driverProperties = {}; 167 driverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; 168 169 VkPhysicalDeviceProperties2 properties2 = {}; 170 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 171 properties2.pNext = &driverProperties; 172 173 VkPhysicalDeviceProperties &properties = properties2.properties; 174 pfnGetPhysicalDeviceProperties(physicalDevices[i], &properties); 175 176 // vkGetPhysicalDeviceProperties2() is supported since 1.1 177 // Use vkGetPhysicalDeviceProperties2() to get driver information. 178 if (properties.apiVersion >= VK_API_VERSION_1_1) 179 { 180 pfnGetPhysicalDeviceProperties2(physicalDevices[i], &properties2); 181 } 182 183 // Fill in data for a given physical device (a.k.a. gpu): 184 GPUDeviceInfo &gpu = info->gpus[i]; 185 gpu.vendorId = properties.vendorID; 186 gpu.deviceId = properties.deviceID; 187 // Need to parse/re-format properties.driverVersion. 188 // 189 // TODO(ianelliott): Determine the formatting used for each vendor 190 // (http://anglebug.com/2677) 191 // TODO(http://anglebug.com/7677): Use driverID instead of the hardware vendorID to detect 192 // driveVendor, etc. 193 switch (properties.vendorID) 194 { 195 case kVendorID_AMD: 196 gpu.driverVendor = "Advanced Micro Devices, Inc"; 197 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 198 gpu.detailedDriverVersion.major = properties.driverVersion; 199 break; 200 case kVendorID_ARM: 201 gpu.driverVendor = "Arm Holdings"; 202 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 203 gpu.detailedDriverVersion.major = properties.driverVersion; 204 break; 205 case kVendorID_Broadcom: 206 gpu.driverVendor = "Broadcom"; 207 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 208 gpu.detailedDriverVersion.major = properties.driverVersion; 209 break; 210 case kVendorID_GOOGLE: 211 gpu.driverVendor = "Google"; 212 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 213 gpu.detailedDriverVersion.major = properties.driverVersion; 214 break; 215 case kVendorID_ImgTec: 216 gpu.driverVendor = "Imagination Technologies Limited"; 217 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 218 gpu.detailedDriverVersion.major = properties.driverVersion; 219 break; 220 case kVendorID_Intel: 221 gpu.driverVendor = "Intel Corporation"; 222 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 223 gpu.detailedDriverVersion.major = properties.driverVersion; 224 break; 225 case kVendorID_Kazan: 226 gpu.driverVendor = "Kazan Software"; 227 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 228 gpu.detailedDriverVersion.major = properties.driverVersion; 229 break; 230 case kVendorID_NVIDIA: 231 gpu.driverVendor = "NVIDIA Corporation"; 232 gpu.driverVersion = FormatString("%d.%d.%d.%d", properties.driverVersion >> 22, 233 (properties.driverVersion >> 14) & 0XFF, 234 (properties.driverVersion >> 6) & 0XFF, 235 properties.driverVersion & 0x3F); 236 gpu.detailedDriverVersion.major = properties.driverVersion >> 22; 237 gpu.detailedDriverVersion.minor = (properties.driverVersion >> 14) & 0xFF; 238 gpu.detailedDriverVersion.subMinor = (properties.driverVersion >> 6) & 0xFF; 239 gpu.detailedDriverVersion.patch = properties.driverVersion & 0x3F; 240 break; 241 case kVendorID_Qualcomm: 242 gpu.driverVendor = "Qualcomm Technologies, Inc"; 243 if (properties.driverVersion & 0x80000000) 244 { 245 gpu.driverVersion = FormatString("%d.%d.%d", properties.driverVersion >> 22, 246 (properties.driverVersion >> 12) & 0X3FF, 247 properties.driverVersion & 0xFFF); 248 gpu.detailedDriverVersion.major = properties.driverVersion >> 22; 249 gpu.detailedDriverVersion.minor = (properties.driverVersion >> 12) & 0x3FF; 250 gpu.detailedDriverVersion.subMinor = properties.driverVersion & 0xFFF; 251 } 252 else 253 { 254 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 255 gpu.detailedDriverVersion.major = properties.driverVersion; 256 } 257 break; 258 case kVendorID_VeriSilicon: 259 gpu.driverVendor = "VeriSilicon"; 260 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 261 gpu.detailedDriverVersion.major = properties.driverVersion; 262 break; 263 case kVendorID_Vivante: 264 gpu.driverVendor = "Vivante"; 265 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 266 gpu.detailedDriverVersion.major = properties.driverVersion; 267 break; 268 case kVendorID_Mesa: 269 gpu.driverVendor = "Mesa"; 270 gpu.driverVersion = FormatString("0x%x", properties.driverVersion); 271 gpu.detailedDriverVersion.major = properties.driverVersion; 272 break; 273 default: 274 return false; 275 } 276 gpu.driverId = static_cast<DriverID>(driverProperties.driverID); 277 gpu.driverApiVersion = properties.apiVersion; 278 gpu.driverDate = ""; 279 } 280 281 return true; 282 } 283 284 } // namespace angle