| 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> | 7 #include <dlfcn.h> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "app/gfx/gl/gl_bindings.h" | 10 #include "app/gfx/gl/gl_bindings.h" |
| 11 #include "app/gfx/gl/gl_context.h" | 11 #include "app/gfx/gl/gl_context.h" |
| 12 #include "app/gfx/gl/gl_implementation.h" | 12 #include "app/gfx/gl/gl_implementation.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/scoped_ptr.h" | 14 #include "base/scoped_ptr.h" |
| 15 #include "base/string_piece.h" |
| 16 #include "base/string_split.h" |
| 15 #include "base/string_util.h" | 17 #include "base/string_util.h" |
| 16 | 18 |
| 17 namespace { | 19 namespace { |
| 18 | 20 |
| 19 // PciDevice and PciAccess are defined to access libpci functions. Their | 21 // PciDevice and PciAccess are defined to access libpci functions. Their |
| 20 // members match the corresponding structures defined by libpci in size up to | 22 // 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 | 23 // 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 | 24 // defined as "fieldX", etc., or, left out if they are declared after the |
| 23 // members we care about in libpci. | 25 // members we care about in libpci. |
| 24 | 26 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 interface->pci_lookup_name == NULL) { | 108 interface->pci_lookup_name == NULL) { |
| 107 LOG(ERROR) << "Missing required function(s) from libpci"; | 109 LOG(ERROR) << "Missing required function(s) from libpci"; |
| 108 dlclose(handle); | 110 dlclose(handle); |
| 109 delete interface; | 111 delete interface; |
| 110 return NULL; | 112 return NULL; |
| 111 } | 113 } |
| 112 return interface; | 114 return interface; |
| 113 } | 115 } |
| 114 | 116 |
| 115 // This close the dynamically opened libpci and delete the interface. | 117 // This close the dynamically opened libpci and delete the interface. |
| 116 void FinalizeLibPci(PciInterface*& interface) { | 118 void FinalizeLibPci(PciInterface** interface) { |
| 117 DCHECK(interface != NULL && interface->lib_handle != NULL); | 119 DCHECK(interface && *interface && (*interface)->lib_handle); |
| 118 dlclose(interface->lib_handle); | 120 dlclose((*interface)->lib_handle); |
| 119 delete interface; | 121 delete (*interface); |
| 120 interface = NULL; | 122 *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 } | 123 } |
| 151 | 124 |
| 152 } // namespace anonymous | 125 } // namespace anonymous |
| 153 | 126 |
| 154 namespace gpu_info_collector { | 127 namespace gpu_info_collector { |
| 155 | 128 |
| 156 bool CollectGraphicsInfo(GPUInfo* gpu_info) { | 129 bool CollectGraphicsInfo(GPUInfo* gpu_info) { |
| 157 gfx::GLContext* context = InitializeGLContext(); | 130 DCHECK(gpu_info); |
| 158 if (context == NULL) | |
| 159 return false; | |
| 160 | 131 |
| 161 // TODO(zmo): collect driver version, pixel shader version, vertex shader | 132 // TODO(zmo): need to consider the case where we are running on top of |
| 162 // version, and gl version. | 133 // desktop GL and GL_ARB_robustness extension is available. |
| 163 std::wstring driver_version = L""; | 134 gpu_info->SetCanLoseContext( |
| 164 uint32 pixel_shader_version = 0; | 135 gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2); |
| 165 uint32 vertex_shader_version = 0; | 136 gpu_info->SetProgress(GPUInfo::kComplete); |
| 166 uint32 gl_version = 0; | 137 return CollectGraphicsInfoGL(gpu_info); |
| 167 bool can_lose_context = | 138 } |
| 168 (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2); | 139 |
| 140 bool CollectVideoCardInfo(GPUInfo* gpu_info) { |
| 141 DCHECK(gpu_info); |
| 169 | 142 |
| 170 // TODO(zmo): be more flexible about library name. | 143 // TODO(zmo): be more flexible about library name. |
| 171 PciInterface* interface = InitializeLibPci("libpci.so.3"); | 144 PciInterface* interface = InitializeLibPci("libpci.so.3"); |
| 172 if (interface == NULL) { | 145 if (interface == NULL) |
| 173 FinalizeGLContext(context); | |
| 174 return false; | 146 return false; |
| 175 } | |
| 176 | 147 |
| 177 PciAccess* access = (interface->pci_alloc)(); | 148 PciAccess* access = (interface->pci_alloc)(); |
| 178 DCHECK(access != NULL); | 149 DCHECK(access != NULL); |
| 179 (interface->pci_init)(access); | 150 (interface->pci_init)(access); |
| 180 (interface->pci_scan_bus)(access); | 151 (interface->pci_scan_bus)(access); |
| 181 std::vector<PciDevice*> gpu_list; | 152 std::vector<PciDevice*> gpu_list; |
| 182 PciDevice* gpu_active = NULL; | 153 PciDevice* gpu_active = NULL; |
| 183 for (PciDevice* device = access->device_list; | 154 for (PciDevice* device = access->device_list; |
| 184 device != NULL; device = device->next) { | 155 device != NULL; device = device->next) { |
| 185 (interface->pci_fill_info)(device, 33); // Fill the IDs and class fields. | 156 (interface->pci_fill_info)(device, 33); // Fill the IDs and class fields. |
| 157 // TODO(zmo): there might be other classes that qualify as display devices. |
| 186 if (device->device_class == 0x0300) { // Device class is DISPLAY_VGA. | 158 if (device->device_class == 0x0300) { // Device class is DISPLAY_VGA. |
| 187 gpu_list.push_back(device); | 159 gpu_list.push_back(device); |
| 188 } | 160 } |
| 189 } | 161 } |
| 190 if (gpu_list.size() == 1) { | 162 if (gpu_list.size() == 1) { |
| 191 gpu_active = gpu_list[0]; | 163 gpu_active = gpu_list[0]; |
| 192 } else { | 164 } else { |
| 193 // If more than one graphics card are identified, find the one that matches | 165 // If more than one graphics card are identified, find the one that matches |
| 194 // gl VENDOR and RENDERER info. | 166 // gl VENDOR and RENDERER info. |
| 195 std::string gl_vendor_string = | 167 std::string gl_vendor_string = gpu_info->gl_vendor(); |
| 196 reinterpret_cast<const char*>(glGetString(GL_VENDOR)); | 168 std::string gl_renderer_string = gpu_info->gl_renderer(); |
| 197 std::string gl_renderer_string = | |
| 198 reinterpret_cast<const char*>(glGetString(GL_RENDERER)); | |
| 199 const int buffer_size = 255; | 169 const int buffer_size = 255; |
| 200 scoped_array<char> buffer(new char[buffer_size]); | 170 scoped_array<char> buffer(new char[buffer_size]); |
| 201 std::vector<PciDevice*> candidates; | 171 std::vector<PciDevice*> candidates; |
| 202 for (size_t i = 0; i < gpu_list.size(); ++i) { | 172 for (size_t i = 0; i < gpu_list.size(); ++i) { |
| 203 PciDevice* gpu = gpu_list[i]; | 173 PciDevice* gpu = gpu_list[i]; |
| 204 // The current implementation of pci_lookup_name returns the same pointer | 174 // The current implementation of pci_lookup_name returns the same pointer |
| 205 // as the passed in upon success, and a different one (NULL or a pointer | 175 // as the passed in upon success, and a different one (NULL or a pointer |
| 206 // to an error message) upon failure. | 176 // to an error message) upon failure. |
| 207 if ((interface->pci_lookup_name)(access, | 177 if ((interface->pci_lookup_name)(access, |
| 208 buffer.get(), | 178 buffer.get(), |
| (...skipping 24 matching lines...) Expand all Loading... |
| 233 break; | 203 break; |
| 234 } | 204 } |
| 235 // If a device's vendor matches gl VENDOR string, we want to consider the | 205 // If a device's vendor matches gl VENDOR string, we want to consider the |
| 236 // possibility that libpci may not return the exact same name as gl | 206 // possibility that libpci may not return the exact same name as gl |
| 237 // RENDERER string. | 207 // RENDERER string. |
| 238 candidates.push_back(gpu); | 208 candidates.push_back(gpu); |
| 239 } | 209 } |
| 240 if (gpu_active == NULL && candidates.size() == 1) | 210 if (gpu_active == NULL && candidates.size() == 1) |
| 241 gpu_active = candidates[0]; | 211 gpu_active = candidates[0]; |
| 242 } | 212 } |
| 243 if (gpu_active != NULL) { | 213 if (gpu_active != NULL) |
| 244 gpu_info->SetGraphicsInfo(gpu_active->vendor_id, | 214 gpu_info->SetVideoCardInfo(gpu_active->vendor_id, gpu_active->device_id); |
| 245 gpu_active->device_id, | |
| 246 driver_version, | |
| 247 pixel_shader_version, | |
| 248 vertex_shader_version, | |
| 249 gl_version, | |
| 250 can_lose_context); | |
| 251 gpu_info->SetProgress(GPUInfo::kComplete); | |
| 252 } | |
| 253 (interface->pci_cleanup)(access); | 215 (interface->pci_cleanup)(access); |
| 254 FinalizeLibPci(interface); | 216 FinalizeLibPci(&interface); |
| 255 FinalizeGLContext(context); | |
| 256 return (gpu_active != NULL); | 217 return (gpu_active != NULL); |
| 257 } | 218 } |
| 258 | 219 |
| 220 bool CollectDriverInfo(GPUInfo* gpu_info) { |
| 221 DCHECK(gpu_info); |
| 222 |
| 223 std::string gl_version_string = gpu_info->gl_version_string(); |
| 224 std::vector<std::string> pieces; |
| 225 base::SplitStringAlongWhitespace(gl_version_string, &pieces); |
| 226 // In linux, the gl version string might be in the format of |
| 227 // GLVersion DriverVendor DriverVersion |
| 228 if (pieces.size() < 3) |
| 229 return false; |
| 230 |
| 231 std::string driver_version = pieces[2]; |
| 232 size_t pos = driver_version.find_first_not_of("0123456789."); |
| 233 if (pos == 0) |
| 234 return false; |
| 235 if (pos != std::string::npos) |
| 236 driver_version = driver_version.substr(0, pos); |
| 237 |
| 238 gpu_info->SetDriverInfo(pieces[1], driver_version); |
| 239 return true; |
| 240 } |
| 241 |
| 259 } // namespace gpu_info_collector | 242 } // namespace gpu_info_collector |
| OLD | NEW |