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 // C system before C++ system.
8 #include <stddef.h>
9 #include <stdint.h>
10
11 // This has to be included before windows.h.
12 #include "third_party/re2/src/re2/re2.h"
13
14 #include <windows.h>
15
16 #include <d3d11.h>
17 #include <d3d11_3.h>
18 #include <d3d12.h>
19 #include <dxgi.h>
20 #include <wrl/client.h>
21
22 #include "base/file_version_info_win.h"
23 #include "base/files/file_path.h"
24 #include "base/files/file_util.h"
25 #include "base/logging.h"
26 #include "base/metrics/histogram_functions.h"
27 #include "base/metrics/histogram_macros.h"
28 #include "base/numerics/safe_conversions.h"
29 #include "base/scoped_native_library.h"
30 #include "base/strings/stringprintf.h"
31 #include "base/trace_event/trace_event.h"
32 #include "base/win/scoped_com_initializer.h"
33 #include "base/win/windows_version.h"
34 #include "build/branding_buildflags.h"
35 #include "gpu/config/gpu_util.h"
36 #include "third_party/vulkan/include/vulkan/vulkan.h"
37 #include "ui/gl/direct_composition_surface_win.h"
38
39 namespace gpu {
40
41 namespace {
42
43 // These values are persisted to logs. Entries should not be renumbered and
44 // numeric values should never be reused.
45 // This should match enum D3D12FeatureLevel in
46 // \tools\metrics\histograms\enums.xml
47 enum class D3D12FeatureLevel {
48 kD3DFeatureLevelUnknown = 0,
49 kD3DFeatureLevel_12_0 = 1,
50 kD3DFeatureLevel_12_1 = 2,
51 kD3DFeatureLevel_11_0 = 3,
52 kD3DFeatureLevel_11_1 = 4,
53 kMaxValue = kD3DFeatureLevel_11_1,
54 };
55
ConvertToHistogramFeatureLevel(uint32_t d3d_feature_level)56 inline D3D12FeatureLevel ConvertToHistogramFeatureLevel(
57 uint32_t d3d_feature_level) {
58 switch (d3d_feature_level) {
59 case 0:
60 return D3D12FeatureLevel::kD3DFeatureLevelUnknown;
61 case D3D_FEATURE_LEVEL_12_0:
62 return D3D12FeatureLevel::kD3DFeatureLevel_12_0;
63 case D3D_FEATURE_LEVEL_12_1:
64 return D3D12FeatureLevel::kD3DFeatureLevel_12_1;
65 case D3D_FEATURE_LEVEL_11_0:
66 return D3D12FeatureLevel::kD3DFeatureLevel_11_0;
67 case D3D_FEATURE_LEVEL_11_1:
68 return D3D12FeatureLevel::kD3DFeatureLevel_11_1;
69 default:
70 NOTREACHED();
71 return D3D12FeatureLevel::kD3DFeatureLevelUnknown;
72 }
73 }
74
FlagsToOverlaySupport(UINT flags)75 OverlaySupport FlagsToOverlaySupport(UINT flags) {
76 if (flags & DXGI_OVERLAY_SUPPORT_FLAG_SCALING)
77 return OverlaySupport::kScaling;
78 if (flags & DXGI_OVERLAY_SUPPORT_FLAG_DIRECT)
79 return OverlaySupport::kDirect;
80 return OverlaySupport::kNone;
81 }
82
83 } // namespace
84
85 #if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OFFICIAL_BUILD)
86 // This function has a real implementation for official builds that can
87 // be found in src/third_party/amd.
88 bool GetAMDSwitchableInfo(bool* is_switchable,
89 uint32_t* active_vendor_id,
90 uint32_t* active_device_id);
91 #else
GetAMDSwitchableInfo(bool * is_switchable,uint32_t * active_vendor_id,uint32_t * active_device_id)92 bool GetAMDSwitchableInfo(bool* is_switchable,
93 uint32_t* active_vendor_id,
94 uint32_t* active_device_id) {
95 return false;
96 }
97 #endif
98
99 // This has to be called after a context is created, active GPU is identified,
100 // and GPU driver bug workarounds are computed again. Otherwise the workaround
101 // |disable_direct_composition| may not be correctly applied.
102 // Also, this has to be called after falling back to SwiftShader decision is
103 // finalized because this function depends on GL is ANGLE's GLES or not.
CollectHardwareOverlayInfo(OverlayInfo * overlay_info)104 void CollectHardwareOverlayInfo(OverlayInfo* overlay_info) {
105 if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE) {
106 overlay_info->direct_composition =
107 gl::DirectCompositionSurfaceWin::IsDirectCompositionSupported();
108 overlay_info->supports_overlays =
109 gl::DirectCompositionSurfaceWin::AreOverlaysSupported();
110 overlay_info->nv12_overlay_support = FlagsToOverlaySupport(
111 gl::DirectCompositionSurfaceWin::GetOverlaySupportFlags(
112 DXGI_FORMAT_NV12));
113 overlay_info->yuy2_overlay_support = FlagsToOverlaySupport(
114 gl::DirectCompositionSurfaceWin::GetOverlaySupportFlags(
115 DXGI_FORMAT_YUY2));
116 }
117 }
118
CollectDriverInfoD3D(GPUInfo * gpu_info)119 bool CollectDriverInfoD3D(GPUInfo* gpu_info) {
120 TRACE_EVENT0("gpu", "CollectDriverInfoD3D");
121
122 Microsoft::WRL::ComPtr<IDXGIFactory> dxgi_factory;
123 HRESULT hr = ::CreateDXGIFactory(IID_PPV_ARGS(&dxgi_factory));
124 if (FAILED(hr))
125 return false;
126
127 bool found_amd = false;
128 bool found_intel = false;
129 bool found_nvidia = false;
130
131 UINT i;
132 Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
133 for (i = 0; SUCCEEDED(dxgi_factory->EnumAdapters(i, &dxgi_adapter)); i++) {
134 DXGI_ADAPTER_DESC desc;
135 dxgi_adapter->GetDesc(&desc);
136
137 GPUInfo::GPUDevice device;
138 device.vendor_id = desc.VendorId;
139 device.device_id = desc.DeviceId;
140 device.sub_sys_id = desc.SubSysId;
141 device.revision = desc.Revision;
142
143 LARGE_INTEGER umd_version;
144 hr = dxgi_adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice),
145 &umd_version);
146 if (SUCCEEDED(hr)) {
147 device.driver_version = base::StringPrintf(
148 "%d.%d.%d.%d", HIWORD(umd_version.HighPart),
149 LOWORD(umd_version.HighPart), HIWORD(umd_version.LowPart),
150 LOWORD(umd_version.LowPart));
151 } else {
152 DLOG(ERROR) << "Unable to retrieve the umd version of adapter: "
153 << desc.Description << " HR: " << std::hex << hr;
154 }
155 switch (device.vendor_id) {
156 case 0x8086:
157 found_intel = true;
158 break;
159 case 0x1002:
160 found_amd = true;
161 break;
162 case 0x10de:
163 found_nvidia = true;
164 break;
165 default:
166 break;
167 }
168
169 if (i == 0) {
170 gpu_info->gpu = device;
171 } else {
172 gpu_info->secondary_gpus.push_back(device);
173 }
174 }
175
176 if (found_intel && base::win::GetVersion() < base::win::Version::WIN10) {
177 // Since Windows 10 (and Windows 8.1 on some systems), switchable graphics
178 // platforms are managed by Windows and each adapter is accessible as
179 // separate devices.
180 // See https://msdn.microsoft.com/en-us/windows/dn265501(v=vs.80)
181 if (found_amd) {
182 bool is_amd_switchable = false;
183 uint32_t active_vendor = 0, active_device = 0;
184 GetAMDSwitchableInfo(&is_amd_switchable, &active_vendor, &active_device);
185 gpu_info->amd_switchable = is_amd_switchable;
186 } else if (found_nvidia) {
187 // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
188 HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
189 gpu_info->optimus = nvd3d9wrap != nullptr;
190 }
191 }
192
193 return i > 0;
194 }
195
196 // DirectX 12 are included with Windows 10 and Server 2016.
GetGpuSupportedD3D12Version(Dx12VulkanVersionInfo * info)197 void GetGpuSupportedD3D12Version(Dx12VulkanVersionInfo* info) {
198 TRACE_EVENT0("gpu", "GetGpuSupportedD3D12Version");
199 info->supports_dx12 = false;
200 info->d3d12_feature_level = 0;
201
202 base::ScopedNativeLibrary d3d12_library(
203 base::FilePath(FILE_PATH_LITERAL("d3d12.dll")));
204 if (!d3d12_library.is_valid())
205 return;
206
207 // The order of feature levels to attempt to create in D3D CreateDevice
208 const D3D_FEATURE_LEVEL feature_levels[] = {
209 D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1,
210 D3D_FEATURE_LEVEL_11_0};
211
212 PFN_D3D12_CREATE_DEVICE D3D12CreateDevice =
213 reinterpret_cast<PFN_D3D12_CREATE_DEVICE>(
214 d3d12_library.GetFunctionPointer("D3D12CreateDevice"));
215 if (D3D12CreateDevice) {
216 // For the default adapter only. (*pAdapter == nullptr)
217 // Check to see if the adapter supports Direct3D 12, but don't create the
218 // actual device yet. (**ppDevice == nullptr)
219 for (auto level : feature_levels) {
220 if (SUCCEEDED(D3D12CreateDevice(nullptr, level, _uuidof(ID3D12Device),
221 nullptr))) {
222 info->d3d12_feature_level = level;
223 info->supports_dx12 = (level >= D3D_FEATURE_LEVEL_12_0) ? true : false;
224 break;
225 }
226 }
227 }
228 }
229
BadAMDVulkanDriverVersion()230 bool BadAMDVulkanDriverVersion() {
231 // Both 32-bit and 64-bit dll are broken. If 64-bit doesn't exist,
232 // 32-bit dll will be used to detect the AMD Vulkan driver.
233 const base::FilePath kAmdDriver64(FILE_PATH_LITERAL("amdvlk64.dll"));
234 const base::FilePath kAmdDriver32(FILE_PATH_LITERAL("amdvlk32.dll"));
235 std::unique_ptr<FileVersionInfoWin> file_version_info =
236 FileVersionInfoWin::CreateFileVersionInfoWin(kAmdDriver64);
237 if (!file_version_info) {
238 file_version_info =
239 FileVersionInfoWin::CreateFileVersionInfoWin(kAmdDriver32);
240 if (!file_version_info)
241 return false;
242 }
243
244 // From the Canary crash logs, the broken amdvlk64.dll versions
245 // are 1.0.39.0, 1.0.51.0 and 1.0.54.0. In the manual test, version
246 // 9.2.10.1 dated 12/6/2017 works and version 1.0.54.0 dated 11/2/1017
247 // crashes. All version numbers small than 1.0.54.0 will be marked as
248 // broken.
249 const base::Version kBadAMDVulkanDriverVersion("1.0.54.0");
250 return file_version_info->GetFileVersion() <= kBadAMDVulkanDriverVersion;
251 }
252
BadVulkanDllVersion()253 bool BadVulkanDllVersion() {
254 std::unique_ptr<FileVersionInfoWin> file_version_info =
255 FileVersionInfoWin::CreateFileVersionInfoWin(
256 base::FilePath(FILE_PATH_LITERAL("vulkan-1.dll")));
257 if (!file_version_info)
258 return false;
259
260 // From the logs, most vulkan-1.dll crashs are from the following versions.
261 // As of 7/23/2018.
262 // 0.0.0.0 - # of crashes: 6556
263 // 1.0.26.0 - # of crashes: 5890
264 // 1.0.33.0 - # of crashes: 12271
265 // 1.0.42.0 - # of crashes: 35749
266 // 1.0.42.1 - # of crashes: 68214
267 // 1.0.51.0 - # of crashes: 5152
268 // The GPU could be from any vendor, but only some certain models would crash.
269 // For those that don't crash, they usually return failures upon GPU vulkan
270 // support querying even though the GPU drivers can support it.
271 base::Version fv = file_version_info->GetFileVersion();
272 const char* const kBadVulkanDllVersion[] = {
273 "0.0.0.0", "1.0.26.0", "1.0.33.0", "1.0.42.0", "1.0.42.1", "1.0.51.0"};
274 for (const char* bad_version : kBadVulkanDllVersion) {
275 if (fv == base::Version(bad_version))
276 return true;
277 }
278 return false;
279 }
280
InitVulkan(base::NativeLibrary * vulkan_library,PFN_vkGetInstanceProcAddr * vkGetInstanceProcAddr,PFN_vkCreateInstance * vkCreateInstance)281 bool InitVulkan(base::NativeLibrary* vulkan_library,
282 PFN_vkGetInstanceProcAddr* vkGetInstanceProcAddr,
283 PFN_vkCreateInstance* vkCreateInstance) {
284 *vulkan_library =
285 base::LoadNativeLibrary(base::FilePath(L"vulkan-1.dll"), nullptr);
286
287 if (!(*vulkan_library)) {
288 return false;
289 }
290
291 *vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
292 GetProcAddress(*vulkan_library, "vkGetInstanceProcAddr"));
293
294 if (*vkGetInstanceProcAddr) {
295 *vkCreateInstance = reinterpret_cast<PFN_vkCreateInstance>(
296 (*vkGetInstanceProcAddr)(nullptr, "vkCreateInstance"));
297 if (*vkCreateInstance) {
298 return true;
299 }
300 }
301
302 // From the crash reports, unloading the library here might cause a crash in
303 // the Vulkan loader or in the Vulkan driver. To work around it, don't
304 // explicitly unload the DLL. Instead, GPU process shutdown will unload all
305 // loaded DLLs.
306 // base::UnloadNativeLibrary(*vulkan_library);
307 return false;
308 }
309
InitVulkanInstanceProc(const VkInstance & vk_instance,const PFN_vkGetInstanceProcAddr & vkGetInstanceProcAddr,PFN_vkEnumeratePhysicalDevices * vkEnumeratePhysicalDevices,PFN_vkEnumerateDeviceExtensionProperties * vkEnumerateDeviceExtensionProperties)310 bool InitVulkanInstanceProc(
311 const VkInstance& vk_instance,
312 const PFN_vkGetInstanceProcAddr& vkGetInstanceProcAddr,
313 PFN_vkEnumeratePhysicalDevices* vkEnumeratePhysicalDevices,
314 PFN_vkEnumerateDeviceExtensionProperties*
315 vkEnumerateDeviceExtensionProperties) {
316
317 *vkEnumeratePhysicalDevices =
318 reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(
319 vkGetInstanceProcAddr(vk_instance, "vkEnumeratePhysicalDevices"));
320
321 *vkEnumerateDeviceExtensionProperties =
322 reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
323 vkGetInstanceProcAddr(vk_instance,
324 "vkEnumerateDeviceExtensionProperties"));
325
326 if ((*vkEnumeratePhysicalDevices) &&
327 (*vkEnumerateDeviceExtensionProperties)) {
328 return true;
329 }
330 return false;
331 }
332
GetGpuSupportedVulkanVersionAndExtensions(Dx12VulkanVersionInfo * info,const std::vector<const char * > & requested_vulkan_extensions,std::vector<bool> * extension_support)333 void GetGpuSupportedVulkanVersionAndExtensions(
334 Dx12VulkanVersionInfo* info,
335 const std::vector<const char*>& requested_vulkan_extensions,
336 std::vector<bool>* extension_support) {
337 TRACE_EVENT0("gpu", "GetGpuSupportedVulkanVersionAndExtensions");
338
339 base::NativeLibrary vulkan_library;
340 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
341 PFN_vkCreateInstance vkCreateInstance;
342 PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
343 PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
344 VkInstance vk_instance = VK_NULL_HANDLE;
345 uint32_t physical_device_count = 0;
346 info->supports_vulkan = false;
347 info->vulkan_version = 0;
348
349 // Skip if the system has an older AMD Vulkan driver amdvlk64.dll or
350 // amdvlk32.dll which crashes when vkCreateInstance() is called. This bug has
351 // been fixed in the latest AMD driver.
352 if (BadAMDVulkanDriverVersion()) {
353 return;
354 }
355
356 // Some early versions of vulkan-1.dll might crash
357 if (BadVulkanDllVersion()) {
358 return;
359 }
360
361 if (!InitVulkan(&vulkan_library, &vkGetInstanceProcAddr, &vkCreateInstance)) {
362 return;
363 }
364
365 VkApplicationInfo app_info = {};
366 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
367
368 VkInstanceCreateInfo create_info = {};
369 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
370 create_info.pApplicationInfo = &app_info;
371
372 // Get the Vulkan API version supported in the GPU driver
373 for (int minor_version = 2; minor_version >= 0; --minor_version) {
374 app_info.apiVersion = VK_MAKE_VERSION(1, minor_version, 0);
375 VkResult result = vkCreateInstance(&create_info, nullptr, &vk_instance);
376 if (result == VK_SUCCESS && vk_instance &&
377 InitVulkanInstanceProc(vk_instance, vkGetInstanceProcAddr,
378 &vkEnumeratePhysicalDevices,
379 &vkEnumerateDeviceExtensionProperties)) {
380 result = vkEnumeratePhysicalDevices(vk_instance, &physical_device_count,
381 nullptr);
382 if (result == VK_SUCCESS && physical_device_count > 0) {
383 info->supports_vulkan = true;
384 info->vulkan_version = app_info.apiVersion;
385 break;
386 } else {
387 // Skip destroy here. GPU process shutdown will unload all loaded DLLs.
388 // vkDestroyInstance(vk_instance, nullptr);
389 vk_instance = VK_NULL_HANDLE;
390 }
391 }
392 }
393
394 // Check whether the requested_vulkan_extensions are supported
395 if (info->supports_vulkan) {
396 std::vector<VkPhysicalDevice> physical_devices(physical_device_count);
397 vkEnumeratePhysicalDevices(vk_instance, &physical_device_count,
398 physical_devices.data());
399
400 // physical_devices[0]: Only query the default device for now
401 uint32_t property_count;
402 vkEnumerateDeviceExtensionProperties(physical_devices[0], nullptr,
403 &property_count, nullptr);
404
405 std::vector<VkExtensionProperties> extension_properties(property_count);
406 if (property_count > 0) {
407 vkEnumerateDeviceExtensionProperties(physical_devices[0], nullptr,
408 &property_count,
409 extension_properties.data());
410 }
411
412 for (size_t i = 0; i < requested_vulkan_extensions.size(); ++i) {
413 for (size_t p = 0; p < property_count; ++p) {
414 if (strcmp(requested_vulkan_extensions[i],
415 extension_properties[p].extensionName) == 0) {
416 (*extension_support)[i] = true;
417 break;
418 }
419 }
420 }
421 }
422
423 // From the crash reports, calling the following two functions might cause a
424 // crash in the Vulkan loader or in the Vulkan driver. To work around it,
425 // don't explicitly unload the DLL. Instead, GPU process shutdown will unload
426 // all loaded DLLs.
427 // if (vk_instance) {
428 // vkDestroyInstance(vk_instance, nullptr);
429 // }
430 // base::UnloadNativeLibrary(vulkan_library);
431 }
432
RecordGpuSupportedRuntimeVersionHistograms(Dx12VulkanVersionInfo * info)433 void RecordGpuSupportedRuntimeVersionHistograms(Dx12VulkanVersionInfo* info) {
434 // D3D
435 GetGpuSupportedD3D12Version(info);
436 UMA_HISTOGRAM_BOOLEAN("GPU.SupportsDX12", info->supports_dx12);
437 UMA_HISTOGRAM_ENUMERATION(
438 "GPU.D3D12FeatureLevel",
439 ConvertToHistogramFeatureLevel(info->d3d12_feature_level));
440
441 // Vulkan
442 const std::vector<const char*> vulkan_extensions = {
443 "VK_KHR_external_memory_win32", "VK_KHR_external_semaphore_win32",
444 "VK_KHR_win32_keyed_mutex"};
445 std::vector<bool> extension_support(vulkan_extensions.size(), false);
446 GetGpuSupportedVulkanVersionAndExtensions(info, vulkan_extensions,
447 &extension_support);
448
449 UMA_HISTOGRAM_BOOLEAN("GPU.SupportsVulkan", info->supports_vulkan);
450 UMA_HISTOGRAM_ENUMERATION(
451 "GPU.VulkanVersion",
452 ConvertToHistogramVulkanVersion(info->vulkan_version));
453
454 for (size_t i = 0; i < vulkan_extensions.size(); ++i) {
455 std::string name = "GPU.VulkanExtSupport.";
456 name.append(vulkan_extensions[i]);
457 base::UmaHistogramBoolean(name, extension_support[i]);
458 }
459 }
460
CollectD3D11FeatureInfo(D3D_FEATURE_LEVEL * d3d11_feature_level,bool * has_discrete_gpu)461 bool CollectD3D11FeatureInfo(D3D_FEATURE_LEVEL* d3d11_feature_level,
462 bool* has_discrete_gpu) {
463 Microsoft::WRL::ComPtr<IDXGIFactory> dxgi_factory;
464 if (FAILED(::CreateDXGIFactory(IID_PPV_ARGS(&dxgi_factory))))
465 return false;
466
467 base::ScopedNativeLibrary d3d11_library(
468 base::FilePath(FILE_PATH_LITERAL("d3d11.dll")));
469 if (!d3d11_library.is_valid())
470 return false;
471 PFN_D3D11_CREATE_DEVICE D3D11CreateDevice =
472 reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
473 d3d11_library.GetFunctionPointer("D3D11CreateDevice"));
474 if (!D3D11CreateDevice)
475 return false;
476
477 // The order of feature levels to attempt to create in D3D CreateDevice
478 const D3D_FEATURE_LEVEL kFeatureLevels[] = {
479 D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1,
480 D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0,
481 D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1};
482
483 bool detected_discrete_gpu = false;
484 D3D_FEATURE_LEVEL max_level = D3D_FEATURE_LEVEL_1_0_CORE;
485 Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
486 for (UINT ii = 0; SUCCEEDED(dxgi_factory->EnumAdapters(ii, &dxgi_adapter));
487 ++ii) {
488 DXGI_ADAPTER_DESC desc;
489 if (SUCCEEDED(dxgi_adapter->GetDesc(&desc)) && desc.VendorId == 0x1414) {
490 // Bypass Microsoft software renderer.
491 continue;
492 }
493 Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device;
494 D3D_FEATURE_LEVEL returned_feature_level = D3D_FEATURE_LEVEL_1_0_CORE;
495 if (FAILED(D3D11CreateDevice(dxgi_adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN,
496 /*Software=*/0,
497 /*Flags=*/0, kFeatureLevels,
498 _countof(kFeatureLevels), D3D11_SDK_VERSION,
499 &d3d11_device, &returned_feature_level,
500 /*ppImmediateContext=*/nullptr))) {
501 continue;
502 }
503 if (returned_feature_level > max_level)
504 max_level = returned_feature_level;
505 Microsoft::WRL::ComPtr<ID3D11Device3> d3d11_device_3;
506 if (FAILED(d3d11_device.As(&d3d11_device_3)))
507 continue;
508 D3D11_FEATURE_DATA_D3D11_OPTIONS2 data = {};
509 if (FAILED(d3d11_device_3->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS2,
510 &data, sizeof(data)))) {
511 continue;
512 }
513 if (!data.UnifiedMemoryArchitecture)
514 detected_discrete_gpu = true;
515 }
516
517 if (max_level > D3D_FEATURE_LEVEL_1_0_CORE) {
518 *d3d11_feature_level = max_level;
519 *has_discrete_gpu = detected_discrete_gpu;
520 return true;
521 }
522 return false;
523 }
524
CollectContextGraphicsInfo(GPUInfo * gpu_info)525 bool CollectContextGraphicsInfo(GPUInfo* gpu_info) {
526 TRACE_EVENT0("gpu", "CollectGraphicsInfo");
527
528 DCHECK(gpu_info);
529
530 if (!CollectGraphicsInfoGL(gpu_info))
531 return false;
532
533 // ANGLE's renderer strings are of the form:
534 // ANGLE (<adapter_identifier> Direct3D<version> vs_x_x ps_x_x)
535 std::string direct3d_version;
536 int vertex_shader_major_version = 0;
537 int vertex_shader_minor_version = 0;
538 int pixel_shader_major_version = 0;
539 int pixel_shader_minor_version = 0;
540 if (RE2::FullMatch(gpu_info->gl_renderer,
541 "ANGLE \\(.*\\)") &&
542 RE2::PartialMatch(gpu_info->gl_renderer,
543 " Direct3D(\\w+)",
544 &direct3d_version) &&
545 RE2::PartialMatch(gpu_info->gl_renderer,
546 " vs_(\\d+)_(\\d+)",
547 &vertex_shader_major_version,
548 &vertex_shader_minor_version) &&
549 RE2::PartialMatch(gpu_info->gl_renderer,
550 " ps_(\\d+)_(\\d+)",
551 &pixel_shader_major_version,
552 &pixel_shader_minor_version)) {
553 gpu_info->vertex_shader_version =
554 base::StringPrintf("%d.%d",
555 vertex_shader_major_version,
556 vertex_shader_minor_version);
557 gpu_info->pixel_shader_version =
558 base::StringPrintf("%d.%d",
559 pixel_shader_major_version,
560 pixel_shader_minor_version);
561
562 DCHECK(!gpu_info->vertex_shader_version.empty());
563 // Note: do not reorder, used by UMA_HISTOGRAM below
564 enum ShaderModel {
565 SHADER_MODEL_UNKNOWN,
566 SHADER_MODEL_2_0,
567 SHADER_MODEL_3_0,
568 SHADER_MODEL_4_0,
569 SHADER_MODEL_4_1,
570 SHADER_MODEL_5_0,
571 NUM_SHADER_MODELS
572 };
573 ShaderModel shader_model = SHADER_MODEL_UNKNOWN;
574 if (gpu_info->vertex_shader_version == "5.0") {
575 shader_model = SHADER_MODEL_5_0;
576 } else if (gpu_info->vertex_shader_version == "4.1") {
577 shader_model = SHADER_MODEL_4_1;
578 } else if (gpu_info->vertex_shader_version == "4.0") {
579 shader_model = SHADER_MODEL_4_0;
580 } else if (gpu_info->vertex_shader_version == "3.0") {
581 shader_model = SHADER_MODEL_3_0;
582 } else if (gpu_info->vertex_shader_version == "2.0") {
583 shader_model = SHADER_MODEL_2_0;
584 }
585 UMA_HISTOGRAM_ENUMERATION("GPU.D3DShaderModel", shader_model,
586 NUM_SHADER_MODELS);
587
588 // DirectX diagnostics are collected asynchronously because it takes a
589 // couple of seconds.
590 }
591 return true;
592 }
593
CollectBasicGraphicsInfo(GPUInfo * gpu_info)594 bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
595 TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo");
596 DCHECK(gpu_info);
597 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE.
598 return CollectDriverInfoD3D(gpu_info);
599 }
600
601 } // namespace gpu
602