- add sources.
[platform/framework/web/crosswalk.git] / src / gpu / config / gpu_info_collector_win.cc
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   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   string16 vendor_id_string = id.substr(8, 4);
594   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 }  // namespace gpu