| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "gpu/config/gpu_info_collector_linux.h" | |
| 6 | |
| 7 #include <stddef.h> | 5 #include <stddef.h> |
| 8 #include <stdint.h> | 6 #include <stdint.h> |
| 9 | 7 |
| 10 #include <vector> | 8 #include <vector> |
| 11 | 9 |
| 12 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 13 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 14 #include "base/logging.h" | 12 #include "base/logging.h" |
| 15 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
| 16 #include "base/strings/string_piece.h" | 14 #include "base/strings/string_piece.h" |
| 17 #include "base/strings/string_split.h" | 15 #include "base/strings/string_split.h" |
| 18 #include "base/strings/string_tokenizer.h" | 16 #include "base/strings/string_tokenizer.h" |
| 19 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
| 20 #include "base/trace_event/trace_event.h" | 18 #include "base/trace_event/trace_event.h" |
| 21 #include "gpu/config/gpu_info_collector.h" | 19 #include "gpu/config/gpu_info_collector.h" |
| 22 #include "gpu/config/gpu_switches.h" | 20 #include "gpu/config/gpu_switches.h" |
| 21 #include "third_party/angle/src/gpu_info_util/SystemInfo.h" |
| 23 #include "third_party/re2/src/re2/re2.h" | 22 #include "third_party/re2/src/re2/re2.h" |
| 24 #include "ui/gl/gl_bindings.h" | 23 #include "ui/gl/gl_bindings.h" |
| 25 #include "ui/gl/gl_context.h" | 24 #include "ui/gl/gl_context.h" |
| 26 #include "ui/gl/gl_implementation.h" | 25 #include "ui/gl/gl_implementation.h" |
| 27 #include "ui/gl/gl_surface.h" | 26 #include "ui/gl/gl_surface.h" |
| 28 #include "ui/gl/gl_switches.h" | 27 #include "ui/gl/gl_switches.h" |
| 29 | 28 |
| 30 #if defined(USE_LIBPCI) | |
| 31 #include "library_loaders/libpci.h" // nogncheck | |
| 32 #endif | |
| 33 | |
| 34 namespace gpu { | 29 namespace gpu { |
| 35 | 30 |
| 36 namespace { | |
| 37 | |
| 38 #if defined(USE_LIBPCI) | |
| 39 // This checks if a system supports PCI bus. | |
| 40 // We check the existence of /sys/bus/pci or /sys/bug/pci_express. | |
| 41 bool IsPciSupported() { | |
| 42 const base::FilePath pci_path("/sys/bus/pci/"); | |
| 43 const base::FilePath pcie_path("/sys/bus/pci_express/"); | |
| 44 return (base::PathExists(pci_path) || | |
| 45 base::PathExists(pcie_path)); | |
| 46 } | |
| 47 #endif // defined(USE_LIBPCI) | |
| 48 | |
| 49 // Scan /sys/module/amdgpu/version. | |
| 50 // Return empty string on failing. | |
| 51 std::string CollectDriverVersionAMDBrahma() { | |
| 52 const base::FilePath ati_file_path("/sys/module/amdgpu/version"); | |
| 53 if (!base::PathExists(ati_file_path)) | |
| 54 return std::string(); | |
| 55 std::string contents; | |
| 56 if (!base::ReadFileToString(ati_file_path, &contents)) | |
| 57 return std::string(); | |
| 58 size_t begin = contents.find_first_of("0123456789"); | |
| 59 if (begin != std::string::npos) { | |
| 60 size_t end = contents.find_first_not_of("0123456789.", begin); | |
| 61 if (end == std::string::npos) | |
| 62 return contents.substr(begin); | |
| 63 else | |
| 64 return contents.substr(begin, end - begin); | |
| 65 } | |
| 66 return std::string(); | |
| 67 } | |
| 68 | |
| 69 // Scan /etc/ati/amdpcsdb.default for "ReleaseVersion". | |
| 70 // Return empty string on failing. | |
| 71 std::string CollectDriverVersionAMDCatalyst() { | |
| 72 const base::FilePath ati_file_path("/etc/ati/amdpcsdb.default"); | |
| 73 if (!base::PathExists(ati_file_path)) | |
| 74 return std::string(); | |
| 75 std::string contents; | |
| 76 if (!base::ReadFileToString(ati_file_path, &contents)) | |
| 77 return std::string(); | |
| 78 base::StringTokenizer t(contents, "\r\n"); | |
| 79 while (t.GetNext()) { | |
| 80 std::string line = t.token(); | |
| 81 if (base::StartsWith(line, "ReleaseVersion=", | |
| 82 base::CompareCase::SENSITIVE)) { | |
| 83 size_t begin = line.find_first_of("0123456789"); | |
| 84 if (begin != std::string::npos) { | |
| 85 size_t end = line.find_first_not_of("0123456789.", begin); | |
| 86 if (end == std::string::npos) | |
| 87 return line.substr(begin); | |
| 88 else | |
| 89 return line.substr(begin, end - begin); | |
| 90 } | |
| 91 } | |
| 92 } | |
| 93 return std::string(); | |
| 94 } | |
| 95 | |
| 96 const uint32_t kVendorIDIntel = 0x8086; | |
| 97 const uint32_t kVendorIDNVidia = 0x10de; | |
| 98 const uint32_t kVendorIDAMD = 0x1002; | |
| 99 | |
| 100 CollectInfoResult CollectPCIVideoCardInfo(GPUInfo* gpu_info) { | |
| 101 DCHECK(gpu_info); | |
| 102 | |
| 103 #if !defined(USE_LIBPCI) | |
| 104 return kCollectInfoNonFatalFailure; | |
| 105 #else | |
| 106 | |
| 107 if (IsPciSupported() == false) { | |
| 108 VLOG(1) << "PCI bus scanning is not supported"; | |
| 109 return kCollectInfoNonFatalFailure; | |
| 110 } | |
| 111 | |
| 112 // TODO(zmo): be more flexible about library name. | |
| 113 LibPciLoader libpci_loader; | |
| 114 if (!libpci_loader.Load("libpci.so.3") && | |
| 115 !libpci_loader.Load("libpci.so")) { | |
| 116 VLOG(1) << "Failed to locate libpci"; | |
| 117 return kCollectInfoNonFatalFailure; | |
| 118 } | |
| 119 | |
| 120 pci_access* access = (libpci_loader.pci_alloc)(); | |
| 121 DCHECK(access != NULL); | |
| 122 (libpci_loader.pci_init)(access); | |
| 123 (libpci_loader.pci_scan_bus)(access); | |
| 124 bool primary_gpu_identified = false; | |
| 125 for (pci_dev* device = access->devices; | |
| 126 device != NULL; device = device->next) { | |
| 127 // Fill the IDs and class fields. | |
| 128 (libpci_loader.pci_fill_info)(device, 33); | |
| 129 bool is_gpu = false; | |
| 130 switch (device->device_class) { | |
| 131 case PCI_CLASS_DISPLAY_VGA: | |
| 132 case PCI_CLASS_DISPLAY_XGA: | |
| 133 case PCI_CLASS_DISPLAY_3D: | |
| 134 is_gpu = true; | |
| 135 break; | |
| 136 case PCI_CLASS_DISPLAY_OTHER: | |
| 137 default: | |
| 138 break; | |
| 139 } | |
| 140 if (!is_gpu) | |
| 141 continue; | |
| 142 if (device->vendor_id == 0 || device->device_id == 0) | |
| 143 continue; | |
| 144 | |
| 145 GPUInfo::GPUDevice gpu; | |
| 146 gpu.vendor_id = device->vendor_id; | |
| 147 gpu.device_id = device->device_id; | |
| 148 | |
| 149 if (!primary_gpu_identified) { | |
| 150 primary_gpu_identified = true; | |
| 151 gpu_info->gpu = gpu; | |
| 152 } else { | |
| 153 // TODO(zmo): if there are multiple GPUs, we assume the non Intel | |
| 154 // one is primary. Revisit this logic because we actually don't know | |
| 155 // which GPU we are using at this point. | |
| 156 if (gpu_info->gpu.vendor_id == kVendorIDIntel && | |
| 157 gpu.vendor_id != kVendorIDIntel) { | |
| 158 gpu_info->secondary_gpus.push_back(gpu_info->gpu); | |
| 159 gpu_info->gpu = gpu; | |
| 160 } else { | |
| 161 gpu_info->secondary_gpus.push_back(gpu); | |
| 162 } | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 // Detect Optimus or AMD Switchable GPU. | |
| 167 if (gpu_info->secondary_gpus.size() == 1 && | |
| 168 gpu_info->secondary_gpus[0].vendor_id == kVendorIDIntel) { | |
| 169 if (gpu_info->gpu.vendor_id == kVendorIDNVidia) | |
| 170 gpu_info->optimus = true; | |
| 171 if (gpu_info->gpu.vendor_id == kVendorIDAMD) | |
| 172 gpu_info->amd_switchable = true; | |
| 173 } | |
| 174 | |
| 175 (libpci_loader.pci_cleanup)(access); | |
| 176 if (!primary_gpu_identified) | |
| 177 return kCollectInfoNonFatalFailure; | |
| 178 return kCollectInfoSuccess; | |
| 179 #endif | |
| 180 } | |
| 181 | |
| 182 } // namespace anonymous | |
| 183 | |
| 184 CollectInfoResult CollectContextGraphicsInfo(GPUInfo* gpu_info) { | 31 CollectInfoResult CollectContextGraphicsInfo(GPUInfo* gpu_info) { |
| 185 DCHECK(gpu_info); | 32 DCHECK(gpu_info); |
| 186 | 33 |
| 187 TRACE_EVENT0("gpu", "gpu_info_collector::CollectGraphicsInfo"); | 34 TRACE_EVENT0("gpu", "gpu_info_collector::CollectGraphicsInfo"); |
| 188 | 35 |
| 189 CollectInfoResult result = CollectGraphicsInfoGL(gpu_info); | 36 CollectInfoResult result = CollectGraphicsInfoGL(gpu_info); |
| 190 gpu_info->context_info_state = result; | 37 gpu_info->context_info_state = result; |
| 191 return result; | 38 return result; |
| 192 } | 39 } |
| 193 | 40 |
| 194 CollectInfoResult CollectBasicGraphicsInfo(GPUInfo* gpu_info) { | 41 CollectInfoResult CollectBasicGraphicsInfo(GPUInfo* gpu_info) { |
| 195 DCHECK(gpu_info); | 42 DCHECK(gpu_info); |
| 196 | 43 |
| 197 CollectInfoResult result = CollectPCIVideoCardInfo(gpu_info); | 44 angle::SystemInfo system_info; |
| 198 | 45 if (angle::GetSystemInfo(&system_info)) { |
| 199 std::string driver_version; | 46 gpu_info->basic_info_state = kCollectInfoSuccess; |
| 200 switch (gpu_info->gpu.vendor_id) { | 47 FillGPUInfoFromSystemInfo(gpu_info, &system_info); |
| 201 case kVendorIDAMD: | 48 } else { |
| 202 driver_version = CollectDriverVersionAMDBrahma(); | 49 gpu_info->basic_info_state = kCollectInfoNonFatalFailure; |
| 203 if (!driver_version.empty()) { | |
| 204 gpu_info->driver_vendor = "ATI / AMD (Brahma)"; | |
| 205 gpu_info->driver_version = driver_version; | |
| 206 } else { | |
| 207 driver_version = CollectDriverVersionAMDCatalyst(); | |
| 208 if (!driver_version.empty()) { | |
| 209 gpu_info->driver_vendor = "ATI / AMD (Catalyst)"; | |
| 210 gpu_info->driver_version = driver_version; | |
| 211 } | |
| 212 } | |
| 213 break; | |
| 214 case kVendorIDNVidia: | |
| 215 driver_version = CollectDriverVersionNVidia(); | |
| 216 if (!driver_version.empty()) { | |
| 217 gpu_info->driver_vendor = "NVIDIA"; | |
| 218 gpu_info->driver_version = driver_version; | |
| 219 } | |
| 220 break; | |
| 221 case kVendorIDIntel: | |
| 222 // In dual-GPU cases, sometimes PCI scan only gives us the | |
| 223 // integrated GPU (i.e., the Intel one). | |
| 224 if (gpu_info->secondary_gpus.size() == 0) { | |
| 225 driver_version = CollectDriverVersionNVidia(); | |
| 226 if (!driver_version.empty()) { | |
| 227 gpu_info->driver_vendor = "NVIDIA"; | |
| 228 gpu_info->driver_version = driver_version; | |
| 229 gpu_info->optimus = true; | |
| 230 // Put Intel to the secondary GPU list. | |
| 231 gpu_info->secondary_gpus.push_back(gpu_info->gpu); | |
| 232 // Put NVIDIA as the primary GPU. | |
| 233 gpu_info->gpu.vendor_id = kVendorIDNVidia; | |
| 234 gpu_info->gpu.device_id = 0; // Unknown Device. | |
| 235 } | |
| 236 } | |
| 237 break; | |
| 238 } | 50 } |
| 239 | 51 |
| 240 gpu_info->basic_info_state = result; | 52 return gpu_info->basic_info_state; |
| 241 return result; | |
| 242 } | 53 } |
| 243 | 54 |
| 244 CollectInfoResult CollectDriverInfoGL(GPUInfo* gpu_info) { | 55 CollectInfoResult CollectDriverInfoGL(GPUInfo* gpu_info) { |
| 245 DCHECK(gpu_info); | 56 DCHECK(gpu_info); |
| 246 | 57 |
| 247 // Driver vendor and version are always expected to be extracted from the | 58 // Driver vendor and version are always expected to be extracted from the |
| 248 // testing gl version. | 59 // testing gl version. |
| 249 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | 60 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 250 switches::kGpuTestingGLVersion) && | 61 switches::kGpuTestingGLVersion) && |
| 251 !gpu_info->driver_vendor.empty() && !gpu_info->driver_version.empty()) { | 62 !gpu_info->driver_vendor.empty() && !gpu_info->driver_version.empty()) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 281 gpu_info->driver_version = driver_version; | 92 gpu_info->driver_version = driver_version; |
| 282 return kCollectInfoSuccess; | 93 return kCollectInfoSuccess; |
| 283 } | 94 } |
| 284 | 95 |
| 285 void MergeGPUInfo(GPUInfo* basic_gpu_info, | 96 void MergeGPUInfo(GPUInfo* basic_gpu_info, |
| 286 const GPUInfo& context_gpu_info) { | 97 const GPUInfo& context_gpu_info) { |
| 287 MergeGPUInfoGL(basic_gpu_info, context_gpu_info); | 98 MergeGPUInfoGL(basic_gpu_info, context_gpu_info); |
| 288 } | 99 } |
| 289 | 100 |
| 290 } // namespace gpu | 101 } // namespace gpu |
| OLD | NEW |