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