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"
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"
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
))
59 if (!base::StringToDouble(score_string
, &score
))
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: "
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(),
98 current_results
= results
;
101 std::string current_results_string
= current_results
.MaybeAsASCII();
102 if (current_results_string
.empty())
105 // Get relevant scores from results file. XML schema at:
106 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa969210.aspx
108 if (!reader
.LoadFile(current_results_string
)) {
109 LOG(ERROR
) << "Could not open WinSAT results file.";
112 // Descend into <WinSAT> root element.
113 if (!reader
.SkipToElement() || !reader
.Read()) {
114 LOG(ERROR
) << "Could not read WinSAT results file.";
118 // Search for <WinSPR> element containing the results.
120 if (reader
.NodeName() == "WinSPR")
122 } while (reader
.Next());
123 // Descend into <WinSPR> element.
124 if (!reader
.Read()) {
125 LOG(ERROR
) << "Could not find WinSPR element in results file.";
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.";
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("GPU.WinSAT.OverallScore2",
158 stats
.overall
* 10, 10, 200, 50);
159 UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.WinSAT.GraphicsScore2",
160 stats
.graphics
* 10, 10, 200, 50);
161 UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.WinSAT.GamingScore2",
162 stats
.gaming
* 10, 10, 200, 50);
163 UMA_HISTOGRAM_BOOLEAN(
164 "GPU.WinSAT.HasResults",
165 stats
.overall
!= 0.0 && stats
.graphics
!= 0.0 && stats
.gaming
!= 0.0);
170 // Returns the display link driver version or an invalid version if it is
172 Version
DisplayLinkVersion() {
173 base::win::RegKey key
;
175 if (key
.Open(HKEY_LOCAL_MACHINE
, L
"SOFTWARE", KEY_READ
| KEY_WOW64_64KEY
))
178 if (key
.OpenKey(L
"DisplayLink", KEY_READ
| KEY_WOW64_64KEY
))
181 if (key
.OpenKey(L
"Core", KEY_READ
| KEY_WOW64_64KEY
))
184 base::string16 version
;
185 if (key
.ReadValue(L
"Version", &version
))
188 return Version(base::UTF16ToASCII(version
));
191 // Returns whether Lenovo dCute is installed.
192 bool IsLenovoDCuteInstalled() {
193 base::win::RegKey key
;
195 if (key
.Open(HKEY_LOCAL_MACHINE
, L
"SOFTWARE", KEY_READ
| KEY_WOW64_64KEY
))
198 if (key
.OpenKey(L
"Lenovo", KEY_READ
| KEY_WOW64_64KEY
))
201 if (key
.OpenKey(L
"Lenovo dCute", KEY_READ
| KEY_WOW64_64KEY
))
207 // Determines whether D3D11 won't work, either because it is not supported on
208 // the machine or because it is known it is likely to crash.
209 bool D3D11ShouldWork(const GPUInfo
& gpu_info
) {
210 // TODO(apatrick): This is a temporary change to see what impact disabling
211 // D3D11 stats collection has on Canary.
215 // Windows XP never supports D3D11. It seems to be less stable that D3D9 on
217 if (base::win::GetVersion() <= base::win::VERSION_VISTA
)
220 // http://crbug.com/175525.
221 if (gpu_info
.display_link_version
.IsValid())
228 // Collects information about the level of D3D11 support and records it in
229 // the UMA stats. Records no stats when D3D11 in not supported at all.
230 void CollectD3D11SupportOnWorkerThread() {
231 TRACE_EVENT0("gpu", "CollectD3D11Support");
233 typedef HRESULT (WINAPI
*D3D11CreateDeviceFunc
)(
234 IDXGIAdapter
* adapter
,
235 D3D_DRIVER_TYPE driver_type
,
238 const D3D_FEATURE_LEVEL
* feature_levels
,
239 UINT num_feature_levels
,
241 ID3D11Device
** device
,
242 D3D_FEATURE_LEVEL
* feature_level
,
243 ID3D11DeviceContext
** immediate_context
);
245 // This enumeration must be kept in sync with histograms.xml. Do not reorder
246 // the members; always add to the end.
248 FEATURE_LEVEL_UNKNOWN
,
249 FEATURE_LEVEL_NO_D3D11_DLL
,
250 FEATURE_LEVEL_NO_CREATE_DEVICE_ENTRY_POINT
,
251 FEATURE_LEVEL_DEVICE_CREATION_FAILED
,
261 FeatureLevel feature_level
= FEATURE_LEVEL_UNKNOWN
;
262 UINT bgra_support
= 0;
264 // This module is leaked in case it is hooked by third party software.
265 base::NativeLibrary d3d11_module
= base::LoadNativeLibrary(
266 base::FilePath(L
"d3d11.dll"),
270 feature_level
= FEATURE_LEVEL_NO_D3D11_DLL
;
272 D3D11CreateDeviceFunc create_func
=
273 reinterpret_cast<D3D11CreateDeviceFunc
>(
274 base::GetFunctionPointerFromNativeLibrary(d3d11_module
,
275 "D3D11CreateDevice"));
277 feature_level
= FEATURE_LEVEL_NO_CREATE_DEVICE_ENTRY_POINT
;
279 static const D3D_FEATURE_LEVEL d3d_feature_levels
[] = {
280 D3D_FEATURE_LEVEL_11_0
,
281 D3D_FEATURE_LEVEL_10_1
,
282 D3D_FEATURE_LEVEL_10_0
,
283 D3D_FEATURE_LEVEL_9_3
,
284 D3D_FEATURE_LEVEL_9_2
,
285 D3D_FEATURE_LEVEL_9_1
288 base::win::ScopedComPtr
<ID3D11Device
> device
;
289 D3D_FEATURE_LEVEL d3d_feature_level
;
290 base::win::ScopedComPtr
<ID3D11DeviceContext
> device_context
;
291 HRESULT hr
= create_func(NULL
,
292 D3D_DRIVER_TYPE_HARDWARE
,
296 arraysize(d3d_feature_levels
),
300 device_context
.Receive());
302 feature_level
= FEATURE_LEVEL_DEVICE_CREATION_FAILED
;
304 switch (d3d_feature_level
) {
305 case D3D_FEATURE_LEVEL_11_0
:
306 feature_level
= FEATURE_LEVEL_11_0
;
308 case D3D_FEATURE_LEVEL_10_1
:
309 feature_level
= FEATURE_LEVEL_10_1
;
311 case D3D_FEATURE_LEVEL_10_0
:
312 feature_level
= FEATURE_LEVEL_10_0
;
314 case D3D_FEATURE_LEVEL_9_3
:
315 feature_level
= FEATURE_LEVEL_9_3
;
317 case D3D_FEATURE_LEVEL_9_2
:
318 feature_level
= FEATURE_LEVEL_9_2
;
320 case D3D_FEATURE_LEVEL_9_1
:
321 feature_level
= FEATURE_LEVEL_9_1
;
328 hr
= device
->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM
,
330 DCHECK(SUCCEEDED(hr
));
335 UMA_HISTOGRAM_ENUMERATION("GPU.D3D11_FeatureLevel",
339 // ANGLE requires at least feature level 10.0. Do not record any further
340 // stats if ANGLE would not work anyway.
341 if (feature_level
< FEATURE_LEVEL_10_0
)
344 UMA_HISTOGRAM_BOOLEAN(
345 "GPU.D3D11_B8G8R8A8_Texture2DSupport",
346 (bgra_support
& D3D11_FORMAT_SUPPORT_TEXTURE2D
) != 0);
347 UMA_HISTOGRAM_BOOLEAN(
348 "GPU.D3D11_B8G8R8A8_RenderTargetSupport",
349 (bgra_support
& D3D11_FORMAT_SUPPORT_RENDER_TARGET
) != 0);
352 // Collects information about the level of D3D11 support and records it in
353 // the UMA stats. Records no stats when D3D11 in not supported at all.
354 void CollectD3D11Support() {
355 // D3D11 takes about 50ms to initialize so do this on a worker thread.
356 base::WorkerPool::PostTask(
358 base::Bind(CollectD3D11SupportOnWorkerThread
),
361 } // namespace anonymous
363 #if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD)
364 // This function has a real implementation for official builds that can
365 // be found in src/third_party/amd.
366 void GetAMDVideocardInfo(GPUInfo
* gpu_info
);
368 void GetAMDVideocardInfo(GPUInfo
* gpu_info
) {
374 CollectInfoResult
CollectDriverInfoD3D(const std::wstring
& device_id
,
376 TRACE_EVENT0("gpu", "CollectDriverInfoD3D");
378 // create device info for the display device
379 HDEVINFO device_info
= SetupDiGetClassDevsW(
380 NULL
, device_id
.c_str(), NULL
,
381 DIGCF_PRESENT
| DIGCF_PROFILE
| DIGCF_ALLCLASSES
);
382 if (device_info
== INVALID_HANDLE_VALUE
) {
383 LOG(ERROR
) << "Creating device info failed";
384 return kCollectInfoNonFatalFailure
;
389 SP_DEVINFO_DATA device_info_data
;
390 device_info_data
.cbSize
= sizeof(device_info_data
);
391 while (SetupDiEnumDeviceInfo(device_info
, index
++, &device_info_data
)) {
393 if (SetupDiGetDeviceRegistryPropertyW(device_info
,
397 reinterpret_cast<PBYTE
>(value
),
401 std::wstring driver_key
= L
"System\\CurrentControlSet\\Control\\Class\\";
403 LONG result
= RegOpenKeyExW(
404 HKEY_LOCAL_MACHINE
, driver_key
.c_str(), 0, KEY_QUERY_VALUE
, &key
);
405 if (result
== ERROR_SUCCESS
) {
406 DWORD dwcb_data
= sizeof(value
);
407 std::string driver_version
;
408 result
= RegQueryValueExW(
409 key
, L
"DriverVersion", NULL
, NULL
,
410 reinterpret_cast<LPBYTE
>(value
), &dwcb_data
);
411 if (result
== ERROR_SUCCESS
)
412 driver_version
= base::UTF16ToASCII(std::wstring(value
));
414 std::string driver_date
;
415 dwcb_data
= sizeof(value
);
416 result
= RegQueryValueExW(
417 key
, L
"DriverDate", NULL
, NULL
,
418 reinterpret_cast<LPBYTE
>(value
), &dwcb_data
);
419 if (result
== ERROR_SUCCESS
)
420 driver_date
= base::UTF16ToASCII(std::wstring(value
));
422 std::string driver_vendor
;
423 dwcb_data
= sizeof(value
);
424 result
= RegQueryValueExW(
425 key
, L
"ProviderName", NULL
, NULL
,
426 reinterpret_cast<LPBYTE
>(value
), &dwcb_data
);
427 if (result
== ERROR_SUCCESS
) {
428 driver_vendor
= base::UTF16ToASCII(std::wstring(value
));
429 if (driver_vendor
== "Advanced Micro Devices, Inc." ||
430 driver_vendor
== "ATI Technologies Inc.") {
431 // We are conservative and assume that in the absence of a clear
432 // signal the videocard is assumed to be switchable. Additionally,
433 // some switchable systems with Intel GPUs aren't correctly
434 // detected, so always count them.
435 GetAMDVideocardInfo(gpu_info
);
436 if (!gpu_info
->amd_switchable
&&
437 gpu_info
->gpu
.vendor_id
== 0x8086) {
438 gpu_info
->amd_switchable
= true;
439 gpu_info
->secondary_gpus
.push_back(gpu_info
->gpu
);
440 gpu_info
->gpu
.vendor_id
= 0x1002;
441 gpu_info
->gpu
.device_id
= 0; // Unknown discrete AMD GPU.
446 gpu_info
->driver_vendor
= driver_vendor
;
447 gpu_info
->driver_version
= driver_version
;
448 gpu_info
->driver_date
= driver_date
;
455 SetupDiDestroyDeviceInfoList(device_info
);
456 return found
? kCollectInfoSuccess
: kCollectInfoNonFatalFailure
;
459 CollectInfoResult
CollectContextGraphicsInfo(GPUInfo
* gpu_info
) {
460 TRACE_EVENT0("gpu", "CollectGraphicsInfo");
464 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL
)) {
465 std::string requested_implementation_name
=
466 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL
);
467 if (requested_implementation_name
== "swiftshader") {
468 gpu_info
->software_rendering
= true;
469 gpu_info
->context_info_state
= kCollectInfoNonFatalFailure
;
470 return kCollectInfoNonFatalFailure
;
474 CollectInfoResult result
= CollectGraphicsInfoGL(gpu_info
);
475 if (result
!= kCollectInfoSuccess
) {
476 gpu_info
->context_info_state
= result
;
480 // ANGLE's renderer strings are of the form:
481 // ANGLE (<adapter_identifier> Direct3D<version> vs_x_x ps_x_x)
482 std::string direct3d_version
;
483 int vertex_shader_major_version
= 0;
484 int vertex_shader_minor_version
= 0;
485 int pixel_shader_major_version
= 0;
486 int pixel_shader_minor_version
= 0;
487 gpu_info
->adapter_luid
= 0;
488 if (RE2::FullMatch(gpu_info
->gl_renderer
,
490 RE2::PartialMatch(gpu_info
->gl_renderer
,
492 &direct3d_version
) &&
493 RE2::PartialMatch(gpu_info
->gl_renderer
,
495 &vertex_shader_major_version
,
496 &vertex_shader_minor_version
) &&
497 RE2::PartialMatch(gpu_info
->gl_renderer
,
499 &pixel_shader_major_version
,
500 &pixel_shader_minor_version
)) {
501 gpu_info
->can_lose_context
= direct3d_version
== "9";
502 gpu_info
->vertex_shader_version
=
503 base::StringPrintf("%d.%d",
504 vertex_shader_major_version
,
505 vertex_shader_minor_version
);
506 gpu_info
->pixel_shader_version
=
507 base::StringPrintf("%d.%d",
508 pixel_shader_major_version
,
509 pixel_shader_minor_version
);
511 // ANGLE's EGL vendor strings are of the form:
512 // Google, Inc. (adapter LUID: 0123456789ABCDEF)
513 // The LUID is optional and identifies the GPU adapter ANGLE is using.
514 const char* egl_vendor
= eglQueryString(
515 gfx::GLSurfaceEGL::GetHardwareDisplay(),
517 RE2::PartialMatch(egl_vendor
,
518 " \\(adapter LUID: ([0-9A-Fa-f]{16})\\)",
519 RE2::Hex(&gpu_info
->adapter_luid
));
521 // DirectX diagnostics are collected asynchronously because it takes a
522 // couple of seconds.
524 gpu_info
->dx_diagnostics_info_state
= kCollectInfoNonFatalFailure
;
527 gpu_info
->context_info_state
= kCollectInfoSuccess
;
528 return kCollectInfoSuccess
;
531 CollectInfoResult
CollectGpuID(uint32
* vendor_id
, uint32
* device_id
) {
532 DCHECK(vendor_id
&& device_id
);
536 // Taken from http://developer.nvidia.com/object/device_ids.html
538 dd
.cb
= sizeof(DISPLAY_DEVICE
);
540 for (int i
= 0; EnumDisplayDevices(NULL
, i
, &dd
, 0); ++i
) {
541 if (dd
.StateFlags
& DISPLAY_DEVICE_PRIMARY_DEVICE
) {
547 if (id
.length() > 20) {
548 int vendor
= 0, device
= 0;
549 std::wstring vendor_string
= id
.substr(8, 4);
550 std::wstring device_string
= id
.substr(17, 4);
551 base::HexStringToInt(base::UTF16ToASCII(vendor_string
), &vendor
);
552 base::HexStringToInt(base::UTF16ToASCII(device_string
), &device
);
555 if (*vendor_id
!= 0 && *device_id
!= 0)
556 return kCollectInfoSuccess
;
558 return kCollectInfoNonFatalFailure
;
561 CollectInfoResult
CollectBasicGraphicsInfo(GPUInfo
* gpu_info
) {
562 TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo");
566 gpu_info
->performance_stats
= RetrieveGpuPerformanceStatsWithHistograms();
568 // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
569 HMODULE nvd3d9wrap
= GetModuleHandleW(L
"nvd3d9wrap.dll");
570 gpu_info
->optimus
= nvd3d9wrap
!= NULL
;
572 gpu_info
->lenovo_dcute
= IsLenovoDCuteInstalled();
574 gpu_info
->display_link_version
= DisplayLinkVersion();
576 if (!gpu_info
->display_link_version
.IsValid()) {
577 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
578 DISPLAY_LINK_NOT_INSTALLED
,
579 DISPLAY_LINK_INSTALLATION_STATUS_MAX
);
580 } else if (gpu_info
->display_link_version
.IsOlderThan("7.2")) {
581 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
582 DISPLAY_LINK_7_1_OR_EARLIER
,
583 DISPLAY_LINK_INSTALLATION_STATUS_MAX
);
585 UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
586 DISPLAY_LINK_7_2_OR_LATER
,
587 DISPLAY_LINK_INSTALLATION_STATUS_MAX
);
590 // Taken from http://developer.nvidia.com/object/device_ids.html
592 dd
.cb
= sizeof(DISPLAY_DEVICE
);
594 for (int i
= 0; EnumDisplayDevices(NULL
, i
, &dd
, 0); ++i
) {
595 if (dd
.StateFlags
& DISPLAY_DEVICE_PRIMARY_DEVICE
) {
601 if (id
.length() <= 20) {
602 gpu_info
->basic_info_state
= kCollectInfoNonFatalFailure
;
603 return kCollectInfoNonFatalFailure
;
606 int vendor_id
= 0, device_id
= 0;
607 base::string16 vendor_id_string
= id
.substr(8, 4);
608 base::string16 device_id_string
= id
.substr(17, 4);
609 base::HexStringToInt(base::UTF16ToASCII(vendor_id_string
), &vendor_id
);
610 base::HexStringToInt(base::UTF16ToASCII(device_id_string
), &device_id
);
611 gpu_info
->gpu
.vendor_id
= vendor_id
;
612 gpu_info
->gpu
.device_id
= device_id
;
613 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE.
614 if (!CollectDriverInfoD3D(id
, gpu_info
)) {
615 gpu_info
->basic_info_state
= kCollectInfoNonFatalFailure
;
616 return kCollectInfoNonFatalFailure
;
619 // Collect basic information about supported D3D11 features. Delay for 45
620 // seconds so as not to regress performance tests.
621 if (D3D11ShouldWork(*gpu_info
)) {
622 // This is on a field trial so we can turn it off easily if it blows up
623 // again in stable channel.
624 scoped_refptr
<base::FieldTrial
> trial(
625 base::FieldTrialList::FactoryGetFieldTrial(
626 "D3D11Experiment", 100, "Disabled", 2015, 7, 8,
627 base::FieldTrial::SESSION_RANDOMIZED
, NULL
));
628 const int enabled_group
=
629 trial
->AppendGroup("Enabled", 0);
631 if (trial
->group() == enabled_group
) {
632 base::MessageLoop::current()->PostDelayedTask(
634 base::Bind(&CollectD3D11Support
),
635 base::TimeDelta::FromSeconds(45));
639 gpu_info
->basic_info_state
= kCollectInfoSuccess
;
640 return kCollectInfoSuccess
;
643 CollectInfoResult
CollectDriverInfoGL(GPUInfo
* gpu_info
) {
644 TRACE_EVENT0("gpu", "CollectDriverInfoGL");
646 if (!gpu_info
->driver_version
.empty())
647 return kCollectInfoSuccess
;
649 bool parsed
= RE2::PartialMatch(
650 gpu_info
->gl_version
, "([\\d\\.]+)$", &gpu_info
->driver_version
);
651 return parsed
? kCollectInfoSuccess
: kCollectInfoNonFatalFailure
;
654 void MergeGPUInfo(GPUInfo
* basic_gpu_info
,
655 const GPUInfo
& context_gpu_info
) {
656 DCHECK(basic_gpu_info
);
658 if (context_gpu_info
.software_rendering
) {
659 basic_gpu_info
->software_rendering
= true;
663 MergeGPUInfoGL(basic_gpu_info
, context_gpu_info
);
665 basic_gpu_info
->dx_diagnostics
= context_gpu_info
.dx_diagnostics
;