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