• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~VulkanLibrary()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 
getVulkanInstance()42     VkInstance getVulkanInstance()
43     {
44         mLibVulkan = vk::OpenLibVulkan();
45         if (!mLibVulkan)
46         {
47             // If Vulkan doesn't exist, bail-out early:
48             return VK_NULL_HANDLE;
49         }
50 
51         // Determine the available Vulkan instance version:
52         uint32_t instanceVersion = VK_API_VERSION_1_0;
53 #if defined(VK_VERSION_1_1)
54         auto pfnEnumerateInstanceVersion =
55             getProc<PFN_vkEnumerateInstanceVersion>("vkEnumerateInstanceVersion");
56         if (!pfnEnumerateInstanceVersion ||
57             pfnEnumerateInstanceVersion(&instanceVersion) != VK_SUCCESS)
58         {
59             instanceVersion = VK_API_VERSION_1_0;
60         }
61 #endif  // VK_VERSION_1_1
62 
63         // Create a Vulkan instance:
64         VkApplicationInfo appInfo;
65         appInfo.sType              = VK_STRUCTURE_TYPE_APPLICATION_INFO;
66         appInfo.pNext              = nullptr;
67         appInfo.pApplicationName   = "";
68         appInfo.applicationVersion = 1;
69         appInfo.pEngineName        = "";
70         appInfo.engineVersion      = 1;
71         appInfo.apiVersion         = instanceVersion;
72 
73         VkInstanceCreateInfo createInstanceInfo;
74         createInstanceInfo.sType                   = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
75         createInstanceInfo.pNext                   = nullptr;
76         createInstanceInfo.flags                   = 0;
77         createInstanceInfo.pApplicationInfo        = &appInfo;
78         createInstanceInfo.enabledLayerCount       = 0;
79         createInstanceInfo.ppEnabledLayerNames     = nullptr;
80         createInstanceInfo.enabledExtensionCount   = 0;
81         createInstanceInfo.ppEnabledExtensionNames = nullptr;
82 
83         auto pfnCreateInstance = getProc<PFN_vkCreateInstance>("vkCreateInstance");
84         if (!pfnCreateInstance ||
85             pfnCreateInstance(&createInstanceInfo, nullptr, &mInstance) != VK_SUCCESS)
86         {
87             return VK_NULL_HANDLE;
88         }
89 
90         return mInstance;
91     }
92 
93     template <typename Func>
getProc(const char * fn) const94     Func getProc(const char *fn) const
95     {
96         return reinterpret_cast<Func>(mLibVulkan->getSymbol(fn));
97     }
98 
99   private:
100     std::unique_ptr<Library> mLibVulkan = nullptr;
101     VkInstance mInstance                = VK_NULL_HANDLE;
102 };
103 
104 ANGLE_FORMAT_PRINTF(1, 2)
FormatString(const char * fmt,...)105 std::string FormatString(const char *fmt, ...)
106 {
107     va_list vararg;
108     va_start(vararg, fmt);
109 
110     std::vector<char> buffer;
111     size_t len = FormatStringIntoVector(fmt, vararg, buffer);
112     va_end(vararg);
113 
114     return std::string(&buffer[0], len);
115 }
116 
GetSystemInfoVulkan(SystemInfo * info)117 bool GetSystemInfoVulkan(SystemInfo *info)
118 {
119     return GetSystemInfoVulkanWithICD(info, vk::ICD::Default);
120 }
121 
GetSystemInfoVulkanWithICD(SystemInfo * info,vk::ICD preferredICD)122 bool GetSystemInfoVulkanWithICD(SystemInfo *info, vk::ICD preferredICD)
123 {
124     const bool enableValidationLayers = false;
125     vk::ScopedVkLoaderEnvironment scopedEnvironment(enableValidationLayers, preferredICD);
126 
127     // This implementation builds on top of the Vulkan API, but cannot assume the existence of the
128     // Vulkan library.  ANGLE can be installed on versions of Android as old as Ice Cream Sandwich.
129     // Therefore, we need to use dlopen()/dlsym() in order to see if Vulkan is installed on the
130     // system, and if so, to use it:
131     VulkanLibrary vkLibrary;
132     VkInstance instance = vkLibrary.getVulkanInstance();
133     if (instance == VK_NULL_HANDLE)
134     {
135         // If Vulkan doesn't exist, bail-out early:
136         return false;
137     }
138 
139     // Enumerate the Vulkan physical devices, which are ANGLE gpus:
140     auto pfnEnumeratePhysicalDevices =
141         vkLibrary.getProc<PFN_vkEnumeratePhysicalDevices>("vkEnumeratePhysicalDevices");
142     auto pfnGetPhysicalDeviceProperties =
143         vkLibrary.getProc<PFN_vkGetPhysicalDeviceProperties>("vkGetPhysicalDeviceProperties");
144     uint32_t physicalDeviceCount = 0;
145     if (!pfnEnumeratePhysicalDevices || !pfnGetPhysicalDeviceProperties ||
146         pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr) != VK_SUCCESS)
147     {
148         return false;
149     }
150     std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
151     if (pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data()) !=
152         VK_SUCCESS)
153     {
154         return false;
155     }
156 
157     // If we get to here, we will likely provide a valid answer (unless an unknown vendorID):
158     info->gpus.resize(physicalDeviceCount);
159 
160     for (uint32_t i = 0; i < physicalDeviceCount; i++)
161     {
162         VkPhysicalDeviceProperties properties;
163         pfnGetPhysicalDeviceProperties(physicalDevices[i], &properties);
164         // Fill in data for a given physical device (a.k.a. gpu):
165         GPUDeviceInfo &gpu = info->gpus[i];
166         gpu.vendorId       = properties.vendorID;
167         gpu.deviceId       = properties.deviceID;
168         // Need to parse/re-format properties.driverVersion.
169         //
170         // TODO(ianelliott): Determine the formatting used for each vendor
171         // (http://anglebug.com/2677)
172         switch (properties.vendorID)
173         {
174             case kVendorID_AMD:
175                 gpu.driverVendor                = "Advanced Micro Devices, Inc";
176                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
177                 gpu.detailedDriverVersion.major = properties.driverVersion;
178                 break;
179             case kVendorID_ARM:
180                 gpu.driverVendor                = "Arm Holdings";
181                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
182                 gpu.detailedDriverVersion.major = properties.driverVersion;
183                 break;
184             case kVendorID_Broadcom:
185                 gpu.driverVendor                = "Broadcom";
186                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
187                 gpu.detailedDriverVersion.major = properties.driverVersion;
188                 break;
189             case kVendorID_GOOGLE:
190                 gpu.driverVendor                = "Google";
191                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
192                 gpu.detailedDriverVersion.major = properties.driverVersion;
193                 break;
194             case kVendorID_ImgTec:
195                 gpu.driverVendor                = "Imagination Technologies Limited";
196                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
197                 gpu.detailedDriverVersion.major = properties.driverVersion;
198                 break;
199             case kVendorID_Intel:
200                 gpu.driverVendor                = "Intel Corporation";
201                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
202                 gpu.detailedDriverVersion.major = properties.driverVersion;
203                 break;
204             case kVendorID_Kazan:
205                 gpu.driverVendor                = "Kazan Software";
206                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
207                 gpu.detailedDriverVersion.major = properties.driverVersion;
208                 break;
209             case kVendorID_NVIDIA:
210                 gpu.driverVendor  = "NVIDIA Corporation";
211                 gpu.driverVersion = FormatString("%d.%d.%d.%d", properties.driverVersion >> 22,
212                                                  (properties.driverVersion >> 14) & 0XFF,
213                                                  (properties.driverVersion >> 6) & 0XFF,
214                                                  properties.driverVersion & 0x3F);
215                 gpu.detailedDriverVersion.major    = properties.driverVersion >> 22;
216                 gpu.detailedDriverVersion.minor    = (properties.driverVersion >> 14) & 0xFF;
217                 gpu.detailedDriverVersion.subMinor = (properties.driverVersion >> 6) & 0xFF;
218                 gpu.detailedDriverVersion.patch    = properties.driverVersion & 0x3F;
219                 break;
220             case kVendorID_Qualcomm:
221                 gpu.driverVendor = "Qualcomm Technologies, Inc";
222                 if (properties.driverVersion & 0x80000000)
223                 {
224                     gpu.driverVersion = FormatString("%d.%d.%d", properties.driverVersion >> 22,
225                                                      (properties.driverVersion >> 12) & 0X3FF,
226                                                      properties.driverVersion & 0xFFF);
227                     gpu.detailedDriverVersion.major    = properties.driverVersion >> 22;
228                     gpu.detailedDriverVersion.minor    = (properties.driverVersion >> 12) & 0x3FF;
229                     gpu.detailedDriverVersion.subMinor = properties.driverVersion & 0xFFF;
230                 }
231                 else
232                 {
233                     gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
234                     gpu.detailedDriverVersion.major = properties.driverVersion;
235                 }
236                 break;
237             case kVendorID_VeriSilicon:
238                 gpu.driverVendor                = "VeriSilicon";
239                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
240                 gpu.detailedDriverVersion.major = properties.driverVersion;
241                 break;
242             case kVendorID_Vivante:
243                 gpu.driverVendor                = "Vivante";
244                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
245                 gpu.detailedDriverVersion.major = properties.driverVersion;
246                 break;
247             default:
248                 return false;
249         }
250         gpu.driverDate = "";
251     }
252 
253     return true;
254 }
255 
256 }  // namespace angle
257