• 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         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