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

Unified Diff: chrome/gpu/gpu_info_collector_linux.cc

Issue 5861007: Collect GPU information (vendor id and device id) in Linux.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Resonding to kbr's review Created 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/gpu/gpu_info_collector_linux.cc
===================================================================
--- chrome/gpu/gpu_info_collector_linux.cc (revision 69274)
+++ chrome/gpu/gpu_info_collector_linux.cc (working copy)
@@ -4,18 +4,253 @@
#include "chrome/gpu/gpu_info_collector.h"
+#include <dlfcn.h>
+#include <vector>
+
+#include "app/gfx/gl/gl_bindings.h"
+#include "app/gfx/gl/gl_context.h"
+#include "app/gfx/gl/gl_implementation.h"
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+
+namespace {
+
+// PciDevice and PciAccess are defined to access libpci functions. Their
+// members match the corresponding structures defined by libpci in size up to
+// fields we may access. For those members we don't use, their names are
+// defined as "fieldX", etc., or, left out if they are declared after the
+// members we care about in libpci.
+
+struct PciDevice {
+ PciDevice* next;
+
+ uint16 field0;
+ uint8 field1;
+ uint8 field2;
+ uint8 field3;
+ int field4;
+
+ uint16 vendor_id;
+ uint16 device_id;
+ uint16 device_class;
+};
+
+struct PciAccess {
+ unsigned int field0;
+ int field1;
+ int field2;
+ char* field3;
+ int field4;
+ int field5;
+ unsigned int field6;
+ int field7;
+
+ void (*function0)();
+ void (*function1)();
+ void (*function2)();
+
+ PciDevice* device_list;
+};
+
+// Define function types.
+typedef PciAccess* (*FT_pci_alloc)();
+typedef void (*FT_pci_init)(PciAccess*);
+typedef void (*FT_pci_cleanup)(PciAccess*);
+typedef void (*FT_pci_scan_bus)(PciAccess*);
+typedef void (*FT_pci_scan_bus)(PciAccess*);
+typedef int (*FT_pci_fill_info)(PciDevice*, int);
+typedef char* (*FT_pci_lookup_name)(PciAccess*, char*, int, int, ...);
+
+// This includes dynamically linked library handle and functions pointers from
+// libpci.
+struct PciInterface {
+ void* lib_handle;
+
+ FT_pci_alloc pci_alloc;
+ FT_pci_init pci_init;
+ FT_pci_cleanup pci_cleanup;
+ FT_pci_scan_bus pci_scan_bus;
+ FT_pci_fill_info pci_fill_info;
+ FT_pci_lookup_name pci_lookup_name;
+};
+
+// This dynamically opens libpci and get function pointers we need. Return
+// NULL if library fails to open or any functions can not be located.
+// Returned interface (if not NULL) should be deleted in FinalizeLibPci.
+PciInterface* InitializeLibPci(const char* lib_name) {
+ void* handle = dlopen(lib_name, RTLD_LAZY);
+ if (handle == NULL) {
+ LOG(ERROR) << "Fail to dlopen libpci";
+ return NULL;
+ }
+ PciInterface* interface = new struct PciInterface;
+ interface->lib_handle = handle;
+ interface->pci_alloc = reinterpret_cast<FT_pci_alloc>(
+ dlsym(handle, "pci_alloc"));
+ interface->pci_init = reinterpret_cast<FT_pci_init>(
+ dlsym(handle, "pci_init"));
+ interface->pci_cleanup = reinterpret_cast<FT_pci_cleanup>(
+ dlsym(handle, "pci_cleanup"));
+ interface->pci_scan_bus = reinterpret_cast<FT_pci_scan_bus>(
+ dlsym(handle, "pci_scan_bus"));
+ interface->pci_fill_info = reinterpret_cast<FT_pci_fill_info>(
+ dlsym(handle, "pci_fill_info"));
+ interface->pci_lookup_name = reinterpret_cast<FT_pci_lookup_name>(
+ dlsym(handle, "pci_lookup_name"));
+ if (interface->pci_alloc == NULL ||
+ interface->pci_init == NULL ||
+ interface->pci_cleanup == NULL ||
+ interface->pci_scan_bus == NULL ||
+ interface->pci_fill_info == NULL ||
+ interface->pci_lookup_name == NULL) {
+ LOG(ERROR) << "Missing required function(s) from libpci";
+ dlclose(handle);
+ delete interface;
+ return NULL;
+ }
+ return interface;
+}
+
+// This close the dynamically opened libpci and delete the interface.
+void FinalizeLibPci(PciInterface*& interface) {
+ DCHECK(interface != NULL && interface->lib_handle != NULL);
+ dlclose(interface->lib_handle);
+ delete interface;
+ interface = NULL;
+}
+
+// This creates an offscreen GL context for gl queries. Returned GLContext
+// should be deleted in FinalizeGLContext.
+gfx::GLContext* InitializeGLContext() {
+ if (!gfx::GLContext::InitializeOneOff()) {
+ LOG(ERROR) << "gfx::GLContext::InitializeOneOff() failed";
+ return NULL;
+ }
+ gfx::GLContext* context = gfx::GLContext::CreateOffscreenGLContext(NULL);
+ if (context == NULL) {
+ LOG(ERROR) << "gfx::GLContext::CreateOffscreenGLContext(NULL) failed";
+ return NULL;
+ }
+ if (!context->MakeCurrent()) {
+ LOG(ERROR) << "gfx::GLContext::MakeCurrent() failed";
+ context->Destroy();
+ delete context;
+ return NULL;
+ }
+ return context;
+}
+
+// This destroy and delete the GL context.
+void FinalizeGLContext(gfx::GLContext*& context) {
+ DCHECK(context != NULL);
+ context->Destroy();
+ delete context;
+ context = NULL;
+}
+
+} // namespace anonymous
+
namespace gpu_info_collector {
bool CollectGraphicsInfo(GPUInfo* gpu_info) {
- // TODO(rlp): complete this function
- // TODO(apatrick): this illustrates how can_lose_context will be implemented
- // on this platform in the future.
- // bool can_lose_context =
- // gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2;
+ gfx::GLContext* context = InitializeGLContext();
+ if (context == NULL)
+ return false;
- gpu_info->SetProgress(GPUInfo::kComplete);
+ // TODO(zmo): collect driver version, pixel shader version, vertex shader
+ // version, and gl version.
+ std::wstring driver_version = L"";
+ uint32 pixel_shader_version = 0;
+ uint32 vertex_shader_version = 0;
+ uint32 gl_version = 0;
+ bool can_lose_context =
+ (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2);
- return true;
+ // TODO(zmo): be more flexible about library name.
+ PciInterface* interface = InitializeLibPci("libpci.so.3");
+ if (interface == NULL) {
+ FinalizeGLContext(context);
+ return false;
+ }
+
+ PciAccess* access = (interface->pci_alloc)();
+ DCHECK(access != NULL);
+ (interface->pci_init)(access);
+ (interface->pci_scan_bus)(access);
+ std::vector<PciDevice*> gpu_list;
+ PciDevice* gpu_active = NULL;
+ for (PciDevice* device = access->device_list;
+ device != NULL; device = device->next) {
+ (interface->pci_fill_info)(device, 33); // Fill the IDs and class fields.
+ if (device->device_class == 0x0300) { // Device class is DISPLAY_VGA.
+ gpu_list.push_back(device);
+ }
+ }
+ if (gpu_list.size() == 1) {
+ gpu_active = gpu_list[0];
+ } else {
+ // If more than one graphics card are identified, find the one that matches
+ // gl VENDOR and RENDERER info.
+ std::string gl_vendor_string =
+ reinterpret_cast<const char*>(glGetString(GL_VENDOR));
+ std::string gl_renderer_string =
+ reinterpret_cast<const char*>(glGetString(GL_RENDERER));
+ const int buffer_size = 255;
+ scoped_array<char> buffer(new char[buffer_size]);
+ std::vector<PciDevice*> candidates;
+ for (size_t i = 0; i < gpu_list.size(); ++i) {
+ PciDevice* gpu = gpu_list[i];
+ if ((interface->pci_lookup_name)(access,
Ken Russell (switch to Gerrit) 2010/12/20 19:52:54 Add a comment indicating that the current implemen
+ buffer.get(),
+ buffer_size,
+ 1,
+ gpu->vendor_id) != buffer.get())
+ continue;
+ std::string vendor_string = buffer.get();
+ const bool kCaseSensitive = false;
+ if (!StartsWithASCII(gl_vendor_string, vendor_string, kCaseSensitive))
+ continue;
+ if ((interface->pci_lookup_name)(access,
+ buffer.get(),
+ buffer_size,
+ 2,
+ gpu->vendor_id,
+ gpu->device_id) != buffer.get())
+ continue;
+ std::string device_string = buffer.get();
+ size_t begin = device_string.find_first_of('[');
+ size_t end = device_string.find_last_of(']');
+ if (begin != std::string::npos && end != std::string::npos &&
+ begin < end) {
+ device_string = device_string.substr(begin + 1, end - begin - 1);
+ }
+ if (StartsWithASCII(gl_renderer_string, device_string, kCaseSensitive)) {
+ gpu_active = gpu;
+ break;
+ }
+ // If a device's vendor matches gl VENDOR string, we want to consider the
+ // possibility that libpci may not return the exact same name as gl
+ // RENDERER string.
+ candidates.push_back(gpu);
+ }
+ if (gpu_active == NULL && candidates.size() == 1)
+ gpu_active = candidates[0];
+ }
+ if (gpu_active != NULL) {
+ gpu_info->SetGraphicsInfo(gpu_active->vendor_id,
+ gpu_active->device_id,
+ driver_version,
+ pixel_shader_version,
+ vertex_shader_version,
+ gl_version,
+ can_lose_context);
+ gpu_info->SetProgress(GPUInfo::kComplete);
+ }
+ (interface->pci_cleanup)(access);
+ FinalizeLibPci(interface);
+ FinalizeGLContext(context);
+ return (gpu_active != NULL);
}
} // namespace gpu_info_collector
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698