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