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