| 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> | 7 #include <dlfcn.h> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 if (end == std::string::npos) | 157 if (end == std::string::npos) |
| 158 return line.substr(begin); | 158 return line.substr(begin); |
| 159 else | 159 else |
| 160 return line.substr(begin, end - begin); | 160 return line.substr(begin, end - begin); |
| 161 } | 161 } |
| 162 } | 162 } |
| 163 } | 163 } |
| 164 return ""; | 164 return ""; |
| 165 } | 165 } |
| 166 | 166 |
| 167 const uint32 kVendorIDIntel = 0x8086; |
| 168 const uint32 kVendorIDNVidia = 0x10de; |
| 169 const uint32 kVendorIDAMD = 0x1002; |
| 170 |
| 167 } // namespace anonymous | 171 } // namespace anonymous |
| 168 | 172 |
| 169 namespace gpu_info_collector { | 173 namespace gpu_info_collector { |
| 170 | 174 |
| 171 bool CollectGraphicsInfo(content::GPUInfo* gpu_info) { | 175 bool CollectGraphicsInfo(content::GPUInfo* gpu_info) { |
| 172 DCHECK(gpu_info); | 176 DCHECK(gpu_info); |
| 173 | 177 |
| 174 if (CommandLine::ForCurrentProcess()->HasSwitch( | 178 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 175 switches::kGpuNoContextLost)) { | 179 switches::kGpuNoContextLost)) { |
| 176 gpu_info->can_lose_context = false; | 180 gpu_info->can_lose_context = false; |
| 177 } else { | 181 } else { |
| 178 // TODO(zmo): need to consider the case where we are running on top | 182 // TODO(zmo): need to consider the case where we are running on top |
| 179 // of desktop GL and GL_ARB_robustness extension is available. | 183 // of desktop GL and GL_ARB_robustness extension is available. |
| 180 gpu_info->can_lose_context = | 184 gpu_info->can_lose_context = |
| 181 (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2); | 185 (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2); |
| 182 } | 186 } |
| 183 | 187 |
| 184 gpu_info->finalized = true; | 188 gpu_info->finalized = true; |
| 185 bool rt = CollectGraphicsInfoGL(gpu_info); | 189 bool rt = CollectGraphicsInfoGL(gpu_info); |
| 186 | 190 |
| 187 return rt; | 191 return rt; |
| 188 } | 192 } |
| 189 | 193 |
| 190 bool CollectPreliminaryGraphicsInfo(content::GPUInfo* gpu_info) { | 194 bool CollectPreliminaryGraphicsInfo(content::GPUInfo* gpu_info) { |
| 191 DCHECK(gpu_info); | 195 DCHECK(gpu_info); |
| 192 | 196 |
| 193 bool rt = CollectVideoCardInfo(gpu_info); | 197 bool rt = CollectVideoCardInfo(gpu_info); |
| 194 | 198 |
| 195 if (gpu_info->vendor_id == 0x1002) { // ATI | 199 if (gpu_info->gpu.vendor_id == kVendorIDAMD) { |
| 196 std::string ati_driver_version = CollectDriverVersionATI(); | 200 std::string ati_driver_version = CollectDriverVersionATI(); |
| 197 if (!ati_driver_version.empty()) { | 201 if (!ati_driver_version.empty()) { |
| 198 gpu_info->driver_vendor = "ATI / AMD"; | 202 gpu_info->driver_vendor = "ATI / AMD"; |
| 199 gpu_info->driver_version = ati_driver_version; | 203 gpu_info->driver_version = ati_driver_version; |
| 200 } | 204 } |
| 201 } | 205 } |
| 202 | 206 |
| 207 // Disable all GPU features for Optimus on Linux. |
| 208 if (gpu_info->optimus) { |
| 209 gpu_info->gpu_accessible = false; |
| 210 gpu_info->finalized = true; |
| 211 } |
| 212 |
| 203 return rt; | 213 return rt; |
| 204 } | 214 } |
| 205 | 215 |
| 206 bool CollectVideoCardInfo(content::GPUInfo* gpu_info) { | 216 bool CollectVideoCardInfo(content::GPUInfo* gpu_info) { |
| 207 DCHECK(gpu_info); | 217 DCHECK(gpu_info); |
| 208 | 218 |
| 209 if (IsPciSupported() == false) { | 219 if (IsPciSupported() == false) { |
| 210 VLOG(1) << "PCI bus scanning is not supported"; | 220 VLOG(1) << "PCI bus scanning is not supported"; |
| 211 return false; | 221 return false; |
| 212 } | 222 } |
| 213 | 223 |
| 214 // TODO(zmo): be more flexible about library name. | 224 // TODO(zmo): be more flexible about library name. |
| 215 PciInterface* interface = InitializeLibPci("libpci.so.3"); | 225 PciInterface* interface = InitializeLibPci("libpci.so.3"); |
| 216 if (interface == NULL) | 226 if (interface == NULL) |
| 217 interface = InitializeLibPci("libpci.so"); | 227 interface = InitializeLibPci("libpci.so"); |
| 218 if (interface == NULL) { | 228 if (interface == NULL) { |
| 219 VLOG(1) << "Failed to locate libpci"; | 229 VLOG(1) << "Failed to locate libpci"; |
| 220 return false; | 230 return false; |
| 221 } | 231 } |
| 222 | 232 |
| 223 PciAccess* access = (interface->pci_alloc)(); | 233 PciAccess* access = (interface->pci_alloc)(); |
| 224 DCHECK(access != NULL); | 234 DCHECK(access != NULL); |
| 225 (interface->pci_init)(access); | 235 (interface->pci_init)(access); |
| 226 (interface->pci_scan_bus)(access); | 236 (interface->pci_scan_bus)(access); |
| 227 std::vector<PciDevice*> gpu_list; | 237 bool primary_gpu_identified = false; |
| 228 PciDevice* gpu_active = NULL; | |
| 229 for (PciDevice* device = access->device_list; | 238 for (PciDevice* device = access->device_list; |
| 230 device != NULL; device = device->next) { | 239 device != NULL; device = device->next) { |
| 231 (interface->pci_fill_info)(device, 33); // Fill the IDs and class fields. | 240 (interface->pci_fill_info)(device, 33); // Fill the IDs and class fields. |
| 232 // TODO(zmo): there might be other classes that qualify as display devices. | 241 // TODO(zmo): there might be other classes that qualify as display devices. |
| 233 if (device->device_class == 0x0300) { // Device class is DISPLAY_VGA. | 242 if (device->device_class != 0x0300) // Device class is DISPLAY_VGA. |
| 234 if (gpu_info->vendor_id == 0 || gpu_info->vendor_id == device->vendor_id) | 243 continue; |
| 235 gpu_list.push_back(device); | 244 |
| 236 } | 245 content::GPUInfo::GPUDevice gpu; |
| 237 } | 246 gpu.vendor_id = device->vendor_id; |
| 238 if (gpu_list.size() == 1) { | 247 gpu.device_id = device->device_id; |
| 239 gpu_active = gpu_list[0]; | 248 |
| 240 } else { | |
| 241 // If more than one graphics card are identified, find the one that matches | |
| 242 // gl VENDOR and RENDERER info. | |
| 243 std::string gl_vendor_string = gpu_info->gl_vendor; | |
| 244 std::string gl_renderer_string = gpu_info->gl_renderer; | |
| 245 const int buffer_size = 255; | 249 const int buffer_size = 255; |
| 246 scoped_array<char> buffer(new char[buffer_size]); | 250 scoped_array<char> buffer(new char[buffer_size]); |
| 247 std::vector<PciDevice*> candidates; | 251 // The current implementation of pci_lookup_name returns the same pointer |
| 248 for (size_t i = 0; i < gpu_list.size(); ++i) { | 252 // as the passed in upon success, and a different one (NULL or a pointer |
| 249 PciDevice* gpu = gpu_list[i]; | 253 // to an error message) upon failure. |
| 250 // The current implementation of pci_lookup_name returns the same pointer | 254 if ((interface->pci_lookup_name)(access, |
| 251 // as the passed in upon success, and a different one (NULL or a pointer | 255 buffer.get(), |
| 252 // to an error message) upon failure. | 256 buffer_size, |
| 253 if ((interface->pci_lookup_name)(access, | 257 1, |
| 254 buffer.get(), | 258 device->vendor_id) == buffer.get()) { |
| 255 buffer_size, | 259 gpu.vendor_string = buffer.get(); |
| 256 1, | 260 } |
| 257 gpu->vendor_id) != buffer.get()) | 261 if ((interface->pci_lookup_name)(access, |
| 258 continue; | 262 buffer.get(), |
| 259 std::string vendor_string = buffer.get(); | 263 buffer_size, |
| 260 const bool kCaseSensitive = false; | 264 2, |
| 261 if (!StartsWithASCII(gl_vendor_string, vendor_string, kCaseSensitive)) | 265 device->vendor_id, |
| 262 continue; | 266 device->device_id) == buffer.get()) { |
| 263 if ((interface->pci_lookup_name)(access, | |
| 264 buffer.get(), | |
| 265 buffer_size, | |
| 266 2, | |
| 267 gpu->vendor_id, | |
| 268 gpu->device_id) != buffer.get()) | |
| 269 continue; | |
| 270 std::string device_string = buffer.get(); | 267 std::string device_string = buffer.get(); |
| 271 size_t begin = device_string.find_first_of('['); | 268 size_t begin = device_string.find_first_of('['); |
| 272 size_t end = device_string.find_last_of(']'); | 269 size_t end = device_string.find_last_of(']'); |
| 273 if (begin != std::string::npos && end != std::string::npos && | 270 if (begin != std::string::npos && end != std::string::npos && |
| 274 begin < end) { | 271 begin < end) { |
| 275 device_string = device_string.substr(begin + 1, end - begin - 1); | 272 device_string = device_string.substr(begin + 1, end - begin - 1); |
| 276 } | 273 } |
| 277 if (StartsWithASCII(gl_renderer_string, device_string, kCaseSensitive)) { | 274 gpu.device_string = device_string; |
| 278 gpu_active = gpu; | 275 } |
| 279 break; | 276 |
| 277 if (!primary_gpu_identified) { |
| 278 primary_gpu_identified = true; |
| 279 gpu_info->gpu = gpu; |
| 280 } else { |
| 281 // TODO(zmo): if there are multiple GPUs, we assume the non Intel |
| 282 // one is primary. Revisit this logic because we actually don't know |
| 283 // which GPU we are using at this point. |
| 284 if (gpu_info->gpu.vendor_id == kVendorIDIntel && |
| 285 gpu.vendor_id != kVendorIDIntel) { |
| 286 gpu_info->secondary_gpus.push_back(gpu_info->gpu); |
| 287 gpu_info->gpu = gpu; |
| 288 } else { |
| 289 gpu_info->secondary_gpus.push_back(gpu); |
| 280 } | 290 } |
| 281 // If a device's vendor matches gl VENDOR string, we want to consider the | |
| 282 // possibility that libpci may not return the exact same name as gl | |
| 283 // RENDERER string. | |
| 284 candidates.push_back(gpu); | |
| 285 } | 291 } |
| 286 if (gpu_active == NULL && candidates.size() == 1) | |
| 287 gpu_active = candidates[0]; | |
| 288 } | 292 } |
| 289 if (gpu_active != NULL) { | 293 |
| 290 gpu_info->vendor_id = gpu_active->vendor_id; | 294 // Detect Optimus or AMD Switchable GPU. |
| 291 gpu_info->device_id = gpu_active->device_id; | 295 if (gpu_info->secondary_gpus.size() == 1 && |
| 296 gpu_info->secondary_gpus[0].vendor_id == kVendorIDIntel) { |
| 297 if (gpu_info->gpu.vendor_id == kVendorIDNVidia) |
| 298 gpu_info->optimus = true; |
| 299 if (gpu_info->gpu.vendor_id == kVendorIDAMD) |
| 300 gpu_info->amd_switchable = true; |
| 292 } | 301 } |
| 302 |
| 293 (interface->pci_cleanup)(access); | 303 (interface->pci_cleanup)(access); |
| 294 FinalizeLibPci(&interface); | 304 FinalizeLibPci(&interface); |
| 295 return (gpu_active != NULL); | 305 return (primary_gpu_identified); |
| 296 } | 306 } |
| 297 | 307 |
| 298 bool CollectDriverInfoGL(content::GPUInfo* gpu_info) { | 308 bool CollectDriverInfoGL(content::GPUInfo* gpu_info) { |
| 299 DCHECK(gpu_info); | 309 DCHECK(gpu_info); |
| 300 | 310 |
| 301 std::string gl_version_string = gpu_info->gl_version_string; | 311 std::string gl_version_string = gpu_info->gl_version_string; |
| 302 if (StartsWithASCII(gl_version_string, "OpenGL ES", true)) | 312 if (StartsWithASCII(gl_version_string, "OpenGL ES", true)) |
| 303 gl_version_string = gl_version_string.substr(10); | 313 gl_version_string = gl_version_string.substr(10); |
| 304 std::vector<std::string> pieces; | 314 std::vector<std::string> pieces; |
| 305 base::SplitStringAlongWhitespace(gl_version_string, &pieces); | 315 base::SplitStringAlongWhitespace(gl_version_string, &pieces); |
| 306 // In linux, the gl version string might be in the format of | 316 // In linux, the gl version string might be in the format of |
| 307 // GLVersion DriverVendor DriverVersion | 317 // GLVersion DriverVendor DriverVersion |
| 308 if (pieces.size() < 3) | 318 if (pieces.size() < 3) |
| 309 return false; | 319 return false; |
| 310 | 320 |
| 311 std::string driver_version = pieces[2]; | 321 std::string driver_version = pieces[2]; |
| 312 size_t pos = driver_version.find_first_not_of("0123456789."); | 322 size_t pos = driver_version.find_first_not_of("0123456789."); |
| 313 if (pos == 0) | 323 if (pos == 0) |
| 314 return false; | 324 return false; |
| 315 if (pos != std::string::npos) | 325 if (pos != std::string::npos) |
| 316 driver_version = driver_version.substr(0, pos); | 326 driver_version = driver_version.substr(0, pos); |
| 317 | 327 |
| 318 gpu_info->driver_vendor = pieces[1]; | 328 gpu_info->driver_vendor = pieces[1]; |
| 319 gpu_info->driver_version = driver_version; | 329 gpu_info->driver_version = driver_version; |
| 320 return true; | 330 return true; |
| 321 } | 331 } |
| 322 | 332 |
| 323 } // namespace gpu_info_collector | 333 } // namespace gpu_info_collector |
| OLD | NEW |