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                 break;
53         }
54 
55         if (!mLibVulkan)
56         {
57             // If Vulkan doesn't exist, bail-out early:
58             return VK_NULL_HANDLE;
59         }
60 
61         // Determine the available Vulkan instance version:
62         uint32_t instanceVersion = VK_API_VERSION_1_0;
63 #if defined(VK_VERSION_1_1)
64         auto pfnEnumerateInstanceVersion =
65             getProc<PFN_vkEnumerateInstanceVersion>("vkEnumerateInstanceVersion");
66         if (!pfnEnumerateInstanceVersion ||
67             pfnEnumerateInstanceVersion(&instanceVersion) != VK_SUCCESS)
68         {
69             instanceVersion = VK_API_VERSION_1_0;
70         }
71 #endif  // VK_VERSION_1_1
72 
73         // Create a Vulkan instance:
74         VkApplicationInfo appInfo;
75         appInfo.sType              = VK_STRUCTURE_TYPE_APPLICATION_INFO;
76         appInfo.pNext              = nullptr;
77         appInfo.pApplicationName   = "";
78         appInfo.applicationVersion = 1;
79         appInfo.pEngineName        = "";
80         appInfo.engineVersion      = 1;
81         appInfo.apiVersion         = instanceVersion;
82 
83         VkInstanceCreateInfo createInstanceInfo;
84         createInstanceInfo.sType                   = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
85         createInstanceInfo.pNext                   = nullptr;
86         createInstanceInfo.flags                   = 0;
87         createInstanceInfo.pApplicationInfo        = &appInfo;
88         createInstanceInfo.enabledLayerCount       = 0;
89         createInstanceInfo.ppEnabledLayerNames     = nullptr;
90         createInstanceInfo.enabledExtensionCount   = 0;
91         createInstanceInfo.ppEnabledExtensionNames = nullptr;
92 
93         auto pfnCreateInstance = getProc<PFN_vkCreateInstance>("vkCreateInstance");
94         if (!pfnCreateInstance ||
95             pfnCreateInstance(&createInstanceInfo, nullptr, &mInstance) != VK_SUCCESS)
96         {
97             return VK_NULL_HANDLE;
98         }
99 
100         return mInstance;
101     }
102 
103     template <typename Func>
getProc(const char * fn) const104     Func getProc(const char *fn) const
105     {
106         return reinterpret_cast<Func>(mLibVulkan->getSymbol(fn));
107     }
108 
109   private:
110     Library *mLibVulkan  = nullptr;
111     VkInstance mInstance = VK_NULL_HANDLE;
112 };
113 
114 ANGLE_FORMAT_PRINTF(1, 2)
FormatString(const char * fmt,...)115 std::string FormatString(const char *fmt, ...)
116 {
117     va_list vararg;
118     va_start(vararg, fmt);
119 
120     std::vector<char> buffer;
121     size_t len = FormatStringIntoVector(fmt, vararg, buffer);
122     va_end(vararg);
123 
124     return std::string(&buffer[0], len);
125 }
126 
GetSystemInfoVulkan(SystemInfo * info)127 bool GetSystemInfoVulkan(SystemInfo *info)
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     uint32_t physicalDeviceCount = 0;
147     if (!pfnEnumeratePhysicalDevices ||
148         pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr) != VK_SUCCESS)
149     {
150         return false;
151     }
152     std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
153     if (pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data()) !=
154         VK_SUCCESS)
155     {
156         return false;
157     }
158 
159     // If we get to here, we will likely provide a valid answer (unless an unknown vendorID):
160     info->gpus.resize(physicalDeviceCount);
161 
162     for (uint32_t i = 0; i < physicalDeviceCount; i++)
163     {
164         VkPhysicalDeviceProperties properties;
165         pfnGetPhysicalDeviceProperties(physicalDevices[i], &properties);
166         // Fill in data for a given physical device (a.k.a. gpu):
167         GPUDeviceInfo &gpu = info->gpus[i];
168         gpu.vendorId       = properties.vendorID;
169         gpu.deviceId       = properties.deviceID;
170         // Need to parse/re-format properties.driverVersion.
171         //
172         // TODO(ianelliott): Determine the formatting used for each vendor
173         // (http://anglebug.com/2677)
174         switch (properties.vendorID)
175         {
176             case kVendorID_AMD:
177                 gpu.driverVendor                = "Advanced Micro Devices, Inc";
178                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
179                 gpu.detailedDriverVersion.major = properties.driverVersion;
180                 break;
181             case kVendorID_ARM:
182                 gpu.driverVendor                = "Arm Holdings";
183                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
184                 gpu.detailedDriverVersion.major = properties.driverVersion;
185                 break;
186             case kVendorID_Broadcom:
187                 gpu.driverVendor                = "Broadcom";
188                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
189                 gpu.detailedDriverVersion.major = properties.driverVersion;
190                 break;
191             case kVendorID_ImgTec:
192                 gpu.driverVendor                = "Imagination Technologies Limited";
193                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
194                 gpu.detailedDriverVersion.major = properties.driverVersion;
195                 break;
196             case kVendorID_Intel:
197                 gpu.driverVendor                = "Intel Corporation";
198                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
199                 gpu.detailedDriverVersion.major = properties.driverVersion;
200                 break;
201             case kVendorID_Kazan:
202                 gpu.driverVendor                = "Kazan Software";
203                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
204                 gpu.detailedDriverVersion.major = properties.driverVersion;
205                 break;
206             case kVendorID_NVIDIA:
207                 gpu.driverVendor  = "NVIDIA Corporation";
208                 gpu.driverVersion = FormatString("%d.%d.%d.%d", properties.driverVersion >> 22,
209                                                  (properties.driverVersion >> 14) & 0XFF,
210                                                  (properties.driverVersion >> 6) & 0XFF,
211                                                  properties.driverVersion & 0x3F);
212                 gpu.detailedDriverVersion.major    = properties.driverVersion >> 22;
213                 gpu.detailedDriverVersion.minor    = (properties.driverVersion >> 14) & 0xFF;
214                 gpu.detailedDriverVersion.subMinor = (properties.driverVersion >> 6) & 0xFF;
215                 gpu.detailedDriverVersion.patch    = properties.driverVersion & 0x3F;
216                 break;
217             case kVendorID_Qualcomm:
218                 gpu.driverVendor = "Qualcomm Technologies, Inc";
219                 if (properties.driverVersion & 0x80000000)
220                 {
221                     gpu.driverVersion = FormatString("%d.%d.%d", properties.driverVersion >> 22,
222                                                      (properties.driverVersion >> 12) & 0X3FF,
223                                                      properties.driverVersion & 0xFFF);
224                     gpu.detailedDriverVersion.major    = properties.driverVersion >> 22;
225                     gpu.detailedDriverVersion.minor    = (properties.driverVersion >> 12) & 0x3FF;
226                     gpu.detailedDriverVersion.subMinor = properties.driverVersion & 0xFFF;
227                 }
228                 else
229                 {
230                     gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
231                     gpu.detailedDriverVersion.major = properties.driverVersion;
232                 }
233                 break;
234             case kVendorID_VeriSilicon:
235                 gpu.driverVendor                = "VeriSilicon";
236                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
237                 gpu.detailedDriverVersion.major = properties.driverVersion;
238                 break;
239             case kVendorID_Vivante:
240                 gpu.driverVendor                = "Vivante";
241                 gpu.driverVersion               = FormatString("0x%x", properties.driverVersion);
242                 gpu.detailedDriverVersion.major = properties.driverVersion;
243                 break;
244             default:
245                 return false;
246         }
247         gpu.driverDate = "";
248     }
249 
250     return true;
251 }
252 
253 }  // namespace angle
254