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