xref: /aosp_15_r20/external/angle/src/gpu_info_util/SystemInfo.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 
CMDeviceIDToDeviceAndVendorID(const std::string & id,uint32_t * vendorId,uint32_t * deviceId)246 bool CMDeviceIDToDeviceAndVendorID(const std::string &id, uint32_t *vendorId, uint32_t *deviceId)
247 {
248     unsigned int vendor = 0;
249     unsigned int device = 0;
250 
251     bool success = id.length() >= 21 && HexStringToUInt(id.substr(8, 4), &vendor) &&
252                    HexStringToUInt(id.substr(17, 4), &device);
253 
254     *vendorId = vendor;
255     *deviceId = device;
256     return success;
257 }
258 
GetDualGPUInfo(SystemInfo * info)259 void GetDualGPUInfo(SystemInfo *info)
260 {
261     ASSERT(!info->gpus.empty());
262 
263     // On dual-GPU systems we assume the non-Intel GPU is the graphics one.
264     // TODO: this is incorrect and problematic.  activeGPUIndex must be removed if it cannot be
265     // determined correctly.  A potential solution is to create an OpenGL context and parse
266     // GL_VENDOR.  Currently, our test infrastructure is relying on this information and incorrectly
267     // applies test expectations on dual-GPU systems when the Intel GPU is active.
268     // http://anglebug.com/40644803.
269     int active    = 0;
270     bool hasIntel = false;
271     for (size_t i = 0; i < info->gpus.size(); ++i)
272     {
273         if (IsIntel(info->gpus[i].vendorId))
274         {
275             hasIntel = true;
276         }
277         if (IsIntel(info->gpus[active].vendorId))
278         {
279             active = static_cast<int>(i);
280         }
281     }
282 
283     // Assume that a combination of NVIDIA or AMD with Intel means Optimus or AMD Switchable
284     info->activeGPUIndex  = active;
285     info->isOptimus       = hasIntel && IsNVIDIA(info->gpus[active].vendorId);
286     info->isAMDSwitchable = hasIntel && IsAMD(info->gpus[active].vendorId);
287 }
288 
PrintSystemInfo(const SystemInfo & info)289 void PrintSystemInfo(const SystemInfo &info)
290 {
291     std::cout << info.gpus.size() << " GPUs:\n";
292 
293     for (size_t i = 0; i < info.gpus.size(); i++)
294     {
295         const auto &gpu = info.gpus[i];
296 
297         std::cout << "  " << i << " - " << VendorName(gpu.vendorId) << " device id: 0x" << std::hex
298                   << std::uppercase << gpu.deviceId << std::dec << ", revision id: 0x" << std::hex
299                   << std::uppercase << gpu.revisionId << std::dec << ", system device id: 0x"
300                   << std::hex << std::uppercase << gpu.systemDeviceId << std::dec << "\n";
301         if (!gpu.driverVendor.empty())
302         {
303             std::cout << "       Driver Vendor: " << gpu.driverVendor << "\n";
304         }
305         if (!gpu.driverVersion.empty())
306         {
307             std::cout << "       Driver Version: " << gpu.driverVersion << "\n";
308         }
309         if (!gpu.driverDate.empty())
310         {
311             std::cout << "       Driver Date: " << gpu.driverDate << "\n";
312         }
313         if (gpu.detailedDriverVersion.major != 0 || gpu.detailedDriverVersion.minor != 0 ||
314             gpu.detailedDriverVersion.subMinor != 0 || gpu.detailedDriverVersion.patch != 0)
315         {
316             std::cout << "       Detailed Driver Version:\n"
317                       << "           major: " << gpu.detailedDriverVersion.major
318                       << "           minor: " << gpu.detailedDriverVersion.minor
319                       << "           subMinor: " << gpu.detailedDriverVersion.subMinor
320                       << "           patch: " << gpu.detailedDriverVersion.patch << "\n";
321         }
322     }
323 
324     std::cout << "\n";
325     std::cout << "Active GPU: " << info.activeGPUIndex << "\n";
326 
327     std::cout << "\n";
328     std::cout << "Optimus: " << (info.isOptimus ? "true" : "false") << "\n";
329     std::cout << "AMD Switchable: " << (info.isAMDSwitchable ? "true" : "false") << "\n";
330     std::cout << "Mac Switchable: " << (info.isMacSwitchable ? "true" : "false") << "\n";
331 
332     std::cout << "\n";
333     if (!info.machineManufacturer.empty())
334     {
335         std::cout << "Machine Manufacturer: " << info.machineManufacturer << "\n";
336     }
337     if (info.androidSdkLevel != 0)
338     {
339         std::cout << "Android SDK Level: " << info.androidSdkLevel << "\n";
340     }
341     if (!info.machineModelName.empty())
342     {
343         std::cout << "Machine Model: " << info.machineModelName << "\n";
344     }
345     if (!info.machineModelVersion.empty())
346     {
347         std::cout << "Machine Model Version: " << info.machineModelVersion << "\n";
348     }
349     std::cout << std::endl;
350 }
351 
ParseNvidiaDriverVersion(uint32_t version)352 VersionInfo ParseNvidiaDriverVersion(uint32_t version)
353 {
354     return {
355         version >> 22,         // major
356         version >> 14 & 0xff,  // minor
357         version >> 6 & 0xff,   // subMinor
358         version & 0x3f         // patch
359     };
360 }
361 
ParseMesaDriverVersion(uint32_t version)362 VersionInfo ParseMesaDriverVersion(uint32_t version)
363 {
364     // Mesa uses VK_MAKE_VERSION
365     return {
366         version >> 22 & 0x7F,
367         version >> 12 & 0x3FF,
368         version & 0xFFF,
369         0,
370     };
371 }
372 
GetSystemDeviceIdFromParts(uint32_t highPart,uint32_t lowPart)373 uint64_t GetSystemDeviceIdFromParts(uint32_t highPart, uint32_t lowPart)
374 {
375     return (static_cast<uint64_t>(highPart) << 32) | lowPart;
376 }
377 
GetSystemDeviceIdHighPart(uint64_t systemDeviceId)378 uint32_t GetSystemDeviceIdHighPart(uint64_t systemDeviceId)
379 {
380     return (systemDeviceId >> 32) & 0xffffffff;
381 }
382 
GetSystemDeviceIdLowPart(uint64_t systemDeviceId)383 uint32_t GetSystemDeviceIdLowPart(uint64_t systemDeviceId)
384 {
385     return systemDeviceId & 0xffffffff;
386 }
387 
GetPreferredDeviceString()388 std::string GetPreferredDeviceString()
389 {
390     std::string device = angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv);
391     ToLower(&device);
392     return device;
393 }
394 
395 }  // namespace angle
396