Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / gpu / config / gpu_info_collector_win.cc
blobeabf9b22681556c02a41cd33159c4119f28b0771
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 <d3d9.h>
12 #include <d3d11.h>
13 #include <dxgi.h>
14 #include <setupapi.h>
16 #include "base/command_line.h"
17 #include "base/debug/trace_event.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/win/registry.h"
34 #include "base/win/scoped_com_initializer.h"
35 #include "base/win/scoped_comptr.h"
36 #include "base/win/windows_version.h"
37 #include "third_party/libxml/chromium/libxml_utils.h"
38 #include "ui/gl/gl_implementation.h"
39 #include "ui/gl/gl_surface_egl.h"
41 namespace gpu {
43 namespace {
45 // This must be kept in sync with histograms.xml.
46 enum DisplayLinkInstallationStatus {
47 DISPLAY_LINK_NOT_INSTALLED,
48 DISPLAY_LINK_7_1_OR_EARLIER,
49 DISPLAY_LINK_7_2_OR_LATER,
50 DISPLAY_LINK_INSTALLATION_STATUS_MAX
53 float ReadXMLFloatValue(XmlReader* reader) {
54 std::string score_string;
55 if (!reader->ReadElementContent(&score_string))
56 return 0.0;
58 double score;
59 if (!base::StringToDouble(score_string, &score))
60 return 0.0;
62 return static_cast<float>(score);
65 GpuPerformanceStats RetrieveGpuPerformanceStats() {
66 TRACE_EVENT0("gpu", "RetrieveGpuPerformanceStats");
68 // If the user re-runs the assessment without restarting, the COM API
69 // returns WINSAT_ASSESSMENT_STATE_NOT_AVAILABLE. Because of that and
70 // http://crbug.com/124325, read the assessment result files directly.
71 GpuPerformanceStats stats;
73 // Get path to WinSAT results files.
74 wchar_t winsat_results_path[MAX_PATH];
75 DWORD size = ExpandEnvironmentStrings(
76 L"%WinDir%\\Performance\\WinSAT\\DataStore\\",
77 winsat_results_path, MAX_PATH);
78 if (size == 0 || size > MAX_PATH) {
79 LOG(ERROR) << "The path to the WinSAT results is too long: "
80 << size << " chars.";
81 return stats;
84 // Find most recent formal assessment results.
85 base::FileEnumerator file_enumerator(
86 base::FilePath(winsat_results_path),
87 false, // not recursive
88 base::FileEnumerator::FILES,
89 FILE_PATH_LITERAL("* * Formal.Assessment (*).WinSAT.xml"));
91 base::FilePath current_results;
92 for (base::FilePath results = file_enumerator.Next(); !results.empty();
93 results = file_enumerator.Next()) {
94 // The filenames start with the date and time as yyyy-mm-dd hh.mm.ss.xxx,
95 // so the greatest file lexicographically is also the most recent file.
96 if (base::FilePath::CompareLessIgnoreCase(current_results.value(),
97 results.value()))
98 current_results = results;
101 std::string current_results_string = current_results.MaybeAsASCII();
102 if (current_results_string.empty())
103 return stats;
105 // Get relevant scores from results file. XML schema at:
106 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa969210.aspx
107 XmlReader reader;
108 if (!reader.LoadFile(current_results_string)) {
109 LOG(ERROR) << "Could not open WinSAT results file.";
110 return stats;
112 // Descend into <WinSAT> root element.
113 if (!reader.SkipToElement() || !reader.Read()) {
114 LOG(ERROR) << "Could not read WinSAT results file.";
115 return stats;
118 // Search for <WinSPR> element containing the results.
119 do {
120 if (reader.NodeName() == "WinSPR")
121 break;
122 } while (reader.Next());
123 // Descend into <WinSPR> element.
124 if (!reader.Read()) {
125 LOG(ERROR) << "Could not find WinSPR element in results file.";
126 return stats;
129 // Read scores.
130 for (int depth = reader.Depth(); reader.Depth() == depth; reader.Next()) {
131 std::string node_name = reader.NodeName();
132 if (node_name == "SystemScore")
133 stats.overall = ReadXMLFloatValue(&reader);
134 else if (node_name == "GraphicsScore")
135 stats.graphics = ReadXMLFloatValue(&reader);
136 else if (node_name == "GamingScore")
137 stats.gaming = ReadXMLFloatValue(&reader);
140 if (stats.overall == 0.0)
141 LOG(ERROR) << "Could not read overall score from assessment results.";
142 if (stats.graphics == 0.0)
143 LOG(ERROR) << "Could not read graphics score from assessment results.";
144 if (stats.gaming == 0.0)
145 LOG(ERROR) << "Could not read gaming score from assessment results.";
147 return stats;
150 GpuPerformanceStats RetrieveGpuPerformanceStatsWithHistograms() {
151 base::TimeTicks start_time = base::TimeTicks::Now();
153 GpuPerformanceStats stats = RetrieveGpuPerformanceStats();
155 UMA_HISTOGRAM_TIMES("GPU.WinSAT.ReadResultsFileTime",
156 base::TimeTicks::Now() - start_time);
157 UMA_HISTOGRAM_CUSTOM_COUNTS(
158 "GPU.WinSAT.OverallScore2",
159 static_cast<base::HistogramBase::Sample>(stats.overall * 10), 10, 200,
160 50);
161 UMA_HISTOGRAM_CUSTOM_COUNTS(
162 "GPU.WinSAT.GraphicsScore2",
163 static_cast<base::HistogramBase::Sample>(stats.graphics * 10), 10, 200,
164 50);
165 UMA_HISTOGRAM_CUSTOM_COUNTS(
166 "GPU.WinSAT.GamingScore2",
167 static_cast<base::HistogramBase::Sample>(stats.gaming * 10), 10, 200, 50);
168 UMA_HISTOGRAM_BOOLEAN(
169 "GPU.WinSAT.HasResults",
170 stats.overall != 0.0 && stats.graphics != 0.0 && stats.gaming != 0.0);
172 return stats;
175 // Returns the display link driver version or an invalid version if it is
176 // not installed.
177 Version DisplayLinkVersion() {
178 base::win::RegKey key;
180 if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE", KEY_READ | KEY_WOW64_64KEY))
181 return Version();
183 if (key.OpenKey(L"DisplayLink", KEY_READ | KEY_WOW64_64KEY))
184 return Version();
186 if (key.OpenKey(L"Core", KEY_READ | KEY_WOW64_64KEY))
187 return Version();
189 base::string16 version;
190 if (key.ReadValue(L"Version", &version))
191 return Version();
193 return Version(base::UTF16ToASCII(version));
196 // Returns whether Lenovo dCute is installed.
197 bool IsLenovoDCuteInstalled() {
198 base::win::RegKey key;
200 if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE", KEY_READ | KEY_WOW64_64KEY))
201 return false;
203 if (key.OpenKey(L"Lenovo", KEY_READ | KEY_WOW64_64KEY))
204 return false;
206 if (key.OpenKey(L"Lenovo dCute", KEY_READ | KEY_WOW64_64KEY))
207 return false;
209 return true;
212 // Determines whether D3D11 won't work, either because it is not supported on
213 // the machine or because it is known it is likely to crash.
214 bool D3D11ShouldWork(const GPUInfo& gpu_info) {
215 // TODO(apatrick): This is a temporary change to see what impact disabling
216 // D3D11 stats collection has on Canary.
217 #if 1
218 return false;
219 #else
220 // Windows XP never supports D3D11. It seems to be less stable that D3D9 on
221 // Vista.
222 if (base::win::GetVersion() <= base::win::VERSION_VISTA)
223 return false;
225 // http://crbug.com/175525.
226 if (gpu_info.display_link_version.IsValid())
227 return false;
229 return true;
230 #endif
233 // Collects information about the level of D3D11 support and records it in
234 // the UMA stats. Records no stats when D3D11 in not supported at all.
235 void CollectD3D11SupportOnWorkerThread() {
236 TRACE_EVENT0("gpu", "CollectD3D11Support");
238 typedef HRESULT (WINAPI *D3D11CreateDeviceFunc)(
239 IDXGIAdapter* adapter,
240 D3D_DRIVER_TYPE driver_type,
241 HMODULE software,
242 UINT flags,
243 const D3D_FEATURE_LEVEL* feature_levels,
244 UINT num_feature_levels,
245 UINT sdk_version,
246 ID3D11Device** device,
247 D3D_FEATURE_LEVEL* feature_level,
248 ID3D11DeviceContext** immediate_context);
250 // This enumeration must be kept in sync with histograms.xml. Do not reorder
251 // the members; always add to the end.
252 enum FeatureLevel {
253 FEATURE_LEVEL_UNKNOWN,
254 FEATURE_LEVEL_NO_D3D11_DLL,
255 FEATURE_LEVEL_NO_CREATE_DEVICE_ENTRY_POINT,
256 FEATURE_LEVEL_DEVICE_CREATION_FAILED,
257 FEATURE_LEVEL_9_1,
258 FEATURE_LEVEL_9_2,
259 FEATURE_LEVEL_9_3,
260 FEATURE_LEVEL_10_0,
261 FEATURE_LEVEL_10_1,
262 FEATURE_LEVEL_11_0,
263 NUM_FEATURE_LEVELS
266 FeatureLevel feature_level = FEATURE_LEVEL_UNKNOWN;
267 UINT bgra_support = 0;
269 // This module is leaked in case it is hooked by third party software.
270 base::NativeLibrary d3d11_module = base::LoadNativeLibrary(
271 base::FilePath(L"d3d11.dll"),
272 NULL);
274 if (!d3d11_module) {
275 feature_level = FEATURE_LEVEL_NO_D3D11_DLL;
276 } else {
277 D3D11CreateDeviceFunc create_func =
278 reinterpret_cast<D3D11CreateDeviceFunc>(
279 base::GetFunctionPointerFromNativeLibrary(d3d11_module,
280 "D3D11CreateDevice"));
281 if (!create_func) {
282 feature_level = FEATURE_LEVEL_NO_CREATE_DEVICE_ENTRY_POINT;
283 } else {
284 static const D3D_FEATURE_LEVEL d3d_feature_levels[] = {
285 D3D_FEATURE_LEVEL_11_0,
286 D3D_FEATURE_LEVEL_10_1,
287 D3D_FEATURE_LEVEL_10_0,
288 D3D_FEATURE_LEVEL_9_3,
289 D3D_FEATURE_LEVEL_9_2,
290 D3D_FEATURE_LEVEL_9_1
293 base::win::ScopedComPtr<ID3D11Device> device;
294 D3D_FEATURE_LEVEL d3d_feature_level;
295 base::win::ScopedComPtr<ID3D11DeviceContext> device_context;
296 HRESULT hr = create_func(NULL,
297 D3D_DRIVER_TYPE_HARDWARE,
298 NULL,
300 d3d_feature_levels,
301 arraysize(d3d_feature_levels),
302 D3D11_SDK_VERSION,
303 device.Receive(),
304 &d3d_feature_level,
305 device_context.Receive());
306 if (FAILED(hr)) {
307 feature_level = FEATURE_LEVEL_DEVICE_CREATION_FAILED;
308 } else {
309 switch (d3d_feature_level) {
310 case D3D_FEATURE_LEVEL_11_0:
311 feature_level = FEATURE_LEVEL_11_0;
312 break;
313 case D3D_FEATURE_LEVEL_10_1:
314 feature_level = FEATURE_LEVEL_10_1;
315 break;
316 case D3D_FEATURE_LEVEL_10_0:
317 feature_level = FEATURE_LEVEL_10_0;
318 break;
319 case D3D_FEATURE_LEVEL_9_3:
320 feature_level = FEATURE_LEVEL_9_3;
321 break;
322 case D3D_FEATURE_LEVEL_9_2:
323 feature_level = FEATURE_LEVEL_9_2;
324 break;
325 case D3D_FEATURE_LEVEL_9_1:
326 feature_level = FEATURE_LEVEL_9_1;
327 break;
328 default:
329 NOTREACHED();
330 break;
333 hr = device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM,
334 &bgra_support);
335 DCHECK(SUCCEEDED(hr));
340 UMA_HISTOGRAM_ENUMERATION("GPU.D3D11_FeatureLevel",
341 feature_level,
342 NUM_FEATURE_LEVELS);
344 // ANGLE requires at least feature level 10.0. Do not record any further
345 // stats if ANGLE would not work anyway.
346 if (feature_level < FEATURE_LEVEL_10_0)
347 return;
349 UMA_HISTOGRAM_BOOLEAN(
350 "GPU.D3D11_B8G8R8A8_Texture2DSupport",
351 (bgra_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0);
352 UMA_HISTOGRAM_BOOLEAN(
353 "GPU.D3D11_B8G8R8A8_RenderTargetSupport",
354 (bgra_support & D3D11_FORMAT_SUPPORT_RENDER_TARGET) != 0);
357 // 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 void CollectD3D11Support() {
360 // D3D11 takes about 50ms to initialize so do this on a worker thread.
361 base::WorkerPool::PostTask(
362 FROM_HERE,
363 base::Bind(CollectD3D11SupportOnWorkerThread),
364 false);
366 } // namespace anonymous
368 #if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD)
369 // This function has a real implementation for official builds that can
370 // be found in src/third_party/amd.
371 void GetAMDVideocardInfo(GPUInfo* gpu_info);
372 #else
373 void GetAMDVideocardInfo(GPUInfo* gpu_info) {
374 DCHECK(gpu_info);
375 return;
377 #endif
379 CollectInfoResult CollectDriverInfoD3D(const std::wstring& device_id,
380 GPUInfo* gpu_info) {
381 TRACE_EVENT0("gpu", "CollectDriverInfoD3D");
383 // create device info for the display device
384 HDEVINFO device_info = SetupDiGetClassDevsW(
385 NULL, device_id.c_str(), NULL,
386 DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES);
387 if (device_info == INVALID_HANDLE_VALUE) {
388 LOG(ERROR) << "Creating device info failed";
389 return kCollectInfoNonFatalFailure;
392 DWORD index = 0;
393 bool found = false;
394 SP_DEVINFO_DATA device_info_data;
395 device_info_data.cbSize = sizeof(device_info_data);
396 while (SetupDiEnumDeviceInfo(device_info, index++, &device_info_data)) {
397 WCHAR value[255];
398 if (SetupDiGetDeviceRegistryPropertyW(device_info,
399 &device_info_data,
400 SPDRP_DRIVER,
401 NULL,
402 reinterpret_cast<PBYTE>(value),
403 sizeof(value),
404 NULL)) {
405 HKEY key;
406 std::wstring driver_key = L"System\\CurrentControlSet\\Control\\Class\\";
407 driver_key += value;
408 LONG result = RegOpenKeyExW(
409 HKEY_LOCAL_MACHINE, driver_key.c_str(), 0, KEY_QUERY_VALUE, &key);
410 if (result == ERROR_SUCCESS) {
411 DWORD dwcb_data = sizeof(value);
412 std::string driver_version;
413 result = RegQueryValueExW(
414 key, L"DriverVersion", NULL, NULL,
415 reinterpret_cast<LPBYTE>(value), &dwcb_data);
416 if (result == ERROR_SUCCESS)
417 driver_version = base::UTF16ToASCII(std::wstring(value));
419 std::string driver_date;
420 dwcb_data = sizeof(value);
421 result = RegQueryValueExW(
422 key, L"DriverDate", NULL, NULL,
423 reinterpret_cast<LPBYTE>(value), &dwcb_data);
424 if (result == ERROR_SUCCESS)
425 driver_date = base::UTF16ToASCII(std::wstring(value));
427 std::string driver_vendor;
428 dwcb_data = sizeof(value);
429 result = RegQueryValueExW(
430 key, L"ProviderName", NULL, NULL,
431 reinterpret_cast<LPBYTE>(value), &dwcb_data);
432 if (result == ERROR_SUCCESS) {
433 driver_vendor = base::UTF16ToASCII(std::wstring(value));
434 if (driver_vendor == "Advanced Micro Devices, Inc." ||
435 driver_vendor == "ATI Technologies Inc.") {
436 // We are conservative and assume that in the absence of a clear
437 // signal the videocard is assumed to be switchable. Additionally,
438 // some switchable systems with Intel GPUs aren't correctly
439 // detected, so always count them.
440 GetAMDVideocardInfo(gpu_info);
441 if (!gpu_info->amd_switchable &&
442 gpu_info->gpu.vendor_id == 0x8086) {
443 gpu_info->amd_switchable = true;
444 gpu_info->secondary_gpus.push_back(gpu_info->gpu);
445 gpu_info->gpu.vendor_id = 0x1002;
446 gpu_info->gpu.device_id = 0; // Unknown discrete AMD GPU.
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);
456 break;
460 SetupDiDestroyDeviceInfoList(device_info);
461 return found ? kCollectInfoSuccess : kCollectInfoNonFatalFailure;
464 CollectInfoResult CollectContextGraphicsInfo(GPUInfo* gpu_info) {
465 TRACE_EVENT0("gpu", "CollectGraphicsInfo");
467 DCHECK(gpu_info);
469 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) {
470 std::string requested_implementation_name =
471 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL);
472 if (requested_implementation_name == "swiftshader") {
473 gpu_info->software_rendering = true;
474 gpu_info->context_info_state = kCollectInfoNonFatalFailure;
475 return kCollectInfoNonFatalFailure;
479 CollectInfoResult result = CollectGraphicsInfoGL(gpu_info);
480 if (result != kCollectInfoSuccess) {
481 gpu_info->context_info_state = result;
482 return result;
485 // ANGLE's renderer strings are of the form:
486 // ANGLE (<adapter_identifier> Direct3D<version> vs_x_x ps_x_x)
487 std::string direct3d_version;
488 int vertex_shader_major_version = 0;
489 int vertex_shader_minor_version = 0;
490 int pixel_shader_major_version = 0;
491 int pixel_shader_minor_version = 0;
492 gpu_info->adapter_luid = 0;
493 if (RE2::FullMatch(gpu_info->gl_renderer,
494 "ANGLE \\(.*\\)") &&
495 RE2::PartialMatch(gpu_info->gl_renderer,
496 " Direct3D(\\w+)",
497 &direct3d_version) &&
498 RE2::PartialMatch(gpu_info->gl_renderer,
499 " vs_(\\d+)_(\\d+)",
500 &vertex_shader_major_version,
501 &vertex_shader_minor_version) &&
502 RE2::PartialMatch(gpu_info->gl_renderer,
503 " ps_(\\d+)_(\\d+)",
504 &pixel_shader_major_version,
505 &pixel_shader_minor_version)) {
506 gpu_info->can_lose_context = direct3d_version == "9";
507 gpu_info->vertex_shader_version =
508 base::StringPrintf("%d.%d",
509 vertex_shader_major_version,
510 vertex_shader_minor_version);
511 gpu_info->pixel_shader_version =
512 base::StringPrintf("%d.%d",
513 pixel_shader_major_version,
514 pixel_shader_minor_version);
516 // ANGLE's EGL vendor strings are of the form:
517 // Google, Inc. (adapter LUID: 0123456789ABCDEF)
518 // The LUID is optional and identifies the GPU adapter ANGLE is using.
519 const char* egl_vendor = eglQueryString(
520 gfx::GLSurfaceEGL::GetHardwareDisplay(),
521 EGL_VENDOR);
522 RE2::PartialMatch(egl_vendor,
523 " \\(adapter LUID: ([0-9A-Fa-f]{16})\\)",
524 RE2::Hex(&gpu_info->adapter_luid));
526 // DirectX diagnostics are collected asynchronously because it takes a
527 // couple of seconds.
528 } else {
529 gpu_info->dx_diagnostics_info_state = kCollectInfoNonFatalFailure;
532 gpu_info->context_info_state = kCollectInfoSuccess;
533 return kCollectInfoSuccess;
536 CollectInfoResult CollectGpuID(uint32* vendor_id, uint32* device_id) {
537 DCHECK(vendor_id && device_id);
538 *vendor_id = 0;
539 *device_id = 0;
541 // Taken from http://developer.nvidia.com/object/device_ids.html
542 DISPLAY_DEVICE dd;
543 dd.cb = sizeof(DISPLAY_DEVICE);
544 std::wstring id;
545 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) {
546 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
547 id = dd.DeviceID;
548 break;
552 if (id.length() > 20) {
553 int vendor = 0, device = 0;
554 std::wstring vendor_string = id.substr(8, 4);
555 std::wstring device_string = id.substr(17, 4);
556 base::HexStringToInt(base::UTF16ToASCII(vendor_string), &vendor);
557 base::HexStringToInt(base::UTF16ToASCII(device_string), &device);
558 *vendor_id = vendor;
559 *device_id = device;
560 if (*vendor_id != 0 && *device_id != 0)
561 return kCollectInfoSuccess;
563 return kCollectInfoNonFatalFailure;
566 CollectInfoResult CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
567 TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo");
569 DCHECK(gpu_info);
571 gpu_info->performance_stats = RetrieveGpuPerformanceStatsWithHistograms();
573 // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
574 HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
575 gpu_info->optimus = nvd3d9wrap != NULL;
577 gpu_info->lenovo_dcute = IsLenovoDCuteInstalled();
579 gpu_info->display_link_version = DisplayLinkVersion();
581 if (!gpu_info->display_link_version .IsValid()) {
582 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
583 DISPLAY_LINK_NOT_INSTALLED,
584 DISPLAY_LINK_INSTALLATION_STATUS_MAX);
585 } else if (gpu_info->display_link_version.IsOlderThan("7.2")) {
586 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
587 DISPLAY_LINK_7_1_OR_EARLIER,
588 DISPLAY_LINK_INSTALLATION_STATUS_MAX);
589 } else {
590 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
591 DISPLAY_LINK_7_2_OR_LATER,
592 DISPLAY_LINK_INSTALLATION_STATUS_MAX);
595 // Taken from http://developer.nvidia.com/object/device_ids.html
596 DISPLAY_DEVICE dd;
597 dd.cb = sizeof(DISPLAY_DEVICE);
598 std::wstring id;
599 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) {
600 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
601 id = dd.DeviceID;
602 break;
606 if (id.length() <= 20) {
607 gpu_info->basic_info_state = kCollectInfoNonFatalFailure;
608 return kCollectInfoNonFatalFailure;
611 int vendor_id = 0, device_id = 0;
612 base::string16 vendor_id_string = id.substr(8, 4);
613 base::string16 device_id_string = id.substr(17, 4);
614 base::HexStringToInt(base::UTF16ToASCII(vendor_id_string), &vendor_id);
615 base::HexStringToInt(base::UTF16ToASCII(device_id_string), &device_id);
616 gpu_info->gpu.vendor_id = vendor_id;
617 gpu_info->gpu.device_id = device_id;
618 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE.
619 if (!CollectDriverInfoD3D(id, gpu_info)) {
620 gpu_info->basic_info_state = kCollectInfoNonFatalFailure;
621 return kCollectInfoNonFatalFailure;
624 // Collect basic information about supported D3D11 features. Delay for 45
625 // seconds so as not to regress performance tests.
626 if (D3D11ShouldWork(*gpu_info)) {
627 // This is on a field trial so we can turn it off easily if it blows up
628 // again in stable channel.
629 scoped_refptr<base::FieldTrial> trial(
630 base::FieldTrialList::FactoryGetFieldTrial(
631 "D3D11Experiment", 100, "Disabled", 2015, 7, 8,
632 base::FieldTrial::SESSION_RANDOMIZED, NULL));
633 const int enabled_group =
634 trial->AppendGroup("Enabled", 0);
636 if (trial->group() == enabled_group) {
637 base::MessageLoop::current()->PostDelayedTask(
638 FROM_HERE,
639 base::Bind(&CollectD3D11Support),
640 base::TimeDelta::FromSeconds(45));
644 gpu_info->basic_info_state = kCollectInfoSuccess;
645 return kCollectInfoSuccess;
648 CollectInfoResult CollectDriverInfoGL(GPUInfo* gpu_info) {
649 TRACE_EVENT0("gpu", "CollectDriverInfoGL");
651 if (!gpu_info->driver_version.empty())
652 return kCollectInfoSuccess;
654 bool parsed = RE2::PartialMatch(
655 gpu_info->gl_version, "([\\d\\.]+)$", &gpu_info->driver_version);
656 return parsed ? kCollectInfoSuccess : kCollectInfoNonFatalFailure;
659 void MergeGPUInfo(GPUInfo* basic_gpu_info,
660 const GPUInfo& context_gpu_info) {
661 DCHECK(basic_gpu_info);
663 if (context_gpu_info.software_rendering) {
664 basic_gpu_info->software_rendering = true;
665 return;
668 // Track D3D Shader Model (if available)
669 const std::string& shader_version =
670 context_gpu_info.vertex_shader_version;
672 // Only gather if this is the first time we're seeing
673 // a non-empty shader version string.
674 if (!shader_version.empty() &&
675 basic_gpu_info->vertex_shader_version.empty()) {
677 // Note: do not reorder, used by UMA_HISTOGRAM below
678 enum ShaderModel {
679 SHADER_MODEL_UNKNOWN,
680 SHADER_MODEL_2_0,
681 SHADER_MODEL_3_0,
682 SHADER_MODEL_4_0,
683 SHADER_MODEL_4_1,
684 SHADER_MODEL_5_0,
685 NUM_SHADER_MODELS
688 ShaderModel shader_model = SHADER_MODEL_UNKNOWN;
690 if (shader_version == "5.0") {
691 shader_model = SHADER_MODEL_5_0;
692 } else if (shader_version == "4.1") {
693 shader_model = SHADER_MODEL_4_1;
694 } else if (shader_version == "4.0") {
695 shader_model = SHADER_MODEL_4_0;
696 } else if (shader_version == "3.0") {
697 shader_model = SHADER_MODEL_3_0;
698 } else if (shader_version == "2.0") {
699 shader_model = SHADER_MODEL_2_0;
702 UMA_HISTOGRAM_ENUMERATION("GPU.D3DShaderModel",
703 shader_model,
704 NUM_SHADER_MODELS);
707 MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
709 basic_gpu_info->dx_diagnostics = context_gpu_info.dx_diagnostics;
712 } // namespace gpu