Rewrite AndroidSyncSettings to be significantly simpler.
[chromium-blink-merge.git] / gpu / config / gpu_info_collector_win.cc
blob4deee7c497bcbb59c8882b31e9ea23ebd28c856b
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.
5 #include "gpu/config/gpu_info_collector.h"
7 // This has to be included before windows.h.
8 #include "third_party/re2/re2/re2.h"
10 #include <windows.h>
11 #include <cfgmgr32.h>
12 #include <d3d9.h>
13 #include <d3d11.h>
14 #include <dxgi.h>
15 #include <setupapi.h>
17 #include "base/command_line.h"
18 #include "base/files/file_enumerator.h"
19 #include "base/files/file_path.h"
20 #include "base/files/file_util.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/strings/utf_string_conversions.h"
31 #include "base/threading/thread.h"
32 #include "base/threading/worker_pool.h"
33 #include "base/trace_event/trace_event.h"
34 #include "base/win/registry.h"
35 #include "base/win/scoped_com_initializer.h"
36 #include "base/win/scoped_comptr.h"
37 #include "base/win/windows_version.h"
38 #include "third_party/libxml/chromium/libxml_utils.h"
39 #include "ui/gl/gl_implementation.h"
40 #include "ui/gl/gl_surface_egl.h"
42 namespace gpu {
44 namespace {
46 // This must be kept in sync with histograms.xml.
47 enum DisplayLinkInstallationStatus {
48 DISPLAY_LINK_NOT_INSTALLED,
49 DISPLAY_LINK_7_1_OR_EARLIER,
50 DISPLAY_LINK_7_2_OR_LATER,
51 DISPLAY_LINK_INSTALLATION_STATUS_MAX
54 float ReadXMLFloatValue(XmlReader* reader) {
55 std::string score_string;
56 if (!reader->ReadElementContent(&score_string))
57 return 0.0;
59 double score;
60 if (!base::StringToDouble(score_string, &score))
61 return 0.0;
63 return static_cast<float>(score);
66 GpuPerformanceStats RetrieveGpuPerformanceStats() {
67 TRACE_EVENT0("gpu", "RetrieveGpuPerformanceStats");
69 // If the user re-runs the assessment without restarting, the COM API
70 // returns WINSAT_ASSESSMENT_STATE_NOT_AVAILABLE. Because of that and
71 // http://crbug.com/124325, read the assessment result files directly.
72 GpuPerformanceStats stats;
74 // Get path to WinSAT results files.
75 wchar_t winsat_results_path[MAX_PATH];
76 DWORD size = ExpandEnvironmentStrings(
77 L"%WinDir%\\Performance\\WinSAT\\DataStore\\",
78 winsat_results_path, MAX_PATH);
79 if (size == 0 || size > MAX_PATH) {
80 LOG(ERROR) << "The path to the WinSAT results is too long: "
81 << size << " chars.";
82 return stats;
85 // Find most recent formal assessment results.
86 base::FileEnumerator file_enumerator(
87 base::FilePath(winsat_results_path),
88 false, // not recursive
89 base::FileEnumerator::FILES,
90 FILE_PATH_LITERAL("* * Formal.Assessment (*).WinSAT.xml"));
92 base::FilePath current_results;
93 for (base::FilePath results = file_enumerator.Next(); !results.empty();
94 results = file_enumerator.Next()) {
95 // The filenames start with the date and time as yyyy-mm-dd hh.mm.ss.xxx,
96 // so the greatest file lexicographically is also the most recent file.
97 if (base::FilePath::CompareLessIgnoreCase(current_results.value(),
98 results.value()))
99 current_results = results;
102 std::string current_results_string = current_results.MaybeAsASCII();
103 if (current_results_string.empty())
104 return stats;
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;
113 // Descend into <WinSAT> root element.
114 if (!reader.SkipToElement() || !reader.Read()) {
115 LOG(ERROR) << "Could not read WinSAT results file.";
116 return stats;
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;
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);
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.";
148 return stats;
151 GpuPerformanceStats RetrieveGpuPerformanceStatsWithHistograms() {
152 base::TimeTicks start_time = base::TimeTicks::Now();
154 GpuPerformanceStats stats = RetrieveGpuPerformanceStats();
156 UMA_HISTOGRAM_TIMES("GPU.WinSAT.ReadResultsFileTime",
157 base::TimeTicks::Now() - start_time);
158 UMA_HISTOGRAM_CUSTOM_COUNTS(
159 "GPU.WinSAT.OverallScore2",
160 static_cast<base::HistogramBase::Sample>(stats.overall * 10), 10, 200,
161 50);
162 UMA_HISTOGRAM_CUSTOM_COUNTS(
163 "GPU.WinSAT.GraphicsScore2",
164 static_cast<base::HistogramBase::Sample>(stats.graphics * 10), 10, 200,
165 50);
166 UMA_HISTOGRAM_CUSTOM_COUNTS(
167 "GPU.WinSAT.GamingScore2",
168 static_cast<base::HistogramBase::Sample>(stats.gaming * 10), 10, 200, 50);
169 UMA_HISTOGRAM_BOOLEAN(
170 "GPU.WinSAT.HasResults",
171 stats.overall != 0.0 && stats.graphics != 0.0 && stats.gaming != 0.0);
173 return stats;
176 // Returns the display link driver version or an invalid version if it is
177 // not installed.
178 Version DisplayLinkVersion() {
179 base::win::RegKey key;
181 if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE", KEY_READ | KEY_WOW64_64KEY))
182 return Version();
184 if (key.OpenKey(L"DisplayLink", KEY_READ | KEY_WOW64_64KEY))
185 return Version();
187 if (key.OpenKey(L"Core", KEY_READ | KEY_WOW64_64KEY))
188 return Version();
190 base::string16 version;
191 if (key.ReadValue(L"Version", &version))
192 return Version();
194 return Version(base::UTF16ToASCII(version));
197 // Returns whether Lenovo dCute is installed.
198 bool IsLenovoDCuteInstalled() {
199 base::win::RegKey key;
201 if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE", KEY_READ | KEY_WOW64_64KEY))
202 return false;
204 if (key.OpenKey(L"Lenovo", KEY_READ | KEY_WOW64_64KEY))
205 return false;
207 if (key.OpenKey(L"Lenovo dCute", KEY_READ | KEY_WOW64_64KEY))
208 return false;
210 return true;
213 // Determines whether D3D11 won't work, either because it is not supported on
214 // the machine or because it is known it is likely to crash.
215 bool D3D11ShouldWork(const GPUInfo& gpu_info) {
216 // TODO(apatrick): This is a temporary change to see what impact disabling
217 // D3D11 stats collection has on Canary.
218 #if 1
219 return false;
220 #else
221 // Windows XP never supports D3D11. It seems to be less stable that D3D9 on
222 // Vista.
223 if (base::win::GetVersion() <= base::win::VERSION_VISTA)
224 return false;
226 // http://crbug.com/175525.
227 if (gpu_info.display_link_version.IsValid())
228 return false;
230 return true;
231 #endif
234 // Collects information about the level of D3D11 support and records it in
235 // the UMA stats. Records no stats when D3D11 in not supported at all.
236 void CollectD3D11SupportOnWorkerThread() {
237 TRACE_EVENT0("gpu", "CollectD3D11Support");
239 typedef HRESULT (WINAPI *D3D11CreateDeviceFunc)(
240 IDXGIAdapter* adapter,
241 D3D_DRIVER_TYPE driver_type,
242 HMODULE software,
243 UINT flags,
244 const D3D_FEATURE_LEVEL* feature_levels,
245 UINT num_feature_levels,
246 UINT sdk_version,
247 ID3D11Device** device,
248 D3D_FEATURE_LEVEL* feature_level,
249 ID3D11DeviceContext** immediate_context);
251 // This enumeration must be kept in sync with histograms.xml. Do not reorder
252 // the members; always add to the end.
253 enum FeatureLevel {
254 FEATURE_LEVEL_UNKNOWN,
255 FEATURE_LEVEL_NO_D3D11_DLL,
256 FEATURE_LEVEL_NO_CREATE_DEVICE_ENTRY_POINT,
257 FEATURE_LEVEL_DEVICE_CREATION_FAILED,
258 FEATURE_LEVEL_9_1,
259 FEATURE_LEVEL_9_2,
260 FEATURE_LEVEL_9_3,
261 FEATURE_LEVEL_10_0,
262 FEATURE_LEVEL_10_1,
263 FEATURE_LEVEL_11_0,
264 NUM_FEATURE_LEVELS
267 FeatureLevel feature_level = FEATURE_LEVEL_UNKNOWN;
268 UINT bgra_support = 0;
270 // This module is leaked in case it is hooked by third party software.
271 base::NativeLibrary d3d11_module = base::LoadNativeLibrary(
272 base::FilePath(L"d3d11.dll"),
273 NULL);
275 if (!d3d11_module) {
276 feature_level = FEATURE_LEVEL_NO_D3D11_DLL;
277 } else {
278 D3D11CreateDeviceFunc create_func =
279 reinterpret_cast<D3D11CreateDeviceFunc>(
280 base::GetFunctionPointerFromNativeLibrary(d3d11_module,
281 "D3D11CreateDevice"));
282 if (!create_func) {
283 feature_level = FEATURE_LEVEL_NO_CREATE_DEVICE_ENTRY_POINT;
284 } else {
285 static const D3D_FEATURE_LEVEL d3d_feature_levels[] = {
286 D3D_FEATURE_LEVEL_11_0,
287 D3D_FEATURE_LEVEL_10_1,
288 D3D_FEATURE_LEVEL_10_0,
289 D3D_FEATURE_LEVEL_9_3,
290 D3D_FEATURE_LEVEL_9_2,
291 D3D_FEATURE_LEVEL_9_1
294 base::win::ScopedComPtr<ID3D11Device> device;
295 D3D_FEATURE_LEVEL d3d_feature_level;
296 base::win::ScopedComPtr<ID3D11DeviceContext> device_context;
297 HRESULT hr = create_func(NULL,
298 D3D_DRIVER_TYPE_HARDWARE,
299 NULL,
301 d3d_feature_levels,
302 arraysize(d3d_feature_levels),
303 D3D11_SDK_VERSION,
304 device.Receive(),
305 &d3d_feature_level,
306 device_context.Receive());
307 if (FAILED(hr)) {
308 feature_level = FEATURE_LEVEL_DEVICE_CREATION_FAILED;
309 } else {
310 switch (d3d_feature_level) {
311 case D3D_FEATURE_LEVEL_11_0:
312 feature_level = FEATURE_LEVEL_11_0;
313 break;
314 case D3D_FEATURE_LEVEL_10_1:
315 feature_level = FEATURE_LEVEL_10_1;
316 break;
317 case D3D_FEATURE_LEVEL_10_0:
318 feature_level = FEATURE_LEVEL_10_0;
319 break;
320 case D3D_FEATURE_LEVEL_9_3:
321 feature_level = FEATURE_LEVEL_9_3;
322 break;
323 case D3D_FEATURE_LEVEL_9_2:
324 feature_level = FEATURE_LEVEL_9_2;
325 break;
326 case D3D_FEATURE_LEVEL_9_1:
327 feature_level = FEATURE_LEVEL_9_1;
328 break;
329 default:
330 NOTREACHED();
331 break;
334 hr = device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM,
335 &bgra_support);
336 DCHECK(SUCCEEDED(hr));
341 UMA_HISTOGRAM_ENUMERATION("GPU.D3D11_FeatureLevel",
342 feature_level,
343 NUM_FEATURE_LEVELS);
345 // ANGLE requires at least feature level 10.0. Do not record any further
346 // stats if ANGLE would not work anyway.
347 if (feature_level < FEATURE_LEVEL_10_0)
348 return;
350 UMA_HISTOGRAM_BOOLEAN(
351 "GPU.D3D11_B8G8R8A8_Texture2DSupport",
352 (bgra_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0);
353 UMA_HISTOGRAM_BOOLEAN(
354 "GPU.D3D11_B8G8R8A8_RenderTargetSupport",
355 (bgra_support & D3D11_FORMAT_SUPPORT_RENDER_TARGET) != 0);
358 // Collects information about the level of D3D11 support and records it in
359 // the UMA stats. Records no stats when D3D11 in not supported at all.
360 void CollectD3D11Support() {
361 // D3D11 takes about 50ms to initialize so do this on a worker thread.
362 base::WorkerPool::PostTask(
363 FROM_HERE,
364 base::Bind(CollectD3D11SupportOnWorkerThread),
365 false);
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;
385 } // namespace anonymous
387 #if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD)
388 // This function has a real implementation for official builds that can
389 // be found in src/third_party/amd.
390 void GetAMDVideocardInfo(GPUInfo* gpu_info);
391 #else
392 void GetAMDVideocardInfo(GPUInfo* gpu_info) {
393 DCHECK(gpu_info);
394 return;
396 #endif
398 CollectInfoResult CollectDriverInfoD3D(const std::wstring& device_id,
399 GPUInfo* gpu_info) {
400 TRACE_EVENT0("gpu", "CollectDriverInfoD3D");
402 // Display adapter class GUID from
403 // https://msdn.microsoft.com/en-us/library/windows/hardware/ff553426%28v=vs.85%29.aspx
404 GUID display_class = {0x4d36e968,
405 0xe325,
406 0x11ce,
407 {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
409 // create device info for the display device
410 HDEVINFO device_info;
411 if (base::win::GetVersion() <= base::win::VERSION_XP) {
412 // Collection of information on all adapters is much slower on XP (almost
413 // 100ms), and not very useful (as it's not going to use the GPU anyway), so
414 // just collect information on the current device. http://crbug.com/456178
415 device_info =
416 SetupDiGetClassDevsW(NULL, device_id.c_str(), NULL,
417 DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES);
418 } else {
419 device_info =
420 SetupDiGetClassDevsW(&display_class, NULL, NULL, DIGCF_PRESENT);
422 if (device_info == INVALID_HANDLE_VALUE) {
423 LOG(ERROR) << "Creating device info failed";
424 return kCollectInfoNonFatalFailure;
427 struct GPUDriver {
428 GPUInfo::GPUDevice device;
429 std::string driver_vendor;
430 std::string driver_version;
431 std::string driver_date;
434 std::vector<GPUDriver> drivers;
436 int primary_device = -1;
437 bool found_amd = false;
438 bool found_intel = false;
440 DWORD index = 0;
441 SP_DEVINFO_DATA device_info_data;
442 device_info_data.cbSize = sizeof(device_info_data);
443 while (SetupDiEnumDeviceInfo(device_info, index++, &device_info_data)) {
444 WCHAR value[255];
445 if (SetupDiGetDeviceRegistryPropertyW(device_info,
446 &device_info_data,
447 SPDRP_DRIVER,
448 NULL,
449 reinterpret_cast<PBYTE>(value),
450 sizeof(value),
451 NULL)) {
452 HKEY key;
453 std::wstring driver_key = L"System\\CurrentControlSet\\Control\\Class\\";
454 driver_key += value;
455 LONG result = RegOpenKeyExW(
456 HKEY_LOCAL_MACHINE, driver_key.c_str(), 0, KEY_QUERY_VALUE, &key);
457 if (result == ERROR_SUCCESS) {
458 DWORD dwcb_data = sizeof(value);
459 std::string driver_version;
460 result = RegQueryValueExW(
461 key, L"DriverVersion", NULL, NULL,
462 reinterpret_cast<LPBYTE>(value), &dwcb_data);
463 if (result == ERROR_SUCCESS)
464 driver_version = base::UTF16ToASCII(std::wstring(value));
466 std::string driver_date;
467 dwcb_data = sizeof(value);
468 result = RegQueryValueExW(
469 key, L"DriverDate", NULL, NULL,
470 reinterpret_cast<LPBYTE>(value), &dwcb_data);
471 if (result == ERROR_SUCCESS)
472 driver_date = base::UTF16ToASCII(std::wstring(value));
474 std::string driver_vendor;
475 dwcb_data = sizeof(value);
476 result = RegQueryValueExW(
477 key, L"ProviderName", NULL, NULL,
478 reinterpret_cast<LPBYTE>(value), &dwcb_data);
479 if (result == ERROR_SUCCESS)
480 driver_vendor = base::UTF16ToASCII(std::wstring(value));
482 wchar_t new_device_id[MAX_DEVICE_ID_LEN];
483 CONFIGRET status = CM_Get_Device_ID(
484 device_info_data.DevInst, new_device_id, MAX_DEVICE_ID_LEN, 0);
486 if (status == CR_SUCCESS) {
487 GPUDriver driver;
489 driver.driver_vendor = driver_vendor;
490 driver.driver_version = driver_version;
491 driver.driver_date = driver_date;
492 std::wstring id = new_device_id;
494 if (id.compare(0, device_id.size(), device_id) == 0)
495 primary_device = drivers.size();
497 uint32 vendor_id = 0, device_id = 0;
498 DeviceIDToVendorAndDevice(id, &vendor_id, &device_id);
499 driver.device.vendor_id = vendor_id;
500 driver.device.device_id = device_id;
501 drivers.push_back(driver);
503 if (vendor_id == 0x8086)
504 found_intel = true;
505 if (vendor_id == 0x1002)
506 found_amd = true;
509 RegCloseKey(key);
513 SetupDiDestroyDeviceInfoList(device_info);
514 bool found = false;
515 if (found_amd && found_intel) {
516 // AMD Switchable system found.
517 for (const auto& driver : drivers) {
518 if (driver.device.vendor_id == 0x8086) {
519 gpu_info->gpu = driver.device;
522 if (driver.device.vendor_id == 0x1002) {
523 gpu_info->driver_vendor = driver.driver_vendor;
524 gpu_info->driver_version = driver.driver_version;
525 gpu_info->driver_date = driver.driver_date;
528 GetAMDVideocardInfo(gpu_info);
530 if (!gpu_info->amd_switchable) {
531 // Some machines aren't properly detected as AMD switchable, but count
532 // them anyway.
533 gpu_info->amd_switchable = true;
534 for (const auto& driver : drivers) {
535 if (driver.device.vendor_id == 0x1002) {
536 gpu_info->gpu = driver.device;
537 } else {
538 gpu_info->secondary_gpus.push_back(driver.device);
542 found = true;
543 } else {
544 for (size_t i = 0; i < drivers.size(); ++i) {
545 const GPUDriver& driver = drivers[i];
546 if (static_cast<int>(i) == primary_device) {
547 found = true;
548 gpu_info->gpu = driver.device;
549 gpu_info->driver_vendor = driver.driver_vendor;
550 gpu_info->driver_version = driver.driver_version;
551 gpu_info->driver_date = driver.driver_date;
552 } else {
553 gpu_info->secondary_gpus.push_back(driver.device);
558 return found ? kCollectInfoSuccess : kCollectInfoNonFatalFailure;
561 CollectInfoResult CollectContextGraphicsInfo(GPUInfo* gpu_info) {
562 TRACE_EVENT0("gpu", "CollectGraphicsInfo");
564 DCHECK(gpu_info);
566 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) {
567 std::string requested_implementation_name =
568 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
569 switches::kUseGL);
570 if (requested_implementation_name == "swiftshader") {
571 gpu_info->software_rendering = true;
572 gpu_info->context_info_state = kCollectInfoNonFatalFailure;
573 return kCollectInfoNonFatalFailure;
577 CollectInfoResult result = CollectGraphicsInfoGL(gpu_info);
578 if (result != kCollectInfoSuccess) {
579 gpu_info->context_info_state = result;
580 return result;
583 // ANGLE's renderer strings are of the form:
584 // ANGLE (<adapter_identifier> Direct3D<version> vs_x_x ps_x_x)
585 std::string direct3d_version;
586 int vertex_shader_major_version = 0;
587 int vertex_shader_minor_version = 0;
588 int pixel_shader_major_version = 0;
589 int pixel_shader_minor_version = 0;
590 gpu_info->adapter_luid = 0;
591 if (RE2::FullMatch(gpu_info->gl_renderer,
592 "ANGLE \\(.*\\)") &&
593 RE2::PartialMatch(gpu_info->gl_renderer,
594 " Direct3D(\\w+)",
595 &direct3d_version) &&
596 RE2::PartialMatch(gpu_info->gl_renderer,
597 " vs_(\\d+)_(\\d+)",
598 &vertex_shader_major_version,
599 &vertex_shader_minor_version) &&
600 RE2::PartialMatch(gpu_info->gl_renderer,
601 " ps_(\\d+)_(\\d+)",
602 &pixel_shader_major_version,
603 &pixel_shader_minor_version)) {
604 gpu_info->can_lose_context = direct3d_version == "9";
605 gpu_info->vertex_shader_version =
606 base::StringPrintf("%d.%d",
607 vertex_shader_major_version,
608 vertex_shader_minor_version);
609 gpu_info->pixel_shader_version =
610 base::StringPrintf("%d.%d",
611 pixel_shader_major_version,
612 pixel_shader_minor_version);
614 // ANGLE's EGL vendor strings are of the form:
615 // Google, Inc. (adapter LUID: 0123456789ABCDEF)
616 // The LUID is optional and identifies the GPU adapter ANGLE is using.
617 const char* egl_vendor = eglQueryString(
618 gfx::GLSurfaceEGL::GetHardwareDisplay(),
619 EGL_VENDOR);
620 RE2::PartialMatch(egl_vendor,
621 " \\(adapter LUID: ([0-9A-Fa-f]{16})\\)",
622 RE2::Hex(&gpu_info->adapter_luid));
624 // DirectX diagnostics are collected asynchronously because it takes a
625 // couple of seconds.
626 } else {
627 gpu_info->dx_diagnostics_info_state = kCollectInfoNonFatalFailure;
630 gpu_info->context_info_state = kCollectInfoSuccess;
631 return kCollectInfoSuccess;
634 CollectInfoResult CollectGpuID(uint32* vendor_id, uint32* device_id) {
635 DCHECK(vendor_id && device_id);
636 *vendor_id = 0;
637 *device_id = 0;
639 // Taken from http://developer.nvidia.com/object/device_ids.html
640 DISPLAY_DEVICE dd;
641 dd.cb = sizeof(DISPLAY_DEVICE);
642 std::wstring id;
643 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) {
644 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
645 id = dd.DeviceID;
646 break;
650 if (id.length() > 20) {
651 DeviceIDToVendorAndDevice(id, vendor_id, device_id);
652 if (*vendor_id != 0 && *device_id != 0)
653 return kCollectInfoSuccess;
655 return kCollectInfoNonFatalFailure;
658 CollectInfoResult CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
659 TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo");
661 DCHECK(gpu_info);
663 gpu_info->performance_stats = RetrieveGpuPerformanceStatsWithHistograms();
665 // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
666 HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
667 gpu_info->optimus = nvd3d9wrap != NULL;
669 gpu_info->lenovo_dcute = IsLenovoDCuteInstalled();
671 gpu_info->display_link_version = DisplayLinkVersion();
673 if (!gpu_info->display_link_version .IsValid()) {
674 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
675 DISPLAY_LINK_NOT_INSTALLED,
676 DISPLAY_LINK_INSTALLATION_STATUS_MAX);
677 } else if (gpu_info->display_link_version.IsOlderThan("7.2")) {
678 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
679 DISPLAY_LINK_7_1_OR_EARLIER,
680 DISPLAY_LINK_INSTALLATION_STATUS_MAX);
681 } else {
682 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
683 DISPLAY_LINK_7_2_OR_LATER,
684 DISPLAY_LINK_INSTALLATION_STATUS_MAX);
687 // Taken from http://developer.nvidia.com/object/device_ids.html
688 DISPLAY_DEVICE dd;
689 dd.cb = sizeof(DISPLAY_DEVICE);
690 std::wstring id;
691 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) {
692 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
693 id = dd.DeviceID;
694 break;
698 if (id.length() <= 20) {
699 gpu_info->basic_info_state = kCollectInfoNonFatalFailure;
700 return kCollectInfoNonFatalFailure;
703 DeviceIDToVendorAndDevice(id, &gpu_info->gpu.vendor_id,
704 &gpu_info->gpu.device_id);
705 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE.
706 if (!CollectDriverInfoD3D(id, gpu_info)) {
707 gpu_info->basic_info_state = kCollectInfoNonFatalFailure;
708 return kCollectInfoNonFatalFailure;
711 // Collect basic information about supported D3D11 features. Delay for 45
712 // seconds so as not to regress performance tests.
713 if (D3D11ShouldWork(*gpu_info)) {
714 // This is on a field trial so we can turn it off easily if it blows up
715 // again in stable channel.
716 scoped_refptr<base::FieldTrial> trial(
717 base::FieldTrialList::FactoryGetFieldTrial(
718 "D3D11Experiment", 100, "Disabled", 2015, 7, 8,
719 base::FieldTrial::SESSION_RANDOMIZED, NULL));
720 const int enabled_group =
721 trial->AppendGroup("Enabled", 0);
723 if (trial->group() == enabled_group) {
724 base::MessageLoop::current()->PostDelayedTask(
725 FROM_HERE,
726 base::Bind(&CollectD3D11Support),
727 base::TimeDelta::FromSeconds(45));
731 gpu_info->basic_info_state = kCollectInfoSuccess;
732 return kCollectInfoSuccess;
735 CollectInfoResult CollectDriverInfoGL(GPUInfo* gpu_info) {
736 TRACE_EVENT0("gpu", "CollectDriverInfoGL");
738 if (!gpu_info->driver_version.empty())
739 return kCollectInfoSuccess;
741 bool parsed = RE2::PartialMatch(
742 gpu_info->gl_version, "([\\d\\.]+)$", &gpu_info->driver_version);
743 return parsed ? kCollectInfoSuccess : kCollectInfoNonFatalFailure;
746 void MergeGPUInfo(GPUInfo* basic_gpu_info,
747 const GPUInfo& context_gpu_info) {
748 DCHECK(basic_gpu_info);
750 if (context_gpu_info.software_rendering) {
751 basic_gpu_info->software_rendering = true;
752 return;
755 // Track D3D Shader Model (if available)
756 const std::string& shader_version =
757 context_gpu_info.vertex_shader_version;
759 // Only gather if this is the first time we're seeing
760 // a non-empty shader version string.
761 if (!shader_version.empty() &&
762 basic_gpu_info->vertex_shader_version.empty()) {
764 // Note: do not reorder, used by UMA_HISTOGRAM below
765 enum ShaderModel {
766 SHADER_MODEL_UNKNOWN,
767 SHADER_MODEL_2_0,
768 SHADER_MODEL_3_0,
769 SHADER_MODEL_4_0,
770 SHADER_MODEL_4_1,
771 SHADER_MODEL_5_0,
772 NUM_SHADER_MODELS
775 ShaderModel shader_model = SHADER_MODEL_UNKNOWN;
777 if (shader_version == "5.0") {
778 shader_model = SHADER_MODEL_5_0;
779 } else if (shader_version == "4.1") {
780 shader_model = SHADER_MODEL_4_1;
781 } else if (shader_version == "4.0") {
782 shader_model = SHADER_MODEL_4_0;
783 } else if (shader_version == "3.0") {
784 shader_model = SHADER_MODEL_3_0;
785 } else if (shader_version == "2.0") {
786 shader_model = SHADER_MODEL_2_0;
789 UMA_HISTOGRAM_ENUMERATION("GPU.D3DShaderModel",
790 shader_model,
791 NUM_SHADER_MODELS);
794 MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
796 basic_gpu_info->dx_diagnostics = context_gpu_info.dx_diagnostics;
799 } // namespace gpu