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 CloseSystemLibrary(mLibVulkan);
42 }
43
getVulkanInstance()44 VkInstance getVulkanInstance()
45 {
46 mLibVulkan = vk::OpenLibVulkan();
47 if (!mLibVulkan)
48 {
49 // If Vulkan doesn't exist, bail-out early:
50 return VK_NULL_HANDLE;
51 }
52
53 // Determine the available Vulkan instance version:
54 uint32_t instanceVersion = VK_API_VERSION_1_0;
55 #if defined(VK_VERSION_1_1)
56 auto pfnEnumerateInstanceVersion =
57 getProc<PFN_vkEnumerateInstanceVersion>("vkEnumerateInstanceVersion");
58 if (!pfnEnumerateInstanceVersion ||
59 pfnEnumerateInstanceVersion(&instanceVersion) != VK_SUCCESS)
60 {
61 instanceVersion = VK_API_VERSION_1_0;
62 }
63 #endif // VK_VERSION_1_1
64
65 // Create a Vulkan instance:
66 VkApplicationInfo appInfo;
67 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
68 appInfo.pNext = nullptr;
69 appInfo.pApplicationName = "";
70 appInfo.applicationVersion = 1;
71 appInfo.pEngineName = "";
72 appInfo.engineVersion = 1;
73 appInfo.apiVersion = instanceVersion;
74
75 VkInstanceCreateInfo createInstanceInfo;
76 createInstanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
77 createInstanceInfo.pNext = nullptr;
78 createInstanceInfo.flags = 0;
79 createInstanceInfo.pApplicationInfo = &appInfo;
80 createInstanceInfo.enabledLayerCount = 0;
81 createInstanceInfo.ppEnabledLayerNames = nullptr;
82 createInstanceInfo.enabledExtensionCount = 0;
83 createInstanceInfo.ppEnabledExtensionNames = nullptr;
84
85 auto pfnCreateInstance = getProc<PFN_vkCreateInstance>("vkCreateInstance");
86 if (!pfnCreateInstance ||
87 pfnCreateInstance(&createInstanceInfo, nullptr, &mInstance) != VK_SUCCESS)
88 {
89 return VK_NULL_HANDLE;
90 }
91
92 return mInstance;
93 }
94
95 template <typename Func>
getProc(const char * fn) const96 Func getProc(const char *fn) const
97 {
98 return reinterpret_cast<Func>(angle::GetLibrarySymbol(mLibVulkan, fn));
99 }
100
101 private:
102 void *mLibVulkan = nullptr;
103 VkInstance mInstance = VK_NULL_HANDLE;
104 };
105
106 ANGLE_FORMAT_PRINTF(1, 2)
FormatString(const char * fmt,...)107 std::string FormatString(const char *fmt, ...)
108 {
109 va_list vararg;
110 va_start(vararg, fmt);
111
112 std::vector<char> buffer;
113 size_t len = FormatStringIntoVector(fmt, vararg, buffer);
114 va_end(vararg);
115
116 return std::string(&buffer[0], len);
117 }
118
GetSystemInfoVulkan(SystemInfo * info)119 bool GetSystemInfoVulkan(SystemInfo *info)
120 {
121 return GetSystemInfoVulkanWithICD(info, vk::ICD::Default);
122 }
123
GetSystemInfoVulkanWithICD(SystemInfo * info,vk::ICD preferredICD)124 bool GetSystemInfoVulkanWithICD(SystemInfo *info, vk::ICD preferredICD)
125 {
126 const bool enableValidationLayers = false;
127 vk::ScopedVkLoaderEnvironment scopedEnvironment(enableValidationLayers, preferredICD);
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 || !pfnGetPhysicalDeviceProperties ||
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_GOOGLE:
192 gpu.driverVendor = "Google";
193 gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
194 gpu.detailedDriverVersion.major = properties.driverVersion;
195 break;
196 case kVendorID_ImgTec:
197 gpu.driverVendor = "Imagination Technologies Limited";
198 gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
199 gpu.detailedDriverVersion.major = properties.driverVersion;
200 break;
201 case kVendorID_Intel:
202 gpu.driverVendor = "Intel Corporation";
203 gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
204 gpu.detailedDriverVersion.major = properties.driverVersion;
205 break;
206 case kVendorID_Kazan:
207 gpu.driverVendor = "Kazan Software";
208 gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
209 gpu.detailedDriverVersion.major = properties.driverVersion;
210 break;
211 case kVendorID_NVIDIA:
212 gpu.driverVendor = "NVIDIA Corporation";
213 gpu.driverVersion = FormatString("%d.%d.%d.%d", properties.driverVersion >> 22,
214 (properties.driverVersion >> 14) & 0XFF,
215 (properties.driverVersion >> 6) & 0XFF,
216 properties.driverVersion & 0x3F);
217 gpu.detailedDriverVersion.major = properties.driverVersion >> 22;
218 gpu.detailedDriverVersion.minor = (properties.driverVersion >> 14) & 0xFF;
219 gpu.detailedDriverVersion.subMinor = (properties.driverVersion >> 6) & 0xFF;
220 gpu.detailedDriverVersion.patch = properties.driverVersion & 0x3F;
221 break;
222 case kVendorID_Qualcomm:
223 gpu.driverVendor = "Qualcomm Technologies, Inc";
224 if (properties.driverVersion & 0x80000000)
225 {
226 gpu.driverVersion = FormatString("%d.%d.%d", properties.driverVersion >> 22,
227 (properties.driverVersion >> 12) & 0X3FF,
228 properties.driverVersion & 0xFFF);
229 gpu.detailedDriverVersion.major = properties.driverVersion >> 22;
230 gpu.detailedDriverVersion.minor = (properties.driverVersion >> 12) & 0x3FF;
231 gpu.detailedDriverVersion.subMinor = properties.driverVersion & 0xFFF;
232 }
233 else
234 {
235 gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
236 gpu.detailedDriverVersion.major = properties.driverVersion;
237 }
238 break;
239 case kVendorID_VeriSilicon:
240 gpu.driverVendor = "VeriSilicon";
241 gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
242 gpu.detailedDriverVersion.major = properties.driverVersion;
243 break;
244 case kVendorID_Vivante:
245 gpu.driverVendor = "Vivante";
246 gpu.driverVersion = FormatString("0x%x", properties.driverVersion);
247 gpu.detailedDriverVersion.major = properties.driverVersion;
248 break;
249 default:
250 return false;
251 }
252 gpu.driverDate = "";
253 }
254
255 return true;
256 }
257
258 } // namespace angle
259