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