• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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