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 |