1 //
2 // Copyright 2013 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.cpp: implementation of the system-agnostic parts of SystemInfo.h
8
9 #include "gpu_info_util/SystemInfo.h"
10
11 #include <cstring>
12 #include <iostream>
13 #include <sstream>
14
15 #include "anglebase/no_destructor.h"
16 #include "common/debug.h"
17 #include "common/string_utils.h"
18 #include "common/system_utils.h"
19
20 namespace angle
21 {
22 namespace
23 {
24 constexpr char kANGLEPreferredDeviceEnv[] = "ANGLE_PREFERRED_DEVICE";
25 }
26
VendorName(VendorID vendor)27 std::string VendorName(VendorID vendor)
28 {
29 switch (vendor)
30 {
31 case kVendorID_AMD:
32 return "AMD";
33 case kVendorID_ARM:
34 return "ARM";
35 case kVendorID_Broadcom:
36 return "Broadcom";
37 case kVendorID_GOOGLE:
38 return "Google";
39 case kVendorID_ImgTec:
40 return "ImgTec";
41 case kVendorID_Intel:
42 return "Intel";
43 case kVendorID_Kazan:
44 return "Kazan";
45 case kVendorID_NVIDIA:
46 return "NVIDIA";
47 case kVendorID_Qualcomm:
48 case kVendorID_Qualcomm_DXGI:
49 return "Qualcomm";
50 case kVendorID_VeriSilicon:
51 return "VeriSilicon";
52 case kVendorID_Vivante:
53 return "Vivante";
54 case kVendorID_VMWare:
55 return "VMWare";
56 case kVendorID_VirtIO:
57 return "VirtIO";
58 case kVendorID_Apple:
59 return "Apple";
60 case kVendorID_Microsoft:
61 return "Microsoft";
62 default:
63 return "Unknown (" + std::to_string(vendor) + ")";
64 }
65 }
66
67 GPUDeviceInfo::GPUDeviceInfo() = default;
68
69 GPUDeviceInfo::~GPUDeviceInfo() = default;
70
71 GPUDeviceInfo::GPUDeviceInfo(const GPUDeviceInfo &other) = default;
72
73 SystemInfo::SystemInfo() = default;
74
75 SystemInfo::~SystemInfo() = default;
76
77 SystemInfo::SystemInfo(const SystemInfo &other) = default;
78
hasNVIDIAGPU() const79 bool SystemInfo::hasNVIDIAGPU() const
80 {
81 for (const GPUDeviceInfo &gpu : gpus)
82 {
83 if (IsNVIDIA(gpu.vendorId))
84 {
85 return true;
86 }
87 }
88 return false;
89 }
90
hasIntelGPU() const91 bool SystemInfo::hasIntelGPU() const
92 {
93 for (const GPUDeviceInfo &gpu : gpus)
94 {
95 if (IsIntel(gpu.vendorId))
96 {
97 return true;
98 }
99 }
100 return false;
101 }
102
hasAMDGPU() const103 bool SystemInfo::hasAMDGPU() const
104 {
105 for (const GPUDeviceInfo &gpu : gpus)
106 {
107 if (IsAMD(gpu.vendorId))
108 {
109 return true;
110 }
111 }
112 return false;
113 }
114
getPreferredGPUIndex() const115 std::optional<size_t> SystemInfo::getPreferredGPUIndex() const
116 {
117 std::string device = GetPreferredDeviceString();
118 if (!device.empty())
119 {
120 for (size_t i = 0; i < gpus.size(); ++i)
121 {
122 std::string vendor = VendorName(gpus[i].vendorId);
123 ToLower(&vendor);
124 if (vendor == device)
125 return i;
126 }
127 }
128 return std::nullopt;
129 }
130
IsAMD(VendorID vendorId)131 bool IsAMD(VendorID vendorId)
132 {
133 return vendorId == kVendorID_AMD;
134 }
135
IsARM(VendorID vendorId)136 bool IsARM(VendorID vendorId)
137 {
138 return vendorId == kVendorID_ARM;
139 }
140
IsBroadcom(VendorID vendorId)141 bool IsBroadcom(VendorID vendorId)
142 {
143 return vendorId == kVendorID_Broadcom;
144 }
145
IsImgTec(VendorID vendorId)146 bool IsImgTec(VendorID vendorId)
147 {
148 return vendorId == kVendorID_ImgTec;
149 }
150
IsKazan(VendorID vendorId)151 bool IsKazan(VendorID vendorId)
152 {
153 return vendorId == kVendorID_Kazan;
154 }
155
IsIntel(VendorID vendorId)156 bool IsIntel(VendorID vendorId)
157 {
158 return vendorId == kVendorID_Intel;
159 }
160
IsNVIDIA(VendorID vendorId)161 bool IsNVIDIA(VendorID vendorId)
162 {
163 return vendorId == kVendorID_NVIDIA;
164 }
165
IsQualcomm(VendorID vendorId)166 bool IsQualcomm(VendorID vendorId)
167 {
168 return vendorId == kVendorID_Qualcomm;
169 }
170
IsGoogle(VendorID vendorId)171 bool IsGoogle(VendorID vendorId)
172 {
173 return vendorId == kVendorID_GOOGLE;
174 }
175
IsVeriSilicon(VendorID vendorId)176 bool IsVeriSilicon(VendorID vendorId)
177 {
178 return vendorId == kVendorID_VeriSilicon;
179 }
180
IsVMWare(VendorID vendorId)181 bool IsVMWare(VendorID vendorId)
182 {
183 return vendorId == kVendorID_VMWare;
184 }
185
IsVirtIO(VendorID vendorId)186 bool IsVirtIO(VendorID vendorId)
187 {
188 return vendorId == kVendorID_VirtIO;
189 }
190
IsVivante(VendorID vendorId)191 bool IsVivante(VendorID vendorId)
192 {
193 return vendorId == kVendorID_Vivante;
194 }
195
IsAppleGPU(VendorID vendorId)196 bool IsAppleGPU(VendorID vendorId)
197 {
198 return vendorId == kVendorID_Apple;
199 }
200
IsMicrosoft(VendorID vendorId)201 bool IsMicrosoft(VendorID vendorId)
202 {
203 return vendorId == kVendorID_Microsoft;
204 }
205
ParseAMDBrahmaDriverVersion(const std::string & content,std::string * version)206 bool ParseAMDBrahmaDriverVersion(const std::string &content, std::string *version)
207 {
208 const size_t begin = content.find_first_of("0123456789");
209 if (begin == std::string::npos)
210 {
211 return false;
212 }
213
214 const size_t end = content.find_first_not_of("0123456789.", begin);
215 if (end == std::string::npos)
216 {
217 *version = content.substr(begin);
218 }
219 else
220 {
221 *version = content.substr(begin, end - begin);
222 }
223 return true;
224 }
225
ParseAMDCatalystDriverVersion(const std::string & content,std::string * version)226 bool ParseAMDCatalystDriverVersion(const std::string &content, std::string *version)
227 {
228 std::istringstream stream(content);
229
230 std::string line;
231 while (std::getline(stream, line))
232 {
233 static const char kReleaseVersion[] = "ReleaseVersion=";
234 if (line.compare(0, std::strlen(kReleaseVersion), kReleaseVersion) != 0)
235 {
236 continue;
237 }
238
239 if (ParseAMDBrahmaDriverVersion(line, version))
240 {
241 return true;
242 }
243 }
244 return false;
245 }
246
CMDeviceIDToDeviceAndVendorID(const std::string & id,uint32_t * vendorId,uint32_t * deviceId)247 bool CMDeviceIDToDeviceAndVendorID(const std::string &id, uint32_t *vendorId, uint32_t *deviceId)
248 {
249 unsigned int vendor = 0;
250 unsigned int device = 0;
251
252 bool success = id.length() >= 21 && HexStringToUInt(id.substr(8, 4), &vendor) &&
253 HexStringToUInt(id.substr(17, 4), &device);
254
255 *vendorId = vendor;
256 *deviceId = device;
257 return success;
258 }
259
GetDualGPUInfo(SystemInfo * info)260 void GetDualGPUInfo(SystemInfo *info)
261 {
262 ASSERT(!info->gpus.empty());
263
264 // On dual-GPU systems we assume the non-Intel GPU is the graphics one.
265 // TODO: this is incorrect and problematic. activeGPUIndex must be removed if it cannot be
266 // determined correctly. A potential solution is to create an OpenGL context and parse
267 // GL_VENDOR. Currently, our test infrastructure is relying on this information and incorrectly
268 // applies test expectations on dual-GPU systems when the Intel GPU is active.
269 // http://anglebug.com/40644803.
270 int active = 0;
271 bool hasIntel = false;
272 for (size_t i = 0; i < info->gpus.size(); ++i)
273 {
274 if (IsIntel(info->gpus[i].vendorId))
275 {
276 hasIntel = true;
277 }
278 if (IsIntel(info->gpus[active].vendorId))
279 {
280 active = static_cast<int>(i);
281 }
282 }
283
284 // Assume that a combination of NVIDIA or AMD with Intel means Optimus or AMD Switchable
285 info->activeGPUIndex = active;
286 info->isOptimus = hasIntel && IsNVIDIA(info->gpus[active].vendorId);
287 info->isAMDSwitchable = hasIntel && IsAMD(info->gpus[active].vendorId);
288 }
289
PrintSystemInfo(const SystemInfo & info)290 void PrintSystemInfo(const SystemInfo &info)
291 {
292 std::cout << info.gpus.size() << " GPUs:\n";
293
294 for (size_t i = 0; i < info.gpus.size(); i++)
295 {
296 const auto &gpu = info.gpus[i];
297
298 std::cout << " " << i << " - " << VendorName(gpu.vendorId) << " device id: 0x" << std::hex
299 << std::uppercase << gpu.deviceId << std::dec << ", revision id: 0x" << std::hex
300 << std::uppercase << gpu.revisionId << std::dec << ", system device id: 0x"
301 << std::hex << std::uppercase << gpu.systemDeviceId << std::dec << "\n";
302 if (!gpu.driverVendor.empty())
303 {
304 std::cout << " Driver Vendor: " << gpu.driverVendor << "\n";
305 }
306 if (!gpu.driverVersion.empty())
307 {
308 std::cout << " Driver Version: " << gpu.driverVersion << "\n";
309 }
310 if (!gpu.driverDate.empty())
311 {
312 std::cout << " Driver Date: " << gpu.driverDate << "\n";
313 }
314 if (gpu.detailedDriverVersion.major != 0 || gpu.detailedDriverVersion.minor != 0 ||
315 gpu.detailedDriverVersion.subMinor != 0 || gpu.detailedDriverVersion.patch != 0)
316 {
317 std::cout << " Detailed Driver Version:\n"
318 << " major: " << gpu.detailedDriverVersion.major
319 << " minor: " << gpu.detailedDriverVersion.minor
320 << " subMinor: " << gpu.detailedDriverVersion.subMinor
321 << " patch: " << gpu.detailedDriverVersion.patch << "\n";
322 }
323 }
324
325 std::cout << "\n";
326 std::cout << "Active GPU: " << info.activeGPUIndex << "\n";
327
328 std::cout << "\n";
329 std::cout << "Optimus: " << (info.isOptimus ? "true" : "false") << "\n";
330 std::cout << "AMD Switchable: " << (info.isAMDSwitchable ? "true" : "false") << "\n";
331 std::cout << "Mac Switchable: " << (info.isMacSwitchable ? "true" : "false") << "\n";
332
333 std::cout << "\n";
334 if (!info.machineManufacturer.empty())
335 {
336 std::cout << "Machine Manufacturer: " << info.machineManufacturer << "\n";
337 }
338 if (info.androidSdkLevel != 0)
339 {
340 std::cout << "Android SDK Level: " << info.androidSdkLevel << "\n";
341 }
342 if (!info.machineModelName.empty())
343 {
344 std::cout << "Machine Model: " << info.machineModelName << "\n";
345 }
346 if (!info.machineModelVersion.empty())
347 {
348 std::cout << "Machine Model Version: " << info.machineModelVersion << "\n";
349 }
350 std::cout << std::endl;
351 }
352
GetSystemDeviceIdFromParts(uint32_t highPart,uint32_t lowPart)353 uint64_t GetSystemDeviceIdFromParts(uint32_t highPart, uint32_t lowPart)
354 {
355 return (static_cast<uint64_t>(highPart) << 32) | lowPart;
356 }
357
GetSystemDeviceIdHighPart(uint64_t systemDeviceId)358 uint32_t GetSystemDeviceIdHighPart(uint64_t systemDeviceId)
359 {
360 return (systemDeviceId >> 32) & 0xffffffff;
361 }
362
GetSystemDeviceIdLowPart(uint64_t systemDeviceId)363 uint32_t GetSystemDeviceIdLowPart(uint64_t systemDeviceId)
364 {
365 return systemDeviceId & 0xffffffff;
366 }
367
GetPreferredDeviceString()368 std::string GetPreferredDeviceString()
369 {
370 std::string device = angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv);
371 ToLower(&device);
372 return device;
373 }
374
375 } // namespace angle
376