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