Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2010 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 "chrome/gpu/gpu_info_collector.h" | 5 #include "chrome/gpu/gpu_info_collector.h" |
| 6 | 6 |
| 7 #include <dlfcn.h> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "app/gfx/gl/gl_bindings.h" | |
| 11 #include "app/gfx/gl/gl_context.h" | |
| 12 #include "app/gfx/gl/gl_implementation.h" | |
| 13 #include "base/logging.h" | |
| 14 #include "base/scoped_ptr.h" | |
| 15 #include "base/string_util.h" | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 // PciDevice and PciAccess are defined to access libpci functions. Their | |
| 20 // members match the corresponding structures defined by libpci in size up to | |
| 21 // fields we may access. For those members we don't use, their names are | |
| 22 // defined as "fieldX", etc., or, left out if they are declared after the | |
| 23 // members we care about in libpci. | |
| 24 | |
| 25 struct PciDevice { | |
| 26 PciDevice* next; | |
| 27 | |
| 28 uint16 field0; | |
| 29 uint8 field1; | |
| 30 uint8 field2; | |
| 31 uint8 field3; | |
| 32 int field4; | |
| 33 | |
| 34 uint16 vendor_id; | |
| 35 uint16 device_id; | |
| 36 uint16 device_class; | |
| 37 }; | |
| 38 | |
| 39 struct PciAccess { | |
| 40 unsigned int field0; | |
| 41 int field1; | |
| 42 int field2; | |
| 43 char* field3; | |
| 44 int field4; | |
| 45 int field5; | |
| 46 unsigned int field6; | |
| 47 int field7; | |
| 48 | |
| 49 void (*function0)(); | |
| 50 void (*function1)(); | |
| 51 void (*function2)(); | |
| 52 | |
| 53 PciDevice* device_list; | |
| 54 }; | |
| 55 | |
| 56 // Define function types. | |
| 57 typedef PciAccess* (*FT_pci_alloc)(); | |
| 58 typedef void (*FT_pci_init)(PciAccess*); | |
| 59 typedef void (*FT_pci_cleanup)(PciAccess*); | |
| 60 typedef void (*FT_pci_scan_bus)(PciAccess*); | |
| 61 typedef void (*FT_pci_scan_bus)(PciAccess*); | |
| 62 typedef int (*FT_pci_fill_info)(PciDevice*, int); | |
| 63 typedef char* (*FT_pci_lookup_name)(PciAccess*, char*, int, int, ...); | |
| 64 | |
| 65 // This includes dynamically linked library handle and functions pointers from | |
| 66 // libpci. | |
| 67 struct PciInterface { | |
| 68 void* lib_handle; | |
| 69 | |
| 70 FT_pci_alloc pci_alloc; | |
| 71 FT_pci_init pci_init; | |
| 72 FT_pci_cleanup pci_cleanup; | |
| 73 FT_pci_scan_bus pci_scan_bus; | |
| 74 FT_pci_fill_info pci_fill_info; | |
| 75 FT_pci_lookup_name pci_lookup_name; | |
| 76 }; | |
| 77 | |
| 78 // This dynamically opens libpci and get function pointers we need. Return | |
| 79 // NULL if library fails to open or any functions can not be located. | |
| 80 // Returned interface (if not NULL) should be deleted in FinalizeLibPci. | |
| 81 PciInterface* InitializeLibPci(const char* lib_name) { | |
| 82 void* handle = dlopen(lib_name, RTLD_LAZY); | |
| 83 if (handle == NULL) { | |
| 84 LOG(ERROR) << "Fail to dlopen libpci"; | |
| 85 return NULL; | |
| 86 } | |
| 87 PciInterface* interface = new struct PciInterface; | |
| 88 interface->lib_handle = handle; | |
| 89 interface->pci_alloc = reinterpret_cast<FT_pci_alloc>( | |
| 90 dlsym(handle, "pci_alloc")); | |
| 91 interface->pci_init = reinterpret_cast<FT_pci_init>( | |
| 92 dlsym(handle, "pci_init")); | |
| 93 interface->pci_cleanup = reinterpret_cast<FT_pci_cleanup>( | |
| 94 dlsym(handle, "pci_cleanup")); | |
| 95 interface->pci_scan_bus = reinterpret_cast<FT_pci_scan_bus>( | |
| 96 dlsym(handle, "pci_scan_bus")); | |
| 97 interface->pci_fill_info = reinterpret_cast<FT_pci_fill_info>( | |
| 98 dlsym(handle, "pci_fill_info")); | |
| 99 interface->pci_lookup_name = reinterpret_cast<FT_pci_lookup_name>( | |
| 100 dlsym(handle, "pci_lookup_name")); | |
| 101 if (interface->pci_alloc == NULL || | |
| 102 interface->pci_init == NULL || | |
| 103 interface->pci_cleanup == NULL || | |
| 104 interface->pci_scan_bus == NULL || | |
| 105 interface->pci_fill_info == NULL || | |
| 106 interface->pci_lookup_name == NULL) { | |
| 107 LOG(ERROR) << "Missing required function(s) from libpci"; | |
| 108 dlclose(handle); | |
| 109 delete interface; | |
| 110 return NULL; | |
| 111 } | |
| 112 return interface; | |
| 113 } | |
| 114 | |
| 115 // This close the dynamically opened libpci and delete the interface. | |
| 116 void FinalizeLibPci(PciInterface*& interface) { | |
| 117 DCHECK(interface != NULL && interface->lib_handle != NULL); | |
| 118 dlclose(interface->lib_handle); | |
| 119 delete interface; | |
| 120 interface = NULL; | |
| 121 } | |
| 122 | |
| 123 // This creates an offscreen GL context for gl queries. Returned GLContext | |
| 124 // should be deleted in FinalizeGLContext. | |
| 125 gfx::GLContext* InitializeGLContext() { | |
| 126 if (!gfx::GLContext::InitializeOneOff()) { | |
| 127 LOG(ERROR) << "gfx::GLContext::InitializeOneOff() failed"; | |
| 128 return NULL; | |
| 129 } | |
| 130 gfx::GLContext* context = gfx::GLContext::CreateOffscreenGLContext(NULL); | |
| 131 if (context == NULL) { | |
| 132 LOG(ERROR) << "gfx::GLContext::CreateOffscreenGLContext(NULL) failed"; | |
| 133 return NULL; | |
| 134 } | |
| 135 if (!context->MakeCurrent()) { | |
| 136 LOG(ERROR) << "gfx::GLContext::MakeCurrent() failed"; | |
| 137 context->Destroy(); | |
| 138 delete context; | |
| 139 return NULL; | |
| 140 } | |
| 141 return context; | |
| 142 } | |
| 143 | |
| 144 // This destroy and delete the GL context. | |
| 145 void FinalizeGLContext(gfx::GLContext*& context) { | |
| 146 DCHECK(context != NULL); | |
| 147 context->Destroy(); | |
| 148 delete context; | |
| 149 context = NULL; | |
| 150 } | |
| 151 | |
| 152 } // namespace anonymous | |
| 153 | |
| 7 namespace gpu_info_collector { | 154 namespace gpu_info_collector { |
| 8 | 155 |
| 9 bool CollectGraphicsInfo(GPUInfo* gpu_info) { | 156 bool CollectGraphicsInfo(GPUInfo* gpu_info) { |
| 10 // TODO(rlp): complete this function | 157 gfx::GLContext* context = InitializeGLContext(); |
| 11 // TODO(apatrick): this illustrates how can_lose_context will be implemented | 158 if (context == NULL) |
| 12 // on this platform in the future. | 159 return false; |
| 13 // bool can_lose_context = | 160 |
| 14 // gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2; | 161 // TODO(zmo): collect driver version, pixel shader version, vertex shader |
| 15 | 162 // version, and gl version. |
| 16 gpu_info->SetProgress(GPUInfo::kComplete); | 163 std::wstring driver_version = L""; |
| 17 | 164 uint32 pixel_shader_version = 0; |
| 18 return true; | 165 uint32 vertex_shader_version = 0; |
| 166 uint32 gl_version = 0; | |
| 167 bool can_lose_context = | |
| 168 (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2); | |
| 169 | |
| 170 // TODO(zmo): be more flexible about library name. | |
| 171 PciInterface* interface = InitializeLibPci("libpci.so.3"); | |
| 172 if (interface == NULL) { | |
| 173 FinalizeGLContext(context); | |
| 174 return false; | |
| 175 } | |
| 176 | |
| 177 PciAccess* access = (interface->pci_alloc)(); | |
| 178 DCHECK(access != NULL); | |
| 179 (interface->pci_init)(access); | |
| 180 (interface->pci_scan_bus)(access); | |
| 181 std::vector<PciDevice*> gpu_list; | |
| 182 PciDevice* gpu_active = NULL; | |
| 183 for (PciDevice* device = access->device_list; | |
| 184 device != NULL; device = device->next) { | |
| 185 (interface->pci_fill_info)(device, 33); // Fill the IDs and class fields. | |
| 186 if (device->device_class == 0x0300) { // Device class is DISPLAY_VGA. | |
| 187 gpu_list.push_back(device); | |
| 188 } | |
| 189 } | |
| 190 if (gpu_list.size() == 1) { | |
| 191 gpu_active = gpu_list[0]; | |
| 192 } else { | |
| 193 // If more than one graphics card are identified, find the one that matches | |
| 194 // gl VENDOR and RENDERER info. | |
| 195 std::string gl_vendor_string = | |
| 196 reinterpret_cast<const char*>(glGetString(GL_VENDOR)); | |
| 197 std::string gl_renderer_string = | |
| 198 reinterpret_cast<const char*>(glGetString(GL_RENDERER)); | |
| 199 const int buffer_size = 255; | |
| 200 scoped_array<char> buffer(new char[buffer_size]); | |
| 201 std::vector<PciDevice*> candidates; | |
| 202 for (size_t i = 0; i < gpu_list.size(); ++i) { | |
| 203 PciDevice* gpu = gpu_list[i]; | |
| 204 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
| |
| 205 buffer.get(), | |
| 206 buffer_size, | |
| 207 1, | |
| 208 gpu->vendor_id) != buffer.get()) | |
| 209 continue; | |
| 210 std::string vendor_string = buffer.get(); | |
| 211 const bool kCaseSensitive = false; | |
| 212 if (!StartsWithASCII(gl_vendor_string, vendor_string, kCaseSensitive)) | |
| 213 continue; | |
| 214 if ((interface->pci_lookup_name)(access, | |
| 215 buffer.get(), | |
| 216 buffer_size, | |
| 217 2, | |
| 218 gpu->vendor_id, | |
| 219 gpu->device_id) != buffer.get()) | |
| 220 continue; | |
| 221 std::string device_string = buffer.get(); | |
| 222 size_t begin = device_string.find_first_of('['); | |
| 223 size_t end = device_string.find_last_of(']'); | |
| 224 if (begin != std::string::npos && end != std::string::npos && | |
| 225 begin < end) { | |
| 226 device_string = device_string.substr(begin + 1, end - begin - 1); | |
| 227 } | |
| 228 if (StartsWithASCII(gl_renderer_string, device_string, kCaseSensitive)) { | |
| 229 gpu_active = gpu; | |
| 230 break; | |
| 231 } | |
| 232 // If a device's vendor matches gl VENDOR string, we want to consider the | |
| 233 // possibility that libpci may not return the exact same name as gl | |
| 234 // RENDERER string. | |
| 235 candidates.push_back(gpu); | |
| 236 } | |
| 237 if (gpu_active == NULL && candidates.size() == 1) | |
| 238 gpu_active = candidates[0]; | |
| 239 } | |
| 240 if (gpu_active != NULL) { | |
| 241 gpu_info->SetGraphicsInfo(gpu_active->vendor_id, | |
| 242 gpu_active->device_id, | |
| 243 driver_version, | |
| 244 pixel_shader_version, | |
| 245 vertex_shader_version, | |
| 246 gl_version, | |
| 247 can_lose_context); | |
| 248 gpu_info->SetProgress(GPUInfo::kComplete); | |
| 249 } | |
| 250 (interface->pci_cleanup)(access); | |
| 251 FinalizeLibPci(interface); | |
| 252 FinalizeGLContext(context); | |
| 253 return (gpu_active != NULL); | |
| 19 } | 254 } |
| 20 | 255 |
| 21 } // namespace gpu_info_collector | 256 } // namespace gpu_info_collector |
| OLD | NEW |