Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(769)

Side by Side Diff: content/gpu/gpu_info_collector_linux.cc

Issue 11415138: Linux: create a library loader code generator for dlopen and use it for libpci. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/content_gpu.gypi ('k') | tools/generate_library_loader/generate_library_loader.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « content/content_gpu.gypi ('k') | tools/generate_library_loader/generate_library_loader.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698