• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             return "Qualcomm";
49         case kVendorID_VeriSilicon:
50             return "VeriSilicon";
51         case kVendorID_Vivante:
52             return "Vivante";
53         case kVendorID_VMWare:
54             return "VMWare";
55         case kVendorID_VirtIO:
56             return "VirtIO";
57         case kVendorID_Apple:
58             return "Apple";
59         case kVendorID_Microsoft:
60             return "Microsoft";
61         default:
62             return "Unknown (" + std::to_string(vendor) + ")";
63     }
64 }
65 
66 GPUDeviceInfo::GPUDeviceInfo() = default;
67 
68 GPUDeviceInfo::~GPUDeviceInfo() = default;
69 
70 GPUDeviceInfo::GPUDeviceInfo(const GPUDeviceInfo &other) = default;
71 
72 SystemInfo::SystemInfo() = default;
73 
74 SystemInfo::~SystemInfo() = default;
75 
76 SystemInfo::SystemInfo(const SystemInfo &other) = default;
77 
hasNVIDIAGPU() const78 bool SystemInfo::hasNVIDIAGPU() const
79 {
80     for (const GPUDeviceInfo &gpu : gpus)
81     {
82         if (IsNVIDIA(gpu.vendorId))
83         {
84             return true;
85         }
86     }
87     return false;
88 }
89 
hasIntelGPU() const90 bool SystemInfo::hasIntelGPU() const
91 {
92     for (const GPUDeviceInfo &gpu : gpus)
93     {
94         if (IsIntel(gpu.vendorId))
95         {
96             return true;
97         }
98     }
99     return false;
100 }
101 
hasAMDGPU() const102 bool SystemInfo::hasAMDGPU() const
103 {
104     for (const GPUDeviceInfo &gpu : gpus)
105     {
106         if (IsAMD(gpu.vendorId))
107         {
108             return true;
109         }
110     }
111     return false;
112 }
113 
getPreferredGPUIndex() const114 std::optional<size_t> SystemInfo::getPreferredGPUIndex() const
115 {
116     std::string device = GetPreferredDeviceString();
117     if (!device.empty())
118     {
119         for (size_t i = 0; i < gpus.size(); ++i)
120         {
121             std::string vendor = VendorName(gpus[i].vendorId);
122             ToLower(&vendor);
123             if (vendor == device)
124                 return i;
125         }
126     }
127     return std::nullopt;
128 }
129 
IsAMD(VendorID vendorId)130 bool IsAMD(VendorID vendorId)
131 {
132     return vendorId == kVendorID_AMD;
133 }
134 
IsARM(VendorID vendorId)135 bool IsARM(VendorID vendorId)
136 {
137     return vendorId == kVendorID_ARM;
138 }
139 
IsBroadcom(VendorID vendorId)140 bool IsBroadcom(VendorID vendorId)
141 {
142     return vendorId == kVendorID_Broadcom;
143 }
144 
IsImgTec(VendorID vendorId)145 bool IsImgTec(VendorID vendorId)
146 {
147     return vendorId == kVendorID_ImgTec;
148 }
149 
IsKazan(VendorID vendorId)150 bool IsKazan(VendorID vendorId)
151 {
152     return vendorId == kVendorID_Kazan;
153 }
154 
IsIntel(VendorID vendorId)155 bool IsIntel(VendorID vendorId)
156 {
157     return vendorId == kVendorID_Intel;
158 }
159 
IsNVIDIA(VendorID vendorId)160 bool IsNVIDIA(VendorID vendorId)
161 {
162     return vendorId == kVendorID_NVIDIA;
163 }
164 
IsQualcomm(VendorID vendorId)165 bool IsQualcomm(VendorID vendorId)
166 {
167     return vendorId == kVendorID_Qualcomm;
168 }
169 
IsGoogle(VendorID vendorId)170 bool IsGoogle(VendorID vendorId)
171 {
172     return vendorId == kVendorID_GOOGLE;
173 }
174 
IsVeriSilicon(VendorID vendorId)175 bool IsVeriSilicon(VendorID vendorId)
176 {
177     return vendorId == kVendorID_VeriSilicon;
178 }
179 
IsVMWare(VendorID vendorId)180 bool IsVMWare(VendorID vendorId)
181 {
182     return vendorId == kVendorID_VMWare;
183 }
184 
IsVirtIO(VendorID vendorId)185 bool IsVirtIO(VendorID vendorId)
186 {
187     return vendorId == kVendorID_VirtIO;
188 }
189 
IsVivante(VendorID vendorId)190 bool IsVivante(VendorID vendorId)
191 {
192     return vendorId == kVendorID_Vivante;
193 }
194 
IsAppleGPU(VendorID vendorId)195 bool IsAppleGPU(VendorID vendorId)
196 {
197     return vendorId == kVendorID_Apple;
198 }
199 
IsMicrosoft(VendorID vendorId)200 bool IsMicrosoft(VendorID vendorId)
201 {
202     return vendorId == kVendorID_Microsoft;
203 }
204 
ParseAMDBrahmaDriverVersion(const std::string & content,std::string * version)205 bool ParseAMDBrahmaDriverVersion(const std::string &content, std::string *version)
206 {
207     const size_t begin = content.find_first_of("0123456789");
208     if (begin == std::string::npos)
209     {
210         return false;
211     }
212 
213     const size_t end = content.find_first_not_of("0123456789.", begin);
214     if (end == std::string::npos)
215     {
216         *version = content.substr(begin);
217     }
218     else
219     {
220         *version = content.substr(begin, end - begin);
221     }
222     return true;
223 }
224 
ParseAMDCatalystDriverVersion(const std::string & content,std::string * version)225 bool ParseAMDCatalystDriverVersion(const std::string &content, std::string *version)
226 {
227     std::istringstream stream(content);
228 
229     std::string line;
230     while (std::getline(stream, line))
231     {
232         static const char kReleaseVersion[] = "ReleaseVersion=";
233         if (line.compare(0, std::strlen(kReleaseVersion), kReleaseVersion) != 0)
234         {
235             continue;
236         }
237 
238         if (ParseAMDBrahmaDriverVersion(line, version))
239         {
240             return true;
241         }
242     }
243     return false;
244 }
245 
ParseMacMachineModel(const std::string & identifier,std::string * type,int32_t * major,int32_t * minor)246 bool ParseMacMachineModel(const std::string &identifier,
247                           std::string *type,
248                           int32_t *major,
249                           int32_t *minor)
250 {
251     size_t numberLoc = identifier.find_first_of("0123456789");
252     if (numberLoc == std::string::npos)
253     {
254         return false;
255     }
256 
257     size_t commaLoc = identifier.find(',', numberLoc);
258     if (commaLoc == std::string::npos || commaLoc >= identifier.size())
259     {
260         return false;
261     }
262 
263     const char *numberPtr = &identifier[numberLoc];
264     const char *commaPtr  = &identifier[commaLoc + 1];
265     char *endPtr          = nullptr;
266 
267     int32_t majorTmp = static_cast<int32_t>(std::strtol(numberPtr, &endPtr, 10));
268     if (endPtr == numberPtr)
269     {
270         return false;
271     }
272 
273     int32_t minorTmp = static_cast<int32_t>(std::strtol(commaPtr, &endPtr, 10));
274     if (endPtr == commaPtr)
275     {
276         return false;
277     }
278 
279     *major = majorTmp;
280     *minor = minorTmp;
281     *type  = identifier.substr(0, numberLoc);
282 
283     return true;
284 }
285 
CMDeviceIDToDeviceAndVendorID(const std::string & id,uint32_t * vendorId,uint32_t * deviceId)286 bool CMDeviceIDToDeviceAndVendorID(const std::string &id, uint32_t *vendorId, uint32_t *deviceId)
287 {
288     unsigned int vendor = 0;
289     unsigned int device = 0;
290 
291     bool success = id.length() >= 21 && HexStringToUInt(id.substr(8, 4), &vendor) &&
292                    HexStringToUInt(id.substr(17, 4), &device);
293 
294     *vendorId = vendor;
295     *deviceId = device;
296     return success;
297 }
298 
GetDualGPUInfo(SystemInfo * info)299 void GetDualGPUInfo(SystemInfo *info)
300 {
301     ASSERT(!info->gpus.empty());
302 
303     // On dual-GPU systems we assume the non-Intel GPU is the graphics one.
304     // TODO: this is incorrect and problematic.  activeGPUIndex must be removed if it cannot be
305     // determined correctly.  A potential solution is to create an OpenGL context and parse
306     // GL_VENDOR.  Currently, our test infrastructure is relying on this information and incorrectly
307     // applies test expectations on dual-GPU systems when the Intel GPU is active.
308     // http://anglebug.com/6174.
309     int active    = 0;
310     bool hasIntel = false;
311     for (size_t i = 0; i < info->gpus.size(); ++i)
312     {
313         if (IsIntel(info->gpus[i].vendorId))
314         {
315             hasIntel = true;
316         }
317         if (IsIntel(info->gpus[active].vendorId))
318         {
319             active = static_cast<int>(i);
320         }
321     }
322 
323     // Assume that a combination of NVIDIA or AMD with Intel means Optimus or AMD Switchable
324     info->activeGPUIndex  = active;
325     info->isOptimus       = hasIntel && IsNVIDIA(info->gpus[active].vendorId);
326     info->isAMDSwitchable = hasIntel && IsAMD(info->gpus[active].vendorId);
327 }
328 
PrintSystemInfo(const SystemInfo & info)329 void PrintSystemInfo(const SystemInfo &info)
330 {
331     std::cout << info.gpus.size() << " GPUs:\n";
332 
333     for (size_t i = 0; i < info.gpus.size(); i++)
334     {
335         const auto &gpu = info.gpus[i];
336 
337         std::cout << "  " << i << " - " << VendorName(gpu.vendorId) << " device id: 0x" << std::hex
338                   << std::uppercase << gpu.deviceId << std::dec << ", revision id: 0x" << std::hex
339                   << std::uppercase << gpu.revisionId << std::dec << ", system device id: 0x"
340                   << std::hex << std::uppercase << gpu.systemDeviceId << std::dec << "\n";
341         if (!gpu.driverVendor.empty())
342         {
343             std::cout << "       Driver Vendor: " << gpu.driverVendor << "\n";
344         }
345         if (!gpu.driverVersion.empty())
346         {
347             std::cout << "       Driver Version: " << gpu.driverVersion << "\n";
348         }
349         if (!gpu.driverDate.empty())
350         {
351             std::cout << "       Driver Date: " << gpu.driverDate << "\n";
352         }
353         if (gpu.detailedDriverVersion.major != 0 || gpu.detailedDriverVersion.minor != 0 ||
354             gpu.detailedDriverVersion.subMinor != 0 || gpu.detailedDriverVersion.patch != 0)
355         {
356             std::cout << "       Detailed Driver Version:\n"
357                       << "           major: " << gpu.detailedDriverVersion.major
358                       << "           minor: " << gpu.detailedDriverVersion.minor
359                       << "           subMinor: " << gpu.detailedDriverVersion.subMinor
360                       << "           patch: " << gpu.detailedDriverVersion.patch << "\n";
361         }
362     }
363 
364     std::cout << "\n";
365     std::cout << "Active GPU: " << info.activeGPUIndex << "\n";
366 
367     std::cout << "\n";
368     std::cout << "Optimus: " << (info.isOptimus ? "true" : "false") << "\n";
369     std::cout << "AMD Switchable: " << (info.isAMDSwitchable ? "true" : "false") << "\n";
370     std::cout << "Mac Switchable: " << (info.isMacSwitchable ? "true" : "false") << "\n";
371 
372     std::cout << "\n";
373     if (!info.machineManufacturer.empty())
374     {
375         std::cout << "Machine Manufacturer: " << info.machineManufacturer << "\n";
376     }
377     if (info.androidSdkLevel != 0)
378     {
379         std::cout << "Android SDK Level: " << info.androidSdkLevel << "\n";
380     }
381     if (!info.machineModelName.empty())
382     {
383         std::cout << "Machine Model: " << info.machineModelName << "\n";
384     }
385     if (!info.machineModelVersion.empty())
386     {
387         std::cout << "Machine Model Version: " << info.machineModelVersion << "\n";
388     }
389     std::cout << std::endl;
390 }
391 
ParseNvidiaDriverVersion(uint32_t version)392 VersionInfo ParseNvidiaDriverVersion(uint32_t version)
393 {
394     return {
395         version >> 22,         // major
396         version >> 14 & 0xff,  // minor
397         version >> 6 & 0xff,   // subMinor
398         version & 0x3f         // patch
399     };
400 }
401 
ParseMesaDriverVersion(uint32_t version)402 VersionInfo ParseMesaDriverVersion(uint32_t version)
403 {
404     // Mesa uses VK_MAKE_VERSION
405     return {
406         version >> 22 & 0x7F,
407         version >> 12 & 0x3FF,
408         version & 0xFFF,
409         0,
410     };
411 }
412 
GetSystemDeviceIdFromParts(uint32_t highPart,uint32_t lowPart)413 uint64_t GetSystemDeviceIdFromParts(uint32_t highPart, uint32_t lowPart)
414 {
415     return (static_cast<uint64_t>(highPart) << 32) | lowPart;
416 }
417 
GetSystemDeviceIdHighPart(uint64_t systemDeviceId)418 uint32_t GetSystemDeviceIdHighPart(uint64_t systemDeviceId)
419 {
420     return (systemDeviceId >> 32) & 0xffffffff;
421 }
422 
GetSystemDeviceIdLowPart(uint64_t systemDeviceId)423 uint32_t GetSystemDeviceIdLowPart(uint64_t systemDeviceId)
424 {
425     return systemDeviceId & 0xffffffff;
426 }
427 
GetPreferredDeviceString()428 std::string GetPreferredDeviceString()
429 {
430     std::string device = angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv);
431     ToLower(&device);
432     return device;
433 }
434 
435 }  // namespace angle
436