| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/gpu/gpu_info_collector.h" | 5 #include "content/gpu/gpu_info_collector.h" |
| 6 | 6 |
| 7 #include <dlfcn.h> | |
| 8 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
| 9 #include <vector> | 8 #include <vector> |
| 10 | 9 |
| 11 // TODO(phajdan.jr): Report problem upstream and make pci.h handle this. | |
| 12 extern "C" { | |
| 13 #include <pci/pci.h> | |
| 14 } | |
| 15 | |
| 16 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 17 #include "base/debug/trace_event.h" | 11 #include "base/debug/trace_event.h" |
| 18 #include "base/file_util.h" | 12 #include "base/file_util.h" |
| 19 #include "base/logging.h" | 13 #include "base/logging.h" |
| 20 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 21 #include "base/message_loop.h" | 15 #include "base/message_loop.h" |
| 22 #include "base/string_piece.h" | 16 #include "base/string_piece.h" |
| 23 #include "base/string_split.h" | 17 #include "base/string_split.h" |
| 24 #include "base/string_tokenizer.h" | 18 #include "base/string_tokenizer.h" |
| 25 #include "base/string_util.h" | 19 #include "base/string_util.h" |
| 20 #include "library_loaders/libpci.h" |
| 26 #include "third_party/libXNVCtrl/NVCtrl.h" | 21 #include "third_party/libXNVCtrl/NVCtrl.h" |
| 27 #include "third_party/libXNVCtrl/NVCtrlLib.h" | 22 #include "third_party/libXNVCtrl/NVCtrlLib.h" |
| 28 #include "ui/gl/gl_bindings.h" | 23 #include "ui/gl/gl_bindings.h" |
| 29 #include "ui/gl/gl_context.h" | 24 #include "ui/gl/gl_context.h" |
| 30 #include "ui/gl/gl_implementation.h" | 25 #include "ui/gl/gl_implementation.h" |
| 31 #include "ui/gl/gl_surface.h" | 26 #include "ui/gl/gl_surface.h" |
| 32 #include "ui/gl/gl_switches.h" | 27 #include "ui/gl/gl_switches.h" |
| 33 | 28 |
| 34 namespace { | 29 namespace { |
| 35 | 30 |
| 36 // Define function types. | |
| 37 typedef pci_access* (*FT_pci_alloc)(); | |
| 38 typedef void (*FT_pci_init)(pci_access*); | |
| 39 typedef void (*FT_pci_cleanup)(pci_access*); | |
| 40 typedef void (*FT_pci_scan_bus)(pci_access*); | |
| 41 typedef void (*FT_pci_scan_bus)(pci_access*); | |
| 42 typedef int (*FT_pci_fill_info)(pci_dev*, int); | |
| 43 typedef char* (*FT_pci_lookup_name)(pci_access*, char*, int, int, ...); | |
| 44 | |
| 45 // This includes dynamically linked library handle and functions pointers from | |
| 46 // libpci. | |
| 47 struct PciInterface { | |
| 48 void* lib_handle; | |
| 49 | |
| 50 FT_pci_alloc pci_alloc; | |
| 51 FT_pci_init pci_init; | |
| 52 FT_pci_cleanup pci_cleanup; | |
| 53 FT_pci_scan_bus pci_scan_bus; | |
| 54 FT_pci_fill_info pci_fill_info; | |
| 55 FT_pci_lookup_name pci_lookup_name; | |
| 56 }; | |
| 57 | |
| 58 // This checks if a system supports PCI bus. | 31 // This checks if a system supports PCI bus. |
| 59 // We check the existence of /sys/bus/pci or /sys/bug/pci_express. | 32 // We check the existence of /sys/bus/pci or /sys/bug/pci_express. |
| 60 bool IsPciSupported() { | 33 bool IsPciSupported() { |
| 61 const FilePath pci_path("/sys/bus/pci/"); | 34 const FilePath pci_path("/sys/bus/pci/"); |
| 62 const FilePath pcie_path("/sys/bus/pci_express/"); | 35 const FilePath pcie_path("/sys/bus/pci_express/"); |
| 63 return (file_util::PathExists(pci_path) || | 36 return (file_util::PathExists(pci_path) || |
| 64 file_util::PathExists(pcie_path)); | 37 file_util::PathExists(pcie_path)); |
| 65 } | 38 } |
| 66 | 39 |
| 67 // This dynamically opens libpci and get function pointers we need. Return | |
| 68 // NULL if library fails to open or any functions can not be located. | |
| 69 // Returned interface (if not NULL) should be deleted in FinalizeLibPci. | |
| 70 PciInterface* InitializeLibPci(const char* lib_name) { | |
| 71 scoped_ptr<PciInterface> interface(new PciInterface); | |
| 72 #if defined(DLOPEN_LIBPCI) | |
| 73 void* handle = dlopen(lib_name, RTLD_LAZY); | |
| 74 if (handle == NULL) { | |
| 75 VLOG(1) << "Failed to dlopen " << lib_name; | |
| 76 return NULL; | |
| 77 } | |
| 78 interface->lib_handle = handle; | |
| 79 interface->pci_alloc = reinterpret_cast<FT_pci_alloc>( | |
| 80 dlsym(handle, "pci_alloc")); | |
| 81 interface->pci_init = reinterpret_cast<FT_pci_init>( | |
| 82 dlsym(handle, "pci_init")); | |
| 83 interface->pci_cleanup = reinterpret_cast<FT_pci_cleanup>( | |
| 84 dlsym(handle, "pci_cleanup")); | |
| 85 interface->pci_scan_bus = reinterpret_cast<FT_pci_scan_bus>( | |
| 86 dlsym(handle, "pci_scan_bus")); | |
| 87 interface->pci_fill_info = reinterpret_cast<FT_pci_fill_info>( | |
| 88 dlsym(handle, "pci_fill_info")); | |
| 89 interface->pci_lookup_name = reinterpret_cast<FT_pci_lookup_name>( | |
| 90 dlsym(handle, "pci_lookup_name")); | |
| 91 if (interface->pci_alloc == NULL || | |
| 92 interface->pci_init == NULL || | |
| 93 interface->pci_cleanup == NULL || | |
| 94 interface->pci_scan_bus == NULL || | |
| 95 interface->pci_fill_info == NULL || | |
| 96 interface->pci_lookup_name == NULL) { | |
| 97 VLOG(1) << "Missing required function(s) from " << lib_name; | |
| 98 dlclose(handle); | |
| 99 return NULL; | |
| 100 } | |
| 101 #else // !defined(DLOPEN_LIBPCI) | |
| 102 interface->lib_handle = NULL; | |
| 103 interface->pci_alloc = reinterpret_cast<FT_pci_alloc>( | |
| 104 &pci_alloc); | |
| 105 interface->pci_init = reinterpret_cast<FT_pci_init>( | |
| 106 &pci_init); | |
| 107 interface->pci_cleanup = reinterpret_cast<FT_pci_cleanup>( | |
| 108 &pci_cleanup); | |
| 109 interface->pci_scan_bus = reinterpret_cast<FT_pci_scan_bus>( | |
| 110 &pci_scan_bus); | |
| 111 interface->pci_fill_info = reinterpret_cast<FT_pci_fill_info>( | |
| 112 &pci_fill_info); | |
| 113 interface->pci_lookup_name = reinterpret_cast<FT_pci_lookup_name>( | |
| 114 &pci_lookup_name); | |
| 115 #endif // !defined(DLOPEN_LIBPCI) | |
| 116 return interface.release(); | |
| 117 } | |
| 118 | |
| 119 // This close the dynamically opened libpci and delete the interface. | |
| 120 void FinalizeLibPci(PciInterface** interface) { | |
| 121 #if defined(DLOPEN_LIBPCI) | |
| 122 DCHECK(interface && *interface && (*interface)->lib_handle); | |
| 123 dlclose((*interface)->lib_handle); | |
| 124 #endif // defined(DLOPEN_LIBPCI) | |
| 125 delete (*interface); | |
| 126 *interface = NULL; | |
| 127 } | |
| 128 | |
| 129 // Scan /etc/ati/amdpcsdb.default for "ReleaseVersion". | 40 // Scan /etc/ati/amdpcsdb.default for "ReleaseVersion". |
| 130 // Return empty string on failing. | 41 // Return empty string on failing. |
| 131 std::string CollectDriverVersionATI() { | 42 std::string CollectDriverVersionATI() { |
| 132 const FilePath::CharType kATIFileName[] = | 43 const FilePath::CharType kATIFileName[] = |
| 133 FILE_PATH_LITERAL("/etc/ati/amdpcsdb.default"); | 44 FILE_PATH_LITERAL("/etc/ati/amdpcsdb.default"); |
| 134 FilePath ati_file_path(kATIFileName); | 45 FilePath ati_file_path(kATIFileName); |
| 135 if (!file_util::PathExists(ati_file_path)) | 46 if (!file_util::PathExists(ati_file_path)) |
| 136 return std::string(); | 47 return std::string(); |
| 137 std::string contents; | 48 std::string contents; |
| 138 if (!file_util::ReadFileToString(ati_file_path, &contents)) | 49 if (!file_util::ReadFileToString(ati_file_path, &contents)) |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 | 167 |
| 257 bool CollectVideoCardInfo(content::GPUInfo* gpu_info) { | 168 bool CollectVideoCardInfo(content::GPUInfo* gpu_info) { |
| 258 DCHECK(gpu_info); | 169 DCHECK(gpu_info); |
| 259 | 170 |
| 260 if (IsPciSupported() == false) { | 171 if (IsPciSupported() == false) { |
| 261 VLOG(1) << "PCI bus scanning is not supported"; | 172 VLOG(1) << "PCI bus scanning is not supported"; |
| 262 return false; | 173 return false; |
| 263 } | 174 } |
| 264 | 175 |
| 265 // TODO(zmo): be more flexible about library name. | 176 // TODO(zmo): be more flexible about library name. |
| 266 PciInterface* interface = InitializeLibPci("libpci.so.3"); | 177 LibPciLoader libpci_loader; |
| 267 if (interface == NULL) | 178 if (!libpci_loader.Load("libpci.so.3") && |
| 268 interface = InitializeLibPci("libpci.so"); | 179 !libpci_loader.Load("libpci.so")) { |
| 269 if (interface == NULL) { | |
| 270 VLOG(1) << "Failed to locate libpci"; | 180 VLOG(1) << "Failed to locate libpci"; |
| 271 return false; | 181 return false; |
| 272 } | 182 } |
| 273 | 183 |
| 274 pci_access* access = (interface->pci_alloc)(); | 184 pci_access* access = (libpci_loader.pci_alloc)(); |
| 275 DCHECK(access != NULL); | 185 DCHECK(access != NULL); |
| 276 (interface->pci_init)(access); | 186 (libpci_loader.pci_init)(access); |
| 277 (interface->pci_scan_bus)(access); | 187 (libpci_loader.pci_scan_bus)(access); |
| 278 bool primary_gpu_identified = false; | 188 bool primary_gpu_identified = false; |
| 279 for (pci_dev* device = access->devices; | 189 for (pci_dev* device = access->devices; |
| 280 device != NULL; device = device->next) { | 190 device != NULL; device = device->next) { |
| 281 (interface->pci_fill_info)(device, 33); // Fill the IDs and class fields. | 191 // Fill the IDs and class fields. |
| 192 (libpci_loader.pci_fill_info)(device, 33); |
| 282 // TODO(zmo): there might be other classes that qualify as display devices. | 193 // TODO(zmo): there might be other classes that qualify as display devices. |
| 283 if (device->device_class != 0x0300) // Device class is DISPLAY_VGA. | 194 if (device->device_class != 0x0300) // Device class is DISPLAY_VGA. |
| 284 continue; | 195 continue; |
| 285 | 196 |
| 286 content::GPUInfo::GPUDevice gpu; | 197 content::GPUInfo::GPUDevice gpu; |
| 287 gpu.vendor_id = device->vendor_id; | 198 gpu.vendor_id = device->vendor_id; |
| 288 gpu.device_id = device->device_id; | 199 gpu.device_id = device->device_id; |
| 289 | 200 |
| 290 const int buffer_size = 255; | 201 const int buffer_size = 255; |
| 291 scoped_array<char> buffer(new char[buffer_size]); | 202 scoped_array<char> buffer(new char[buffer_size]); |
| 292 // The current implementation of pci_lookup_name returns the same pointer | 203 // The current implementation of pci_lookup_name returns the same pointer |
| 293 // as the passed in upon success, and a different one (NULL or a pointer | 204 // as the passed in upon success, and a different one (NULL or a pointer |
| 294 // to an error message) upon failure. | 205 // to an error message) upon failure. |
| 295 if ((interface->pci_lookup_name)(access, | 206 if ((libpci_loader.pci_lookup_name)(access, |
| 296 buffer.get(), | 207 buffer.get(), |
| 297 buffer_size, | 208 buffer_size, |
| 298 1, | 209 1, |
| 299 device->vendor_id) == buffer.get()) { | 210 device->vendor_id) == buffer.get()) { |
| 300 gpu.vendor_string = buffer.get(); | 211 gpu.vendor_string = buffer.get(); |
| 301 } | 212 } |
| 302 if ((interface->pci_lookup_name)(access, | 213 if ((libpci_loader.pci_lookup_name)(access, |
| 303 buffer.get(), | 214 buffer.get(), |
| 304 buffer_size, | 215 buffer_size, |
| 305 2, | 216 2, |
| 306 device->vendor_id, | 217 device->vendor_id, |
| 307 device->device_id) == buffer.get()) { | 218 device->device_id) == buffer.get()) { |
| 308 std::string device_string = buffer.get(); | 219 std::string device_string = buffer.get(); |
| 309 size_t begin = device_string.find_first_of('['); | 220 size_t begin = device_string.find_first_of('['); |
| 310 size_t end = device_string.find_last_of(']'); | 221 size_t end = device_string.find_last_of(']'); |
| 311 if (begin != std::string::npos && end != std::string::npos && | 222 if (begin != std::string::npos && end != std::string::npos && |
| 312 begin < end) { | 223 begin < end) { |
| 313 device_string = device_string.substr(begin + 1, end - begin - 1); | 224 device_string = device_string.substr(begin + 1, end - begin - 1); |
| 314 } | 225 } |
| 315 gpu.device_string = device_string; | 226 gpu.device_string = device_string; |
| 316 } | 227 } |
| 317 | 228 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 334 | 245 |
| 335 // Detect Optimus or AMD Switchable GPU. | 246 // Detect Optimus or AMD Switchable GPU. |
| 336 if (gpu_info->secondary_gpus.size() == 1 && | 247 if (gpu_info->secondary_gpus.size() == 1 && |
| 337 gpu_info->secondary_gpus[0].vendor_id == kVendorIDIntel) { | 248 gpu_info->secondary_gpus[0].vendor_id == kVendorIDIntel) { |
| 338 if (gpu_info->gpu.vendor_id == kVendorIDNVidia) | 249 if (gpu_info->gpu.vendor_id == kVendorIDNVidia) |
| 339 gpu_info->optimus = true; | 250 gpu_info->optimus = true; |
| 340 if (gpu_info->gpu.vendor_id == kVendorIDAMD) | 251 if (gpu_info->gpu.vendor_id == kVendorIDAMD) |
| 341 gpu_info->amd_switchable = true; | 252 gpu_info->amd_switchable = true; |
| 342 } | 253 } |
| 343 | 254 |
| 344 (interface->pci_cleanup)(access); | 255 (libpci_loader.pci_cleanup)(access); |
| 345 FinalizeLibPci(&interface); | |
| 346 return (primary_gpu_identified); | 256 return (primary_gpu_identified); |
| 347 } | 257 } |
| 348 | 258 |
| 349 bool CollectDriverInfoGL(content::GPUInfo* gpu_info) { | 259 bool CollectDriverInfoGL(content::GPUInfo* gpu_info) { |
| 350 DCHECK(gpu_info); | 260 DCHECK(gpu_info); |
| 351 | 261 |
| 352 std::string gl_version_string = gpu_info->gl_version_string; | 262 std::string gl_version_string = gpu_info->gl_version_string; |
| 353 if (StartsWithASCII(gl_version_string, "OpenGL ES", true)) | 263 if (StartsWithASCII(gl_version_string, "OpenGL ES", true)) |
| 354 gl_version_string = gl_version_string.substr(10); | 264 gl_version_string = gl_version_string.substr(10); |
| 355 std::vector<std::string> pieces; | 265 std::vector<std::string> pieces; |
| 356 base::SplitStringAlongWhitespace(gl_version_string, &pieces); | 266 base::SplitStringAlongWhitespace(gl_version_string, &pieces); |
| 357 // In linux, the gl version string might be in the format of | 267 // In linux, the gl version string might be in the format of |
| 358 // GLVersion DriverVendor DriverVersion | 268 // GLVersion DriverVendor DriverVersion |
| 359 if (pieces.size() < 3) | 269 if (pieces.size() < 3) |
| 360 return false; | 270 return false; |
| 361 | 271 |
| 362 std::string driver_version = pieces[2]; | 272 std::string driver_version = pieces[2]; |
| 363 size_t pos = driver_version.find_first_not_of("0123456789."); | 273 size_t pos = driver_version.find_first_not_of("0123456789."); |
| 364 if (pos == 0) | 274 if (pos == 0) |
| 365 return false; | 275 return false; |
| 366 if (pos != std::string::npos) | 276 if (pos != std::string::npos) |
| 367 driver_version = driver_version.substr(0, pos); | 277 driver_version = driver_version.substr(0, pos); |
| 368 | 278 |
| 369 gpu_info->driver_vendor = pieces[1]; | 279 gpu_info->driver_vendor = pieces[1]; |
| 370 gpu_info->driver_version = driver_version; | 280 gpu_info->driver_version = driver_version; |
| 371 return true; | 281 return true; |
| 372 } | 282 } |
| 373 | 283 |
| 374 } // namespace gpu_info_collector | 284 } // namespace gpu_info_collector |
| OLD | NEW |