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 return false;
77 }
78
79 if (info->gpus.size() == 0)
80 {
81 return false;
82 }
83
84 GetDualGPUInfo(info);
85
86 for (size_t i = 0; i < info->gpus.size(); ++i)
87 {
88 GPUDeviceInfo *gpu = &info->gpus[i];
89
90 // New GPUs might be added inside this loop, don't query for their driver version again
91 if (!gpu->driverVendor.empty())
92 {
93 continue;
94 }
95
96 if (IsAMD(gpu->vendorId))
97 {
98 std::string version;
99 if (GetAMDBrahmaDriverVersion(&version))
100 {
101 gpu->driverVendor = "AMD (Brahma)";
102 gpu->driverVersion = std::move(version);
103 }
104 else if (GetAMDCatalystDriverVersion(&version))
105 {
106 gpu->driverVendor = "AMD (Catalyst)";
107 gpu->driverVersion = std::move(version);
108 }
109 }
110
111 if (IsNVIDIA(gpu->vendorId))
112 {
113 std::string version;
114 if (GetNvidiaDriverVersionWithXNVCtrl(&version))
115 {
116 gpu->driverVendor = "Nvidia";
117 gpu->driverVersion = std::move(version);
118 }
119 }
120
121 // In dual-GPU cases the PCI scan sometimes only gives us the Intel GPU. If we are able to
122 // query for the Nvidia driver version, it means there was hidden Nvidia GPU, so we add it
123 // to the list.
124 if (IsIntel(gpu->vendorId) && info->gpus.size() == 1)
125 {
126 std::string version;
127 if (GetNvidiaDriverVersionWithXNVCtrl(&version))
128 {
129 GPUDeviceInfo nvidiaInfo;
130 nvidiaInfo.vendorId = kVendorID_NVIDIA;
131 nvidiaInfo.deviceId = 0;
132 gpu->driverVendor = "Nvidia";
133 gpu->driverVersion = std::move(version);
134
135 info->gpus.emplace_back(std::move(nvidiaInfo));
136 info->isOptimus = true;
137 }
138 }
139 }
140
141 return true;
142 }
143
144 } // namespace angle
145