Chromium Code Reviews| 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 "gpu/config/gpu_info_collector.h" | 5 #include "gpu/config/gpu_info_collector.h" |
| 6 | 6 |
| 7 // This has to be included before windows.h. | 7 // This has to be included before windows.h. |
| 8 #include "third_party/re2/re2/re2.h" | 8 #include "third_party/re2/re2/re2.h" |
| 9 | 9 |
| 10 #include <windows.h> | 10 #include <windows.h> |
| 11 #include <cfgmgr32.h> | |
| 11 #include <d3d9.h> | 12 #include <d3d9.h> |
| 12 #include <d3d11.h> | 13 #include <d3d11.h> |
| 13 #include <dxgi.h> | 14 #include <dxgi.h> |
| 14 #include <setupapi.h> | 15 #include <setupapi.h> |
| 15 | 16 |
| 16 #include "base/command_line.h" | 17 #include "base/command_line.h" |
| 17 #include "base/files/file_enumerator.h" | 18 #include "base/files/file_enumerator.h" |
| 18 #include "base/files/file_path.h" | 19 #include "base/files/file_path.h" |
| 19 #include "base/files/file_util.h" | 20 #include "base/files/file_util.h" |
| 20 #include "base/logging.h" | 21 #include "base/logging.h" |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 356 | 357 |
| 357 // Collects information about the level of D3D11 support and records it in | 358 // Collects information about the level of D3D11 support and records it in |
| 358 // the UMA stats. Records no stats when D3D11 in not supported at all. | 359 // the UMA stats. Records no stats when D3D11 in not supported at all. |
| 359 void CollectD3D11Support() { | 360 void CollectD3D11Support() { |
| 360 // D3D11 takes about 50ms to initialize so do this on a worker thread. | 361 // D3D11 takes about 50ms to initialize so do this on a worker thread. |
| 361 base::WorkerPool::PostTask( | 362 base::WorkerPool::PostTask( |
| 362 FROM_HERE, | 363 FROM_HERE, |
| 363 base::Bind(CollectD3D11SupportOnWorkerThread), | 364 base::Bind(CollectD3D11SupportOnWorkerThread), |
| 364 false); | 365 false); |
| 365 } | 366 } |
| 367 | |
| 368 void DeviceIDToVendorAndDevice(const std::wstring& id, | |
| 369 uint32* vendor_id, | |
| 370 uint32* device_id) { | |
| 371 *vendor_id = 0; | |
| 372 *device_id = 0; | |
| 373 if (id.length() < 21) | |
| 374 return; | |
| 375 base::string16 vendor_id_string = id.substr(8, 4); | |
| 376 base::string16 device_id_string = id.substr(17, 4); | |
| 377 int vendor = 0; | |
| 378 int device = 0; | |
| 379 base::HexStringToInt(base::UTF16ToASCII(vendor_id_string), &vendor); | |
| 380 base::HexStringToInt(base::UTF16ToASCII(device_id_string), &device); | |
| 381 *vendor_id = vendor; | |
| 382 *device_id = device; | |
| 383 } | |
| 384 | |
| 366 } // namespace anonymous | 385 } // namespace anonymous |
| 367 | 386 |
| 368 #if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD) | 387 #if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD) |
| 369 // This function has a real implementation for official builds that can | 388 // This function has a real implementation for official builds that can |
| 370 // be found in src/third_party/amd. | 389 // be found in src/third_party/amd. |
| 371 void GetAMDVideocardInfo(GPUInfo* gpu_info); | 390 void GetAMDVideocardInfo(GPUInfo* gpu_info); |
| 372 #else | 391 #else |
| 373 void GetAMDVideocardInfo(GPUInfo* gpu_info) { | 392 void GetAMDVideocardInfo(GPUInfo* gpu_info) { |
| 374 DCHECK(gpu_info); | 393 DCHECK(gpu_info); |
| 375 return; | 394 return; |
| 376 } | 395 } |
| 377 #endif | 396 #endif |
| 378 | 397 |
| 379 CollectInfoResult CollectDriverInfoD3D(const std::wstring& device_id, | 398 CollectInfoResult CollectDriverInfoD3D(const std::wstring& device_id, |
| 380 GPUInfo* gpu_info) { | 399 GPUInfo* gpu_info) { |
| 381 TRACE_EVENT0("gpu", "CollectDriverInfoD3D"); | 400 TRACE_EVENT0("gpu", "CollectDriverInfoD3D"); |
| 382 | 401 |
| 402 GUID display_class = {0x4d36e968, | |
| 403 0xe325, | |
| 404 0x11ce, | |
| 405 {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}; | |
|
Zhenyao Mo
2015/02/05 23:04:28
nit: can you add a comment where the above data co
| |
| 406 | |
| 383 // create device info for the display device | 407 // create device info for the display device |
| 384 HDEVINFO device_info = SetupDiGetClassDevsW( | 408 HDEVINFO device_info = |
| 385 NULL, device_id.c_str(), NULL, | 409 SetupDiGetClassDevsW(&display_class, NULL, NULL, DIGCF_PRESENT); |
| 386 DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES); | |
| 387 if (device_info == INVALID_HANDLE_VALUE) { | 410 if (device_info == INVALID_HANDLE_VALUE) { |
| 388 LOG(ERROR) << "Creating device info failed"; | 411 LOG(ERROR) << "Creating device info failed"; |
| 389 return kCollectInfoNonFatalFailure; | 412 return kCollectInfoNonFatalFailure; |
| 390 } | 413 } |
| 391 | 414 |
| 415 struct GPUDriver { | |
| 416 GPUInfo::GPUDevice device; | |
| 417 std::string driver_vendor; | |
| 418 std::string driver_version; | |
| 419 std::string driver_date; | |
| 420 }; | |
| 421 | |
| 422 std::vector<GPUDriver> drivers; | |
| 423 | |
| 424 int primary_device = -1; | |
| 425 bool found_amd = false; | |
| 426 bool found_intel = false; | |
| 427 | |
| 392 DWORD index = 0; | 428 DWORD index = 0; |
| 393 bool found = false; | |
| 394 SP_DEVINFO_DATA device_info_data; | 429 SP_DEVINFO_DATA device_info_data; |
| 395 device_info_data.cbSize = sizeof(device_info_data); | 430 device_info_data.cbSize = sizeof(device_info_data); |
| 396 while (SetupDiEnumDeviceInfo(device_info, index++, &device_info_data)) { | 431 while (SetupDiEnumDeviceInfo(device_info, index++, &device_info_data)) { |
| 397 WCHAR value[255]; | 432 WCHAR value[255]; |
| 398 if (SetupDiGetDeviceRegistryPropertyW(device_info, | 433 if (SetupDiGetDeviceRegistryPropertyW(device_info, |
| 399 &device_info_data, | 434 &device_info_data, |
| 400 SPDRP_DRIVER, | 435 SPDRP_DRIVER, |
| 401 NULL, | 436 NULL, |
| 402 reinterpret_cast<PBYTE>(value), | 437 reinterpret_cast<PBYTE>(value), |
| 403 sizeof(value), | 438 sizeof(value), |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 422 key, L"DriverDate", NULL, NULL, | 457 key, L"DriverDate", NULL, NULL, |
| 423 reinterpret_cast<LPBYTE>(value), &dwcb_data); | 458 reinterpret_cast<LPBYTE>(value), &dwcb_data); |
| 424 if (result == ERROR_SUCCESS) | 459 if (result == ERROR_SUCCESS) |
| 425 driver_date = base::UTF16ToASCII(std::wstring(value)); | 460 driver_date = base::UTF16ToASCII(std::wstring(value)); |
| 426 | 461 |
| 427 std::string driver_vendor; | 462 std::string driver_vendor; |
| 428 dwcb_data = sizeof(value); | 463 dwcb_data = sizeof(value); |
| 429 result = RegQueryValueExW( | 464 result = RegQueryValueExW( |
| 430 key, L"ProviderName", NULL, NULL, | 465 key, L"ProviderName", NULL, NULL, |
| 431 reinterpret_cast<LPBYTE>(value), &dwcb_data); | 466 reinterpret_cast<LPBYTE>(value), &dwcb_data); |
| 432 if (result == ERROR_SUCCESS) { | 467 if (result == ERROR_SUCCESS) |
| 433 driver_vendor = base::UTF16ToASCII(std::wstring(value)); | 468 driver_vendor = base::UTF16ToASCII(std::wstring(value)); |
| 434 if (driver_vendor == "Advanced Micro Devices, Inc." || | 469 |
| 435 driver_vendor == "ATI Technologies Inc.") { | 470 wchar_t new_device_id[MAX_DEVICE_ID_LEN]; |
| 436 // We are conservative and assume that in the absence of a clear | 471 CONFIGRET status = CM_Get_Device_ID( |
| 437 // signal the videocard is assumed to be switchable. Additionally, | 472 device_info_data.DevInst, new_device_id, MAX_DEVICE_ID_LEN, 0); |
| 438 // some switchable systems with Intel GPUs aren't correctly | 473 |
| 439 // detected, so always count them. | 474 if (status == CR_SUCCESS) { |
| 440 GetAMDVideocardInfo(gpu_info); | 475 GPUDriver driver; |
| 441 if (!gpu_info->amd_switchable && | 476 |
| 442 gpu_info->gpu.vendor_id == 0x8086) { | 477 driver.driver_vendor = driver_vendor; |
| 443 gpu_info->amd_switchable = true; | 478 driver.driver_version = driver_version; |
| 444 gpu_info->secondary_gpus.push_back(gpu_info->gpu); | 479 driver.driver_date = driver_date; |
| 445 gpu_info->gpu.vendor_id = 0x1002; | 480 std::wstring id = new_device_id; |
| 446 gpu_info->gpu.device_id = 0; // Unknown discrete AMD GPU. | 481 |
| 447 } | 482 if (id.compare(0, device_id.size(), device_id) == 0) |
| 448 } | 483 primary_device = drivers.size(); |
| 484 | |
| 485 uint32 vendor_id = 0, device_id = 0; | |
| 486 DeviceIDToVendorAndDevice(id, &vendor_id, &device_id); | |
| 487 driver.device.vendor_id = vendor_id; | |
| 488 driver.device.device_id = device_id; | |
| 489 drivers.push_back(driver); | |
| 490 | |
| 491 if (vendor_id == 0x8086) | |
| 492 found_intel = true; | |
| 493 if (vendor_id == 0x1002) | |
| 494 found_amd = true; | |
| 449 } | 495 } |
| 450 | 496 |
| 451 gpu_info->driver_vendor = driver_vendor; | |
| 452 gpu_info->driver_version = driver_version; | |
| 453 gpu_info->driver_date = driver_date; | |
| 454 found = true; | |
| 455 RegCloseKey(key); | 497 RegCloseKey(key); |
| 456 break; | |
| 457 } | 498 } |
| 458 } | 499 } |
| 459 } | 500 } |
| 460 SetupDiDestroyDeviceInfoList(device_info); | 501 SetupDiDestroyDeviceInfoList(device_info); |
| 502 bool found = false; | |
| 503 if (found_amd && found_intel) { | |
| 504 // AMD Switchable system found. | |
| 505 for (const auto& driver : drivers) { | |
| 506 if (driver.device.vendor_id == 0x8086) { | |
| 507 gpu_info->gpu = driver.device; | |
| 508 } | |
| 509 | |
| 510 if (driver.device.vendor_id == 0x1002) { | |
| 511 gpu_info->driver_vendor = driver.driver_vendor; | |
| 512 gpu_info->driver_version = driver.driver_version; | |
| 513 gpu_info->driver_date = driver.driver_date; | |
| 514 } | |
| 515 } | |
| 516 GetAMDVideocardInfo(gpu_info); | |
| 517 | |
| 518 if (!gpu_info->amd_switchable) { | |
| 519 // Some machines aren't properly detected as AMD switchable, but count | |
| 520 // them anyway. | |
| 521 gpu_info->amd_switchable = true; | |
| 522 for (const auto& driver : drivers) { | |
| 523 if (driver.device.vendor_id == 0x1002) { | |
| 524 gpu_info->gpu = driver.device; | |
| 525 } else { | |
| 526 gpu_info->secondary_gpus.push_back(driver.device); | |
| 527 } | |
| 528 } | |
| 529 } | |
| 530 found = true; | |
| 531 } else { | |
| 532 for (size_t i = 0; i < drivers.size(); ++i) { | |
| 533 const GPUDriver& driver = drivers[i]; | |
| 534 if (static_cast<int>(i) == primary_device) { | |
| 535 found = true; | |
| 536 gpu_info->gpu = driver.device; | |
| 537 gpu_info->driver_vendor = driver.driver_vendor; | |
| 538 gpu_info->driver_version = driver.driver_version; | |
| 539 gpu_info->driver_date = driver.driver_date; | |
| 540 } else { | |
| 541 gpu_info->secondary_gpus.push_back(driver.device); | |
| 542 } | |
| 543 } | |
| 544 } | |
| 545 | |
| 461 return found ? kCollectInfoSuccess : kCollectInfoNonFatalFailure; | 546 return found ? kCollectInfoSuccess : kCollectInfoNonFatalFailure; |
| 462 } | 547 } |
| 463 | 548 |
| 464 CollectInfoResult CollectContextGraphicsInfo(GPUInfo* gpu_info) { | 549 CollectInfoResult CollectContextGraphicsInfo(GPUInfo* gpu_info) { |
| 465 TRACE_EVENT0("gpu", "CollectGraphicsInfo"); | 550 TRACE_EVENT0("gpu", "CollectGraphicsInfo"); |
| 466 | 551 |
| 467 DCHECK(gpu_info); | 552 DCHECK(gpu_info); |
| 468 | 553 |
| 469 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) { | 554 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) { |
| 470 std::string requested_implementation_name = | 555 std::string requested_implementation_name = |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 544 dd.cb = sizeof(DISPLAY_DEVICE); | 629 dd.cb = sizeof(DISPLAY_DEVICE); |
| 545 std::wstring id; | 630 std::wstring id; |
| 546 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) { | 631 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) { |
| 547 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { | 632 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { |
| 548 id = dd.DeviceID; | 633 id = dd.DeviceID; |
| 549 break; | 634 break; |
| 550 } | 635 } |
| 551 } | 636 } |
| 552 | 637 |
| 553 if (id.length() > 20) { | 638 if (id.length() > 20) { |
| 554 int vendor = 0, device = 0; | 639 DeviceIDToVendorAndDevice(id, vendor_id, device_id); |
| 555 std::wstring vendor_string = id.substr(8, 4); | |
| 556 std::wstring device_string = id.substr(17, 4); | |
| 557 base::HexStringToInt(base::UTF16ToASCII(vendor_string), &vendor); | |
| 558 base::HexStringToInt(base::UTF16ToASCII(device_string), &device); | |
| 559 *vendor_id = vendor; | |
| 560 *device_id = device; | |
| 561 if (*vendor_id != 0 && *device_id != 0) | 640 if (*vendor_id != 0 && *device_id != 0) |
| 562 return kCollectInfoSuccess; | 641 return kCollectInfoSuccess; |
| 563 } | 642 } |
| 564 return kCollectInfoNonFatalFailure; | 643 return kCollectInfoNonFatalFailure; |
| 565 } | 644 } |
| 566 | 645 |
| 567 CollectInfoResult CollectBasicGraphicsInfo(GPUInfo* gpu_info) { | 646 CollectInfoResult CollectBasicGraphicsInfo(GPUInfo* gpu_info) { |
| 568 TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo"); | 647 TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo"); |
| 569 | 648 |
| 570 DCHECK(gpu_info); | 649 DCHECK(gpu_info); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 602 id = dd.DeviceID; | 681 id = dd.DeviceID; |
| 603 break; | 682 break; |
| 604 } | 683 } |
| 605 } | 684 } |
| 606 | 685 |
| 607 if (id.length() <= 20) { | 686 if (id.length() <= 20) { |
| 608 gpu_info->basic_info_state = kCollectInfoNonFatalFailure; | 687 gpu_info->basic_info_state = kCollectInfoNonFatalFailure; |
| 609 return kCollectInfoNonFatalFailure; | 688 return kCollectInfoNonFatalFailure; |
| 610 } | 689 } |
| 611 | 690 |
| 612 int vendor_id = 0, device_id = 0; | 691 DeviceIDToVendorAndDevice(id, &gpu_info->gpu.vendor_id, |
| 613 base::string16 vendor_id_string = id.substr(8, 4); | 692 &gpu_info->gpu.device_id); |
| 614 base::string16 device_id_string = id.substr(17, 4); | |
| 615 base::HexStringToInt(base::UTF16ToASCII(vendor_id_string), &vendor_id); | |
| 616 base::HexStringToInt(base::UTF16ToASCII(device_id_string), &device_id); | |
| 617 gpu_info->gpu.vendor_id = vendor_id; | |
| 618 gpu_info->gpu.device_id = device_id; | |
| 619 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE. | 693 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE. |
| 620 if (!CollectDriverInfoD3D(id, gpu_info)) { | 694 if (!CollectDriverInfoD3D(id, gpu_info)) { |
| 621 gpu_info->basic_info_state = kCollectInfoNonFatalFailure; | 695 gpu_info->basic_info_state = kCollectInfoNonFatalFailure; |
| 622 return kCollectInfoNonFatalFailure; | 696 return kCollectInfoNonFatalFailure; |
| 623 } | 697 } |
| 624 | 698 |
| 625 // Collect basic information about supported D3D11 features. Delay for 45 | 699 // Collect basic information about supported D3D11 features. Delay for 45 |
| 626 // seconds so as not to regress performance tests. | 700 // seconds so as not to regress performance tests. |
| 627 if (D3D11ShouldWork(*gpu_info)) { | 701 if (D3D11ShouldWork(*gpu_info)) { |
| 628 // This is on a field trial so we can turn it off easily if it blows up | 702 // This is on a field trial so we can turn it off easily if it blows up |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 704 shader_model, | 778 shader_model, |
| 705 NUM_SHADER_MODELS); | 779 NUM_SHADER_MODELS); |
| 706 } | 780 } |
| 707 | 781 |
| 708 MergeGPUInfoGL(basic_gpu_info, context_gpu_info); | 782 MergeGPUInfoGL(basic_gpu_info, context_gpu_info); |
| 709 | 783 |
| 710 basic_gpu_info->dx_diagnostics = context_gpu_info.dx_diagnostics; | 784 basic_gpu_info->dx_diagnostics = context_gpu_info.dx_diagnostics; |
| 711 } | 785 } |
| 712 | 786 |
| 713 } // namespace gpu | 787 } // namespace gpu |
| OLD | NEW |