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 3 // found in the LICENSE file. 4 5 #include "gpu/config/gpu_info_collector.h" 6 7 // This has to be included before windows.h. 8 #include "third_party/re2/re2/re2.h" 9 10 #include <windows.h> 11 #include <d3d9.h> 12 #include <d3d11.h> 13 #include <dxgi.h> 14 #include <setupapi.h> 15 16 #include "base/command_line.h" 17 #include "base/debug/trace_event.h" 18 #include "base/file_util.h" 19 #include "base/files/file_enumerator.h" 20 #include "base/files/file_path.h" 21 #include "base/logging.h" 22 #include "base/message_loop/message_loop.h" 23 #include "base/metrics/field_trial.h" 24 #include "base/metrics/histogram.h" 25 #include "base/scoped_native_library.h" 26 #include "base/strings/string16.h" 27 #include "base/strings/string_number_conversions.h" 28 #include "base/strings/string_util.h" 29 #include "base/strings/stringprintf.h" 30 #include "base/threading/thread.h" 31 #include "base/threading/worker_pool.h" 32 #include "base/win/registry.h" 33 #include "base/win/scoped_com_initializer.h" 34 #include "base/win/scoped_comptr.h" 35 #include "base/win/windows_version.h" 36 #include "third_party/libxml/chromium/libxml_utils.h" 37 #include "ui/gl/gl_implementation.h" 38 #include "ui/gl/gl_surface_egl.h" 39 40 namespace gpu { 41 42 namespace { 43 44 // This must be kept in sync with histograms.xml. 45 enum DisplayLinkInstallationStatus { 46 DISPLAY_LINK_NOT_INSTALLED, 47 DISPLAY_LINK_7_1_OR_EARLIER, 48 DISPLAY_LINK_7_2_OR_LATER, 49 DISPLAY_LINK_INSTALLATION_STATUS_MAX 50 }; 51 52 float ReadXMLFloatValue(XmlReader* reader) { 53 std::string score_string; 54 if (!reader->ReadElementContent(&score_string)) 55 return 0.0; 56 57 double score; 58 if (!base::StringToDouble(score_string, &score)) 59 return 0.0; 60 61 return static_cast<float>(score); 62 } 63 64 GpuPerformanceStats RetrieveGpuPerformanceStats() { 65 TRACE_EVENT0("gpu", "RetrieveGpuPerformanceStats"); 66 67 // If the user re-runs the assessment without restarting, the COM API 68 // returns WINSAT_ASSESSMENT_STATE_NOT_AVAILABLE. Because of that and 69 // http://crbug.com/124325, read the assessment result files directly. 70 GpuPerformanceStats stats; 71 72 // Get path to WinSAT results files. 73 wchar_t winsat_results_path[MAX_PATH]; 74 DWORD size = ExpandEnvironmentStrings( 75 L"%WinDir%\\Performance\\WinSAT\\DataStore\\", 76 winsat_results_path, MAX_PATH); 77 if (size == 0 || size > MAX_PATH) { 78 LOG(ERROR) << "The path to the WinSAT results is too long: " 79 << size << " chars."; 80 return stats; 81 } 82 83 // Find most recent formal assessment results. 84 base::FileEnumerator file_enumerator( 85 base::FilePath(winsat_results_path), 86 false, // not recursive 87 base::FileEnumerator::FILES, 88 FILE_PATH_LITERAL("* * Formal.Assessment (*).WinSAT.xml")); 89 90 base::FilePath current_results; 91 for (base::FilePath results = file_enumerator.Next(); !results.empty(); 92 results = file_enumerator.Next()) { 93 // The filenames start with the date and time as yyyy-mm-dd hh.mm.ss.xxx, 94 // so the greatest file lexicographically is also the most recent file. 95 if (base::FilePath::CompareLessIgnoreCase(current_results.value(), 96 results.value())) 97 current_results = results; 98 } 99 100 std::string current_results_string = current_results.MaybeAsASCII(); 101 if (current_results_string.empty()) { 102 LOG(ERROR) << "Can't retrieve a valid WinSAT assessment."; 103 return stats; 104 } 105 106 // Get relevant scores from results file. XML schema at: 107 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa969210.aspx 108 XmlReader reader; 109 if (!reader.LoadFile(current_results_string)) { 110 LOG(ERROR) << "Could not open WinSAT results file."; 111 return stats; 112 } 113 // Descend into <WinSAT> root element. 114 if (!reader.SkipToElement() || !reader.Read()) { 115 LOG(ERROR) << "Could not read WinSAT results file."; 116 return stats; 117 } 118 119 // Search for <WinSPR> element containing the results. 120 do { 121 if (reader.NodeName() == "WinSPR") 122 break; 123 } while (reader.Next()); 124 // Descend into <WinSPR> element. 125 if (!reader.Read()) { 126 LOG(ERROR) << "Could not find WinSPR element in results file."; 127 return stats; 128 } 129 130 // Read scores. 131 for (int depth = reader.Depth(); reader.Depth() == depth; reader.Next()) { 132 std::string node_name = reader.NodeName(); 133 if (node_name == "SystemScore") 134 stats.overall = ReadXMLFloatValue(&reader); 135 else if (node_name == "GraphicsScore") 136 stats.graphics = ReadXMLFloatValue(&reader); 137 else if (node_name == "GamingScore") 138 stats.gaming = ReadXMLFloatValue(&reader); 139 } 140 141 if (stats.overall == 0.0) 142 LOG(ERROR) << "Could not read overall score from assessment results."; 143 if (stats.graphics == 0.0) 144 LOG(ERROR) << "Could not read graphics score from assessment results."; 145 if (stats.gaming == 0.0) 146 LOG(ERROR) << "Could not read gaming score from assessment results."; 147 148 return stats; 149 } 150 151 GpuPerformanceStats RetrieveGpuPerformanceStatsWithHistograms() { 152 base::TimeTicks start_time = base::TimeTicks::Now(); 153 154 GpuPerformanceStats stats = RetrieveGpuPerformanceStats(); 155 156 UMA_HISTOGRAM_TIMES("GPU.WinSAT.ReadResultsFileTime", 157 base::TimeTicks::Now() - start_time); 158 UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.WinSAT.OverallScore2", 159 stats.overall * 10, 10, 200, 50); 160 UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.WinSAT.GraphicsScore2", 161 stats.graphics * 10, 10, 200, 50); 162 UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.WinSAT.GamingScore2", 163 stats.gaming * 10, 10, 200, 50); 164 UMA_HISTOGRAM_BOOLEAN( 165 "GPU.WinSAT.HasResults", 166 stats.overall != 0.0 && stats.graphics != 0.0 && stats.gaming != 0.0); 167 168 return stats; 169 } 170 171 // Returns the display link driver version or an invalid version if it is 172 // not installed. 173 Version DisplayLinkVersion() { 174 base::win::RegKey key; 175 176 if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE", KEY_READ | KEY_WOW64_64KEY)) 177 return Version(); 178 179 if (key.OpenKey(L"DisplayLink", KEY_READ | KEY_WOW64_64KEY)) 180 return Version(); 181 182 if (key.OpenKey(L"Core", KEY_READ | KEY_WOW64_64KEY)) 183 return Version(); 184 185 base::string16 version; 186 if (key.ReadValue(L"Version", &version)) 187 return Version(); 188 189 return Version(WideToASCII(version)); 190 } 191 192 // Returns whether Lenovo dCute is installed. 193 bool IsLenovoDCuteInstalled() { 194 base::win::RegKey key; 195 196 if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE", KEY_READ | KEY_WOW64_64KEY)) 197 return false; 198 199 if (key.OpenKey(L"Lenovo", KEY_READ | KEY_WOW64_64KEY)) 200 return false; 201 202 if (key.OpenKey(L"Lenovo dCute", KEY_READ | KEY_WOW64_64KEY)) 203 return false; 204 205 return true; 206 } 207 208 // Determines whether D3D11 won't work, either because it is not supported on 209 // the machine or because it is known it is likely to crash. 210 bool D3D11ShouldWork(const GPUInfo& gpu_info) { 211 // TODO(apatrick): This is a temporary change to see what impact disabling 212 // D3D11 stats collection has on Canary. 213 return false; 214 215 // Windows XP never supports D3D11. It seems to be less stable that D3D9 on 216 // Vista. 217 if (base::win::GetVersion() <= base::win::VERSION_VISTA) 218 return false; 219 220 // http://crbug.com/175525. 221 if (gpu_info.display_link_version.IsValid()) 222 return false; 223 224 return true; 225 } 226 227 // Collects information about the level of D3D11 support and records it in 228 // the UMA stats. Records no stats when D3D11 in not supported at all. 229 void CollectD3D11SupportOnWorkerThread() { 230 TRACE_EVENT0("gpu", "CollectD3D11Support"); 231 232 typedef HRESULT (WINAPI *D3D11CreateDeviceFunc)( 233 IDXGIAdapter* adapter, 234 D3D_DRIVER_TYPE driver_type, 235 HMODULE software, 236 UINT flags, 237 const D3D_FEATURE_LEVEL* feature_levels, 238 UINT num_feature_levels, 239 UINT sdk_version, 240 ID3D11Device** device, 241 D3D_FEATURE_LEVEL* feature_level, 242 ID3D11DeviceContext** immediate_context); 243 244 // This enumeration must be kept in sync with histograms.xml. Do not reorder 245 // the members; always add to the end. 246 enum FeatureLevel { 247 FEATURE_LEVEL_UNKNOWN, 248 FEATURE_LEVEL_NO_D3D11_DLL, 249 FEATURE_LEVEL_NO_CREATE_DEVICE_ENTRY_POINT, 250 FEATURE_LEVEL_DEVICE_CREATION_FAILED, 251 FEATURE_LEVEL_9_1, 252 FEATURE_LEVEL_9_2, 253 FEATURE_LEVEL_9_3, 254 FEATURE_LEVEL_10_0, 255 FEATURE_LEVEL_10_1, 256 FEATURE_LEVEL_11_0, 257 NUM_FEATURE_LEVELS 258 }; 259 260 FeatureLevel feature_level = FEATURE_LEVEL_UNKNOWN; 261 UINT bgra_support = 0; 262 263 // This module is leaked in case it is hooked by third party software. 264 base::NativeLibrary d3d11_module = base::LoadNativeLibrary( 265 base::FilePath(L"d3d11.dll"), 266 NULL); 267 268 if (!d3d11_module) { 269 feature_level = FEATURE_LEVEL_NO_D3D11_DLL; 270 } else { 271 D3D11CreateDeviceFunc create_func = 272 reinterpret_cast<D3D11CreateDeviceFunc>( 273 base::GetFunctionPointerFromNativeLibrary(d3d11_module, 274 "D3D11CreateDevice")); 275 if (!create_func) { 276 feature_level = FEATURE_LEVEL_NO_CREATE_DEVICE_ENTRY_POINT; 277 } else { 278 static const D3D_FEATURE_LEVEL d3d_feature_levels[] = { 279 D3D_FEATURE_LEVEL_11_0, 280 D3D_FEATURE_LEVEL_10_1, 281 D3D_FEATURE_LEVEL_10_0, 282 D3D_FEATURE_LEVEL_9_3, 283 D3D_FEATURE_LEVEL_9_2, 284 D3D_FEATURE_LEVEL_9_1 285 }; 286 287 base::win::ScopedComPtr<ID3D11Device> device; 288 D3D_FEATURE_LEVEL d3d_feature_level; 289 base::win::ScopedComPtr<ID3D11DeviceContext> device_context; 290 HRESULT hr = create_func(NULL, 291 D3D_DRIVER_TYPE_HARDWARE, 292 NULL, 293 0, 294 d3d_feature_levels, 295 arraysize(d3d_feature_levels), 296 D3D11_SDK_VERSION, 297 device.Receive(), 298 &d3d_feature_level, 299 device_context.Receive()); 300 if (FAILED(hr)) { 301 feature_level = FEATURE_LEVEL_DEVICE_CREATION_FAILED; 302 } else { 303 switch (d3d_feature_level) { 304 case D3D_FEATURE_LEVEL_11_0: 305 feature_level = FEATURE_LEVEL_11_0; 306 break; 307 case D3D_FEATURE_LEVEL_10_1: 308 feature_level = FEATURE_LEVEL_10_1; 309 break; 310 case D3D_FEATURE_LEVEL_10_0: 311 feature_level = FEATURE_LEVEL_10_0; 312 break; 313 case D3D_FEATURE_LEVEL_9_3: 314 feature_level = FEATURE_LEVEL_9_3; 315 break; 316 case D3D_FEATURE_LEVEL_9_2: 317 feature_level = FEATURE_LEVEL_9_2; 318 break; 319 case D3D_FEATURE_LEVEL_9_1: 320 feature_level = FEATURE_LEVEL_9_1; 321 break; 322 default: 323 NOTREACHED(); 324 break; 325 } 326 327 hr = device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, 328 &bgra_support); 329 DCHECK(SUCCEEDED(hr)); 330 } 331 } 332 } 333 334 UMA_HISTOGRAM_ENUMERATION("GPU.D3D11_FeatureLevel", 335 feature_level, 336 NUM_FEATURE_LEVELS); 337 338 // ANGLE requires at least feature level 10.0. Do not record any further 339 // stats if ANGLE would not work anyway. 340 if (feature_level < FEATURE_LEVEL_10_0) 341 return; 342 343 UMA_HISTOGRAM_BOOLEAN( 344 "GPU.D3D11_B8G8R8A8_Texture2DSupport", 345 (bgra_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0); 346 UMA_HISTOGRAM_BOOLEAN( 347 "GPU.D3D11_B8G8R8A8_RenderTargetSupport", 348 (bgra_support & D3D11_FORMAT_SUPPORT_RENDER_TARGET) != 0); 349 } 350 351 // Collects information about the level of D3D11 support and records it in 352 // the UMA stats. Records no stats when D3D11 in not supported at all. 353 void CollectD3D11Support() { 354 // D3D11 takes about 50ms to initialize so do this on a worker thread. 355 base::WorkerPool::PostTask( 356 FROM_HERE, 357 base::Bind(CollectD3D11SupportOnWorkerThread), 358 false); 359 } 360 } // namespace anonymous 361 362 #if !defined(GOOGLE_CHROME_BUILD) 363 AMDVideoCardType GetAMDVideocardType() { 364 return STANDALONE; 365 } 366 #else 367 // This function has a real implementation for official builds that can 368 // be found in src/third_party/amd. 369 AMDVideoCardType GetAMDVideocardType(); 370 #endif 371 372 bool CollectDriverInfoD3D(const std::wstring& device_id, 373 GPUInfo* gpu_info) { 374 TRACE_EVENT0("gpu", "CollectDriverInfoD3D"); 375 376 // create device info for the display device 377 HDEVINFO device_info = SetupDiGetClassDevsW( 378 NULL, device_id.c_str(), NULL, 379 DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES); 380 if (device_info == INVALID_HANDLE_VALUE) { 381 LOG(ERROR) << "Creating device info failed"; 382 return false; 383 } 384 385 DWORD index = 0; 386 bool found = false; 387 SP_DEVINFO_DATA device_info_data; 388 device_info_data.cbSize = sizeof(device_info_data); 389 while (SetupDiEnumDeviceInfo(device_info, index++, &device_info_data)) { 390 WCHAR value[255]; 391 if (SetupDiGetDeviceRegistryPropertyW(device_info, 392 &device_info_data, 393 SPDRP_DRIVER, 394 NULL, 395 reinterpret_cast<PBYTE>(value), 396 sizeof(value), 397 NULL)) { 398 HKEY key; 399 std::wstring driver_key = L"System\\CurrentControlSet\\Control\\Class\\"; 400 driver_key += value; 401 LONG result = RegOpenKeyExW( 402 HKEY_LOCAL_MACHINE, driver_key.c_str(), 0, KEY_QUERY_VALUE, &key); 403 if (result == ERROR_SUCCESS) { 404 DWORD dwcb_data = sizeof(value); 405 std::string driver_version; 406 result = RegQueryValueExW( 407 key, L"DriverVersion", NULL, NULL, 408 reinterpret_cast<LPBYTE>(value), &dwcb_data); 409 if (result == ERROR_SUCCESS) 410 driver_version = WideToASCII(std::wstring(value)); 411 412 std::string driver_date; 413 dwcb_data = sizeof(value); 414 result = RegQueryValueExW( 415 key, L"DriverDate", NULL, NULL, 416 reinterpret_cast<LPBYTE>(value), &dwcb_data); 417 if (result == ERROR_SUCCESS) 418 driver_date = WideToASCII(std::wstring(value)); 419 420 std::string driver_vendor; 421 dwcb_data = sizeof(value); 422 result = RegQueryValueExW( 423 key, L"ProviderName", NULL, NULL, 424 reinterpret_cast<LPBYTE>(value), &dwcb_data); 425 if (result == ERROR_SUCCESS) { 426 driver_vendor = WideToASCII(std::wstring(value)); 427 if (driver_vendor == "Advanced Micro Devices, Inc." || 428 driver_vendor == "ATI Technologies Inc.") { 429 // We are conservative and assume that in the absence of a clear 430 // signal the videocard is assumed to be switchable. Additionally, 431 // some switchable systems with Intel GPUs aren't correctly 432 // detected, so always count them. 433 AMDVideoCardType amd_card_type = GetAMDVideocardType(); 434 gpu_info->amd_switchable = (gpu_info->gpu.vendor_id == 0x8086) || 435 (amd_card_type != STANDALONE); 436 } 437 } 438 439 gpu_info->driver_vendor = driver_vendor; 440 gpu_info->driver_version = driver_version; 441 gpu_info->driver_date = driver_date; 442 found = true; 443 RegCloseKey(key); 444 break; 445 } 446 } 447 } 448 SetupDiDestroyDeviceInfoList(device_info); 449 return found; 450 } 451 452 bool CollectContextGraphicsInfo(GPUInfo* gpu_info) { 453 TRACE_EVENT0("gpu", "CollectGraphicsInfo"); 454 455 DCHECK(gpu_info); 456 457 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) { 458 std::string requested_implementation_name = 459 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL); 460 if (requested_implementation_name == "swiftshader") { 461 gpu_info->software_rendering = true; 462 return false; 463 } 464 } 465 466 if (!CollectGraphicsInfoGL(gpu_info)) 467 return false; 468 469 // ANGLE's renderer strings are of the form: 470 // ANGLE (<adapter_identifier> Direct3D<version> vs_x_x ps_x_x) 471 std::string direct3d_version; 472 int vertex_shader_major_version = 0; 473 int vertex_shader_minor_version = 0; 474 int pixel_shader_major_version = 0; 475 int pixel_shader_minor_version = 0; 476 gpu_info->adapter_luid = 0; 477 if (RE2::FullMatch(gpu_info->gl_renderer, 478 "ANGLE \\(.*\\)") && 479 RE2::PartialMatch(gpu_info->gl_renderer, 480 " Direct3D(\\w+)", 481 &direct3d_version) && 482 RE2::PartialMatch(gpu_info->gl_renderer, 483 " vs_(\\d+)_(\\d+)", 484 &vertex_shader_major_version, 485 &vertex_shader_minor_version) && 486 RE2::PartialMatch(gpu_info->gl_renderer, 487 " ps_(\\d+)_(\\d+)", 488 &pixel_shader_major_version, 489 &pixel_shader_minor_version)) { 490 gpu_info->can_lose_context = direct3d_version == "9"; 491 gpu_info->vertex_shader_version = 492 base::StringPrintf("%d.%d", 493 vertex_shader_major_version, 494 vertex_shader_minor_version); 495 gpu_info->pixel_shader_version = 496 base::StringPrintf("%d.%d", 497 pixel_shader_major_version, 498 pixel_shader_minor_version); 499 500 // ANGLE's EGL vendor strings are of the form: 501 // Google, Inc. (adapter LUID: 0123456789ABCDEF) 502 // The LUID is optional and identifies the GPU adapter ANGLE is using. 503 const char* egl_vendor = eglQueryString( 504 gfx::GLSurfaceEGL::GetHardwareDisplay(), 505 EGL_VENDOR); 506 RE2::PartialMatch(egl_vendor, 507 " \\(adapter LUID: ([0-9A-Fa-f]{16})\\)", 508 RE2::Hex(&gpu_info->adapter_luid)); 509 510 // DirectX diagnostics are collected asynchronously because it takes a 511 // couple of seconds. Do not mark gpu_info as complete until that is done. 512 gpu_info->finalized = false; 513 } else { 514 gpu_info->finalized = true; 515 } 516 517 return true; 518 } 519 520 GpuIDResult CollectGpuID(uint32* vendor_id, uint32* device_id) { 521 DCHECK(vendor_id && device_id); 522 *vendor_id = 0; 523 *device_id = 0; 524 525 // Taken from http://developer.nvidia.com/object/device_ids.html 526 DISPLAY_DEVICE dd; 527 dd.cb = sizeof(DISPLAY_DEVICE); 528 std::wstring id; 529 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) { 530 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { 531 id = dd.DeviceID; 532 break; 533 } 534 } 535 536 if (id.length() > 20) { 537 int vendor = 0, device = 0; 538 std::wstring vendor_string = id.substr(8, 4); 539 std::wstring device_string = id.substr(17, 4); 540 base::HexStringToInt(WideToASCII(vendor_string), &vendor); 541 base::HexStringToInt(WideToASCII(device_string), &device); 542 *vendor_id = vendor; 543 *device_id = device; 544 return kGpuIDSuccess; 545 } 546 return kGpuIDFailure; 547 } 548 549 bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) { 550 TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo"); 551 552 DCHECK(gpu_info); 553 554 gpu_info->performance_stats = RetrieveGpuPerformanceStatsWithHistograms(); 555 556 // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled. 557 HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll"); 558 gpu_info->optimus = nvd3d9wrap != NULL; 559 560 gpu_info->lenovo_dcute = IsLenovoDCuteInstalled(); 561 562 gpu_info->display_link_version = DisplayLinkVersion(); 563 564 if (!gpu_info->display_link_version .IsValid()) { 565 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus", 566 DISPLAY_LINK_NOT_INSTALLED, 567 DISPLAY_LINK_INSTALLATION_STATUS_MAX); 568 } else if (gpu_info->display_link_version.IsOlderThan("7.2")) { 569 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus", 570 DISPLAY_LINK_7_1_OR_EARLIER, 571 DISPLAY_LINK_INSTALLATION_STATUS_MAX); 572 } else { 573 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus", 574 DISPLAY_LINK_7_2_OR_LATER, 575 DISPLAY_LINK_INSTALLATION_STATUS_MAX); 576 } 577 578 // Taken from http://developer.nvidia.com/object/device_ids.html 579 DISPLAY_DEVICE dd; 580 dd.cb = sizeof(DISPLAY_DEVICE); 581 std::wstring id; 582 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) { 583 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { 584 id = dd.DeviceID; 585 break; 586 } 587 } 588 589 if (id.length() <= 20) 590 return false; 591 592 int vendor_id = 0, device_id = 0; 593 base::string16 vendor_id_string = id.substr(8, 4); 594 base::string16 device_id_string = id.substr(17, 4); 595 base::HexStringToInt(WideToASCII(vendor_id_string), &vendor_id); 596 base::HexStringToInt(WideToASCII(device_id_string), &device_id); 597 gpu_info->gpu.vendor_id = vendor_id; 598 gpu_info->gpu.device_id = device_id; 599 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE. 600 if (!CollectDriverInfoD3D(id, gpu_info)) 601 return false; 602 603 // Collect basic information about supported D3D11 features. Delay for 45 604 // seconds so as not to regress performance tests. 605 if (D3D11ShouldWork(*gpu_info)) { 606 // This is on a field trial so we can turn it off easily if it blows up 607 // again in stable channel. 608 scoped_refptr<base::FieldTrial> trial( 609 base::FieldTrialList::FactoryGetFieldTrial( 610 "D3D11Experiment", 100, "Disabled", 2015, 7, 8, 611 base::FieldTrial::SESSION_RANDOMIZED, NULL)); 612 const int enabled_group = 613 trial->AppendGroup("Enabled", 0); 614 615 if (trial->group() == enabled_group) { 616 base::MessageLoop::current()->PostDelayedTask( 617 FROM_HERE, 618 base::Bind(&CollectD3D11Support), 619 base::TimeDelta::FromSeconds(45)); 620 } 621 } 622 623 return true; 624 } 625 626 bool CollectDriverInfoGL(GPUInfo* gpu_info) { 627 TRACE_EVENT0("gpu", "CollectDriverInfoGL"); 628 629 if (!gpu_info->driver_version.empty()) 630 return true; 631 632 std::string gl_version_string = gpu_info->gl_version_string; 633 634 return RE2::PartialMatch(gl_version_string, 635 "([\\d\\.]+)$", 636 &gpu_info->driver_version); 637 } 638 639 void MergeGPUInfo(GPUInfo* basic_gpu_info, 640 const GPUInfo& context_gpu_info) { 641 DCHECK(basic_gpu_info); 642 643 if (context_gpu_info.software_rendering) { 644 basic_gpu_info->software_rendering = true; 645 return; 646 } 647 648 MergeGPUInfoGL(basic_gpu_info, context_gpu_info); 649 650 basic_gpu_info->dx_diagnostics = context_gpu_info.dx_diagnostics; 651 } 652 653 bool DetermineActiveGPU(GPUInfo* gpu_info) { 654 DCHECK(gpu_info); 655 if (gpu_info->secondary_gpus.size() == 0) 656 return true; 657 // TODO(zmo): implement this. 658 return false; 659 } 660 661 } // namespace gpu 662