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_linux.cpp: implementation of the Linux-specific parts of SystemInfo.h
8
9 #include "gpu_info_util/SystemInfo_internal.h"
10
11 #include <cstring>
12 #include <fstream>
13
14 #include "common/angleutils.h"
15 #include "common/debug.h"
16
17 namespace angle
18 {
19
20 namespace
21 {
22
ReadWholeFile(const char * filename,std::string * content)23 bool ReadWholeFile(const char *filename, std::string *content)
24 {
25 std::ifstream file(filename);
26
27 if (!file)
28 {
29 return false;
30 }
31
32 *content = std::string(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
33 return true;
34 }
35
36 // Scan /sys/module/amdgpu/version.
GetAMDBrahmaDriverVersion(std::string * version)37 bool GetAMDBrahmaDriverVersion(std::string *version)
38 {
39 *version = "";
40 std::string content;
41
42 return ReadWholeFile("/sys/module/amdgpu/version", &content) &&
43 ParseAMDBrahmaDriverVersion(content, version);
44 }
45
46 // Scan /etc/ati/amdpcsdb.default for "ReleaseVersion".
GetAMDCatalystDriverVersion(std::string * version)47 bool GetAMDCatalystDriverVersion(std::string *version)
48 {
49 *version = "";
50 std::string content;
51
52 return ReadWholeFile("/etc/ati/amdpcsdb.default", &content) &&
53 ParseAMDCatalystDriverVersion(content, version);
54 }
55
56 } // anonymous namespace
57
58 #if !defined(GPU_INFO_USE_X11)
GetNvidiaDriverVersionWithXNVCtrl(std::string * version)59 bool GetNvidiaDriverVersionWithXNVCtrl(std::string *version)
60 {
61 return false;
62 }
63 #endif
64
65 #if !defined(GPU_INFO_USE_LIBPCI)
GetPCIDevicesWithLibPCI(std::vector<GPUDeviceInfo> * devices)66 bool GetPCIDevicesWithLibPCI(std::vector<GPUDeviceInfo> *devices)
67 {
68 return false;
69 }
70 #endif
71
GetSystemInfo(SystemInfo * info)72 bool GetSystemInfo(SystemInfo *info)
73 {
74 if (!GetPCIDevicesWithLibPCI(&(info->gpus)))
75 {
76 #if defined(ANGLE_USE_VULKAN_SYSTEM_INFO)
77 // Try vulkan backend to get GPU info
78 return GetSystemInfoVulkan(info);
79 #else
80 return false;
81 #endif // defined(ANGLE_HAS_VULKAN_SYSTEM_INFO)
82 }
83
84 if (info->gpus.size() == 0)
85 {
86 return false;
87 }
88
89 GetDualGPUInfo(info);
90
91 for (size_t i = 0; i < info->gpus.size(); ++i)
92 {
93 GPUDeviceInfo *gpu = &info->gpus[i];
94
95 // New GPUs might be added inside this loop, don't query for their driver version again
96 if (!gpu->driverVendor.empty())
97 {
98 continue;
99 }
100
101 if (IsAMD(gpu->vendorId))
102 {
103 std::string version;
104 if (GetAMDBrahmaDriverVersion(&version))
105 {
106 gpu->driverVendor = "AMD (Brahma)";
107 gpu->driverVersion = std::move(version);
108 }
109 else if (GetAMDCatalystDriverVersion(&version))
110 {
111 gpu->driverVendor = "AMD (Catalyst)";
112 gpu->driverVersion = std::move(version);
113 }
114 }
115
116 if (IsNVIDIA(gpu->vendorId))
117 {
118 std::string version;
119 if (GetNvidiaDriverVersionWithXNVCtrl(&version))
120 {
121 gpu->driverVendor = "Nvidia";
122 gpu->driverVersion = std::move(version);
123 }
124 }
125
126 // In dual-GPU cases the PCI scan sometimes only gives us the Intel GPU. If we are able to
127 // query for the Nvidia driver version, it means there was hidden Nvidia GPU, so we add it
128 // to the list.
129 if (IsIntel(gpu->vendorId) && info->gpus.size() == 1)
130 {
131 std::string version;
132 if (GetNvidiaDriverVersionWithXNVCtrl(&version))
133 {
134 GPUDeviceInfo nvidiaInfo;
135 nvidiaInfo.vendorId = kVendorID_NVIDIA;
136 nvidiaInfo.deviceId = 0;
137 gpu->driverVendor = "Nvidia";
138 gpu->driverVersion = std::move(version);
139
140 info->gpus.emplace_back(std::move(nvidiaInfo));
141 info->isOptimus = true;
142 }
143 }
144 }
145
146 return true;
147 }
148
149 } // namespace angle
150