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
40namespace gpu {
41
42namespace {
43
44// This must be kept in sync with histograms.xml.
45enum 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
52float 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
64GpuPerformanceStats 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
151GpuPerformanceStats 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.
173Version 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.
193bool 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.
210bool 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.
229void 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.
353void 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)
363AMDVideoCardType 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.
369AMDVideoCardType GetAMDVideocardType();
370#endif
371
372bool 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
452bool 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
520GpuIDResult 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
549bool 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
626bool 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
639void 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
654