gpu_info_collector_win.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  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. #include "gpu/config/gpu_info_collector.h"
  5. // C system before C++ system.
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. // This has to be included before windows.h.
  9. #include "third_party/re2/src/re2/re2.h"
  10. #include <windows.h>
  11. #include <d3d11.h>
  12. #include <d3d11_3.h>
  13. #include <d3d12.h>
  14. #include <dxgi.h>
  15. #include <dxgi1_6.h>
  16. #include <vulkan/vulkan.h>
  17. #include <wrl/client.h>
  18. #include "base/file_version_info_win.h"
  19. #include "base/files/file_path.h"
  20. #include "base/files/file_util.h"
  21. #include "base/logging.h"
  22. #include "base/metrics/histogram_functions.h"
  23. #include "base/metrics/histogram_macros.h"
  24. #include "base/numerics/safe_conversions.h"
  25. #include "base/scoped_native_library.h"
  26. #include "base/strings/stringprintf.h"
  27. #include "base/trace_event/trace_event.h"
  28. #include "base/win/scoped_com_initializer.h"
  29. #include "base/win/windows_version.h"
  30. #include "build/branding_buildflags.h"
  31. #include "gpu/config/gpu_util.h"
  32. #include "ui/gl/direct_composition_support.h"
  33. #include "ui/gl/gl_angle_util_win.h"
  34. #include "ui/gl/gl_display.h"
  35. #include "ui/gl/gl_surface_egl.h"
  36. #include "ui/gl/gl_utils.h"
  37. namespace gpu {
  38. namespace {
  39. // These values are persisted to logs. Entries should not be renumbered and
  40. // numeric values should never be reused.
  41. // This should match enum D3D12FeatureLevel in
  42. // \tools\metrics\histograms\enums.xml
  43. enum class D3D12FeatureLevel {
  44. kD3DFeatureLevelUnknown = 0,
  45. kD3DFeatureLevel_12_0 = 1,
  46. kD3DFeatureLevel_12_1 = 2,
  47. kD3DFeatureLevel_11_0 = 3,
  48. kD3DFeatureLevel_11_1 = 4,
  49. kD3DFeatureLevel_12_2 = 5,
  50. kMaxValue = kD3DFeatureLevel_12_2,
  51. };
  52. inline D3D12FeatureLevel ConvertToHistogramFeatureLevel(
  53. uint32_t d3d_feature_level) {
  54. switch (d3d_feature_level) {
  55. case 0:
  56. return D3D12FeatureLevel::kD3DFeatureLevelUnknown;
  57. case D3D_FEATURE_LEVEL_12_0:
  58. return D3D12FeatureLevel::kD3DFeatureLevel_12_0;
  59. case D3D_FEATURE_LEVEL_12_1:
  60. return D3D12FeatureLevel::kD3DFeatureLevel_12_1;
  61. case D3D_FEATURE_LEVEL_12_2:
  62. return D3D12FeatureLevel::kD3DFeatureLevel_12_2;
  63. case D3D_FEATURE_LEVEL_11_0:
  64. return D3D12FeatureLevel::kD3DFeatureLevel_11_0;
  65. case D3D_FEATURE_LEVEL_11_1:
  66. return D3D12FeatureLevel::kD3DFeatureLevel_11_1;
  67. default:
  68. NOTREACHED();
  69. return D3D12FeatureLevel::kD3DFeatureLevelUnknown;
  70. }
  71. }
  72. // These values are persisted to logs. Entries should not be renumbered and
  73. // numeric values should never be reused.
  74. enum class D3D12ShaderModel {
  75. kUnknownOrNoD3D12Devices = 0,
  76. kD3DShaderModel_5_1 = 1,
  77. kD3DShaderModel_6_0 = 2,
  78. kD3DShaderModel_6_1 = 3,
  79. kD3DShaderModel_6_2 = 4,
  80. kD3DShaderModel_6_3 = 5,
  81. kD3DShaderModel_6_4 = 6,
  82. kD3DShaderModel_6_5 = 7,
  83. kD3DShaderModel_6_6 = 8,
  84. kD3DShaderModel_6_7 = 9,
  85. kMaxValue = kD3DShaderModel_6_7,
  86. };
  87. D3D12ShaderModel ConvertToHistogramShaderVersion(uint32_t version) {
  88. switch (version) {
  89. case 0:
  90. return D3D12ShaderModel::kUnknownOrNoD3D12Devices;
  91. case D3D_SHADER_MODEL_5_1:
  92. return D3D12ShaderModel::kD3DShaderModel_5_1;
  93. case D3D_SHADER_MODEL_6_0:
  94. return D3D12ShaderModel::kD3DShaderModel_6_0;
  95. case D3D_SHADER_MODEL_6_1:
  96. return D3D12ShaderModel::kD3DShaderModel_6_1;
  97. case D3D_SHADER_MODEL_6_2:
  98. return D3D12ShaderModel::kD3DShaderModel_6_2;
  99. case D3D_SHADER_MODEL_6_3:
  100. return D3D12ShaderModel::kD3DShaderModel_6_3;
  101. case D3D_SHADER_MODEL_6_4:
  102. return D3D12ShaderModel::kD3DShaderModel_6_4;
  103. case D3D_SHADER_MODEL_6_5:
  104. return D3D12ShaderModel::kD3DShaderModel_6_5;
  105. case D3D_SHADER_MODEL_6_6:
  106. return D3D12ShaderModel::kD3DShaderModel_6_6;
  107. case D3D_SHADER_MODEL_6_7:
  108. return D3D12ShaderModel::kD3DShaderModel_6_7;
  109. default:
  110. NOTREACHED();
  111. return D3D12ShaderModel::kUnknownOrNoD3D12Devices;
  112. }
  113. }
  114. OverlaySupport FlagsToOverlaySupport(bool overlays_supported, UINT flags) {
  115. if (flags & DXGI_OVERLAY_SUPPORT_FLAG_SCALING)
  116. return OverlaySupport::kScaling;
  117. if (flags & DXGI_OVERLAY_SUPPORT_FLAG_DIRECT)
  118. return OverlaySupport::kDirect;
  119. if (overlays_supported)
  120. return OverlaySupport::kSoftware;
  121. return OverlaySupport::kNone;
  122. }
  123. bool GetActiveAdapterLuid(LUID* luid) {
  124. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  125. gl::QueryD3D11DeviceObjectFromANGLE();
  126. if (!d3d11_device)
  127. return false;
  128. Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
  129. if (FAILED(d3d11_device.As(&dxgi_device)))
  130. return false;
  131. Microsoft::WRL::ComPtr<IDXGIAdapter> adapter;
  132. if (FAILED(dxgi_device->GetAdapter(&adapter)))
  133. return false;
  134. DXGI_ADAPTER_DESC desc;
  135. CHECK_EQ(S_OK, adapter->GetDesc(&desc));
  136. // Zero isn't a valid LUID.
  137. if (desc.AdapterLuid.HighPart == 0 && desc.AdapterLuid.LowPart == 0)
  138. return false;
  139. *luid = desc.AdapterLuid;
  140. return true;
  141. }
  142. } // namespace
  143. #if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OFFICIAL_BUILD)
  144. // This function has a real implementation for official builds that can
  145. // be found in src/third_party/amd.
  146. bool GetAMDSwitchableInfo(bool* is_switchable,
  147. uint32_t* active_vendor_id,
  148. uint32_t* active_device_id);
  149. #else
  150. bool GetAMDSwitchableInfo(bool* is_switchable,
  151. uint32_t* active_vendor_id,
  152. uint32_t* active_device_id) {
  153. return false;
  154. }
  155. #endif
  156. // This has to be called after a context is created, active GPU is identified,
  157. // and GPU driver bug workarounds are computed again. Otherwise the workaround
  158. // |disable_direct_composition| may not be correctly applied.
  159. // Also, this has to be called after falling back to SwiftShader decision is
  160. // finalized because this function depends on GL is ANGLE's GLES or not.
  161. void CollectHardwareOverlayInfo(OverlayInfo* overlay_info) {
  162. if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE) {
  163. overlay_info->direct_composition = gl::DirectCompositionSupported();
  164. overlay_info->supports_overlays = gl::DirectCompositionOverlaysSupported();
  165. overlay_info->nv12_overlay_support = FlagsToOverlaySupport(
  166. overlay_info->supports_overlays,
  167. gl::GetDirectCompositionOverlaySupportFlags(DXGI_FORMAT_NV12));
  168. overlay_info->yuy2_overlay_support = FlagsToOverlaySupport(
  169. overlay_info->supports_overlays,
  170. gl::GetDirectCompositionOverlaySupportFlags(DXGI_FORMAT_YUY2));
  171. overlay_info->bgra8_overlay_support =
  172. FlagsToOverlaySupport(overlay_info->supports_overlays,
  173. gl::GetDirectCompositionOverlaySupportFlags(
  174. DXGI_FORMAT_B8G8R8A8_UNORM));
  175. overlay_info->rgb10a2_overlay_support =
  176. FlagsToOverlaySupport(overlay_info->supports_overlays,
  177. gl::GetDirectCompositionOverlaySupportFlags(
  178. DXGI_FORMAT_R10G10B10A2_UNORM));
  179. }
  180. }
  181. bool CollectDriverInfoD3D(GPUInfo* gpu_info) {
  182. TRACE_EVENT0("gpu", "CollectDriverInfoD3D");
  183. Microsoft::WRL::ComPtr<IDXGIFactory1> dxgi_factory;
  184. HRESULT hr = ::CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory));
  185. if (FAILED(hr))
  186. return false;
  187. bool found_amd = false;
  188. bool found_intel = false;
  189. bool found_nvidia = false;
  190. UINT i;
  191. Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
  192. for (i = 0; SUCCEEDED(dxgi_factory->EnumAdapters(i, &dxgi_adapter)); i++) {
  193. DXGI_ADAPTER_DESC desc;
  194. CHECK_EQ(S_OK, dxgi_adapter->GetDesc(&desc));
  195. GPUInfo::GPUDevice device;
  196. device.vendor_id = desc.VendorId;
  197. device.device_id = desc.DeviceId;
  198. device.sub_sys_id = desc.SubSysId;
  199. device.revision = desc.Revision;
  200. device.luid =
  201. CHROME_LUID{desc.AdapterLuid.LowPart, desc.AdapterLuid.HighPart};
  202. LARGE_INTEGER umd_version;
  203. hr = dxgi_adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice),
  204. &umd_version);
  205. if (SUCCEEDED(hr)) {
  206. device.driver_version = base::StringPrintf(
  207. "%d.%d.%d.%d", HIWORD(umd_version.HighPart),
  208. LOWORD(umd_version.HighPart), HIWORD(umd_version.LowPart),
  209. LOWORD(umd_version.LowPart));
  210. } else {
  211. DLOG(ERROR) << "Unable to retrieve the umd version of adapter: "
  212. << desc.Description << " HR: " << std::hex << hr;
  213. }
  214. switch (device.vendor_id) {
  215. case 0x8086:
  216. found_intel = true;
  217. break;
  218. case 0x1002:
  219. found_amd = true;
  220. break;
  221. case 0x10de:
  222. found_nvidia = true;
  223. break;
  224. default:
  225. break;
  226. }
  227. if (i == 0) {
  228. gpu_info->gpu = device;
  229. } else {
  230. gpu_info->secondary_gpus.push_back(device);
  231. }
  232. }
  233. if (found_intel && base::win::GetVersion() < base::win::Version::WIN10) {
  234. // Since Windows 10 (and Windows 8.1 on some systems), switchable graphics
  235. // platforms are managed by Windows and each adapter is accessible as
  236. // separate devices.
  237. // See https://msdn.microsoft.com/en-us/windows/dn265501(v=vs.80)
  238. if (found_amd) {
  239. bool is_amd_switchable = false;
  240. uint32_t active_vendor = 0, active_device = 0;
  241. GetAMDSwitchableInfo(&is_amd_switchable, &active_vendor, &active_device);
  242. gpu_info->amd_switchable = is_amd_switchable;
  243. } else if (found_nvidia) {
  244. // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
  245. HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
  246. gpu_info->optimus = nvd3d9wrap != nullptr;
  247. }
  248. }
  249. Microsoft::WRL::ComPtr<IDXGIFactory6> dxgi_factory6;
  250. if (gpu_info->GpuCount() > 1 && SUCCEEDED(dxgi_factory.As(&dxgi_factory6))) {
  251. if (SUCCEEDED(dxgi_factory6->EnumAdapterByGpuPreference(
  252. 0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
  253. IID_PPV_ARGS(&dxgi_adapter)))) {
  254. DXGI_ADAPTER_DESC desc;
  255. CHECK_EQ(S_OK, dxgi_adapter->GetDesc(&desc));
  256. GPUInfo::GPUDevice* device = gpu_info->FindGpuByLuid(
  257. desc.AdapterLuid.LowPart, desc.AdapterLuid.HighPart);
  258. DCHECK(device);
  259. device->gpu_preference = gl::GpuPreference::kHighPerformance;
  260. }
  261. if (SUCCEEDED(dxgi_factory6->EnumAdapterByGpuPreference(
  262. 0, DXGI_GPU_PREFERENCE_MINIMUM_POWER,
  263. IID_PPV_ARGS(&dxgi_adapter)))) {
  264. DXGI_ADAPTER_DESC desc;
  265. CHECK_EQ(S_OK, dxgi_adapter->GetDesc(&desc));
  266. GPUInfo::GPUDevice* device = gpu_info->FindGpuByLuid(
  267. desc.AdapterLuid.LowPart, desc.AdapterLuid.HighPart);
  268. DCHECK(device);
  269. device->gpu_preference = gl::GpuPreference::kLowPower;
  270. }
  271. }
  272. return i > 0;
  273. }
  274. // CanCreateD3D12Device returns true/false depending on whether D3D12 device
  275. // creation should be attempted on the passed in adapter. Returns false if there
  276. // are known driver bugs.
  277. bool CanCreateD3D12Device(IDXGIAdapter* dxgi_adapter) {
  278. DXGI_ADAPTER_DESC desc;
  279. CHECK_EQ(S_OK, dxgi_adapter->GetDesc(&desc));
  280. // Known driver bugs are Intel-only. Expand in the future, as necessary, for
  281. // other IHVs.
  282. if (desc.VendorId != 0x8086)
  283. return true;
  284. LARGE_INTEGER umd_version;
  285. HRESULT hr =
  286. dxgi_adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &umd_version);
  287. if (FAILED(hr)) {
  288. return false;
  289. }
  290. // On certain Intel drivers, the driver will crash if you call
  291. // D3D12CreateDevice and the command line of the process is greater than 1024
  292. // bytes. 100.9416 is the first driver to introduce the bug, while 100.9664 is
  293. // the first driver to fix it.
  294. if (HIWORD(umd_version.LowPart) == 100 &&
  295. LOWORD(umd_version.LowPart) >= 9416 &&
  296. LOWORD(umd_version.LowPart) < 9664) {
  297. const char* command_line = GetCommandLineA();
  298. const size_t command_line_length = strlen(command_line);
  299. // Check for 1023 since strlen doesn't include the null terminator.
  300. if (command_line_length > 1023) {
  301. return false;
  302. }
  303. }
  304. return true;
  305. }
  306. // DirectX 12 are included with Windows 10 and Server 2016.
  307. void GetGpuSupportedD3D12Version(uint32_t& d3d12_feature_level,
  308. uint32_t& highest_shader_model_version) {
  309. TRACE_EVENT0("gpu", "GetGpuSupportedD3D12Version");
  310. // Initialize to 0 to indicated an unknown type in UMA.
  311. d3d12_feature_level = 0;
  312. highest_shader_model_version = 0;
  313. base::ScopedNativeLibrary d3d12_library(
  314. base::FilePath(FILE_PATH_LITERAL("d3d12.dll")));
  315. if (!d3d12_library.is_valid())
  316. return;
  317. // The order of feature levels to attempt to create in D3D CreateDevice
  318. const D3D_FEATURE_LEVEL feature_levels[] = {
  319. D3D_FEATURE_LEVEL_12_2, D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0,
  320. D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0};
  321. PFN_D3D12_CREATE_DEVICE D3D12CreateDevice =
  322. reinterpret_cast<PFN_D3D12_CREATE_DEVICE>(
  323. d3d12_library.GetFunctionPointer("D3D12CreateDevice"));
  324. Microsoft::WRL::ComPtr<ID3D12Device> d3d12_device;
  325. if (D3D12CreateDevice) {
  326. Microsoft::WRL::ComPtr<IDXGIFactory1> dxgi_factory;
  327. HRESULT hr = ::CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory));
  328. if (FAILED(hr)) {
  329. return;
  330. }
  331. Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
  332. hr = dxgi_factory->EnumAdapters(0, &dxgi_adapter);
  333. if (FAILED(hr)) {
  334. return;
  335. }
  336. if (!CanCreateD3D12Device(dxgi_adapter.Get())) {
  337. return;
  338. }
  339. // For the default adapter only: EnumAdapters(0, ...).
  340. // Check to see if the adapter supports Direct3D 12.
  341. for (auto level : feature_levels) {
  342. if (SUCCEEDED(D3D12CreateDevice(dxgi_adapter.Get(), level,
  343. _uuidof(ID3D12Device), &d3d12_device))) {
  344. d3d12_feature_level = level;
  345. break;
  346. }
  347. }
  348. }
  349. // Query the maximum supported shader model version.
  350. if (d3d12_device) {
  351. // As per the documentation, CheckFeatureSupport will return E_INVALIDARG if
  352. // the shader model is not known by the current runtime, so we loop in
  353. // decreasing shader model version to determine the highest supported model:
  354. // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_feature_data_shader_model.
  355. const D3D_SHADER_MODEL shader_models[] = {
  356. D3D_SHADER_MODEL_6_7, D3D_SHADER_MODEL_6_6, D3D_SHADER_MODEL_6_5,
  357. D3D_SHADER_MODEL_6_4, D3D_SHADER_MODEL_6_3, D3D_SHADER_MODEL_6_2,
  358. D3D_SHADER_MODEL_6_1, D3D_SHADER_MODEL_6_0, D3D_SHADER_MODEL_5_1,
  359. };
  360. for (auto model : shader_models) {
  361. D3D12_FEATURE_DATA_SHADER_MODEL shader_model_data = {};
  362. shader_model_data.HighestShaderModel = model;
  363. if (SUCCEEDED(d3d12_device->CheckFeatureSupport(
  364. D3D12_FEATURE_SHADER_MODEL, &shader_model_data,
  365. sizeof(shader_model_data)))) {
  366. highest_shader_model_version = shader_model_data.HighestShaderModel;
  367. break;
  368. }
  369. }
  370. }
  371. }
  372. // The old graphics drivers are installed to the Windows system directory
  373. // c:\windows\system32 or SysWOW64. Those versions can be detected without
  374. // specifying the absolute directory. For a newer version (>= ~2018), this won't
  375. // work. The newer graphics drivers are located in
  376. // c:\windows\system32\DriverStore\FileRepository\xxx.infxxx which contains a
  377. // different number at each installation
  378. bool BadAMDVulkanDriverVersion() {
  379. // Both 32-bit and 64-bit dll are broken. If 64-bit doesn't exist,
  380. // 32-bit dll will be used to detect the AMD Vulkan driver.
  381. const base::FilePath kAmdDriver64(FILE_PATH_LITERAL("amdvlk64.dll"));
  382. const base::FilePath kAmdDriver32(FILE_PATH_LITERAL("amdvlk32.dll"));
  383. std::unique_ptr<FileVersionInfoWin> file_version_info =
  384. FileVersionInfoWin::CreateFileVersionInfoWin(kAmdDriver64);
  385. if (!file_version_info) {
  386. file_version_info =
  387. FileVersionInfoWin::CreateFileVersionInfoWin(kAmdDriver32);
  388. if (!file_version_info)
  389. return false;
  390. }
  391. base::Version amd_version = file_version_info->GetFileVersion();
  392. // From the Canary crash logs, the broken amdvlk64.dll versions
  393. // are 1.0.39.0, 1.0.51.0 and 1.0.54.0. In the manual test, version
  394. // 9.2.10.1 dated 12/6/2017 works and version 1.0.54.0 dated 11/2/1017
  395. // crashes. All version numbers small than 1.0.54.0 will be marked as
  396. // broken.
  397. const base::Version kBadAMDVulkanDriverVersion("1.0.54.0");
  398. // CompareTo() returns -1, 0, 1 for <, ==, >.
  399. if (amd_version.CompareTo(kBadAMDVulkanDriverVersion) != 1)
  400. return true;
  401. return false;
  402. }
  403. // Vulkan 1.1 was released by the Khronos Group on March 7, 2018.
  404. // Blocklist all driver versions without Vulkan 1.1 support and those that cause
  405. // lots of crashes.
  406. bool BadGraphicsDriverVersions(const gpu::GPUInfo::GPUDevice& gpu_device) {
  407. // GPU Device info is not available in gpu_integration_test.info-collection
  408. // with --no-delay-for-dx12-vulkan-info-collection.
  409. if (gpu_device.driver_version.empty())
  410. return false;
  411. base::Version driver_version(gpu_device.driver_version);
  412. if (!driver_version.IsValid())
  413. return true;
  414. // AMD Vulkan drivers - amdvlk64.dll
  415. constexpr uint32_t kAMDVendorId = 0x1002;
  416. if (gpu_device.vendor_id == kAMDVendorId) {
  417. // 26.20.12028.2 (2019)- number of crashes 1,188,048 as of 5/14/2020.
  418. // Returns -1, 0, 1 for <, ==, >.
  419. if (driver_version.CompareTo(base::Version("26.20.12028.2")) == 0)
  420. return true;
  421. }
  422. return false;
  423. }
  424. bool InitVulkan(base::NativeLibrary* vulkan_library,
  425. PFN_vkGetInstanceProcAddr* vkGetInstanceProcAddr,
  426. PFN_vkCreateInstance* vkCreateInstance,
  427. uint32_t* vulkan_version) {
  428. *vulkan_version = 0;
  429. *vulkan_library =
  430. base::LoadNativeLibrary(base::FilePath(L"vulkan-1.dll"), nullptr);
  431. if (!(*vulkan_library)) {
  432. return false;
  433. }
  434. *vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
  435. base::GetFunctionPointerFromNativeLibrary(*vulkan_library,
  436. "vkGetInstanceProcAddr"));
  437. if (*vkGetInstanceProcAddr) {
  438. *vulkan_version = VK_MAKE_VERSION(1, 0, 0);
  439. PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion;
  440. vkEnumerateInstanceVersion =
  441. reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
  442. (*vkGetInstanceProcAddr)(nullptr, "vkEnumerateInstanceVersion"));
  443. // If the vkGetInstanceProcAddr returns nullptr for
  444. // vkEnumerateInstanceVersion, it is a Vulkan 1.0 implementation.
  445. if (!vkEnumerateInstanceVersion) {
  446. return false;
  447. }
  448. // Return value can be VK_SUCCESS or VK_ERROR_OUT_OF_HOST_MEMORY.
  449. if (vkEnumerateInstanceVersion(vulkan_version) != VK_SUCCESS) {
  450. return false;
  451. }
  452. // The minimum version required for Vulkan to be enabled is 1.1.0.
  453. // No further queries will be called for early versions. They are unstable
  454. // and might cause crashes.
  455. if (*vulkan_version < VK_MAKE_VERSION(1, 1, 0)) {
  456. return false;
  457. }
  458. *vkCreateInstance = reinterpret_cast<PFN_vkCreateInstance>(
  459. (*vkGetInstanceProcAddr)(nullptr, "vkCreateInstance"));
  460. if (*vkCreateInstance)
  461. return true;
  462. }
  463. // From the crash reports, unloading the library here might cause a crash in
  464. // the Vulkan loader or in the Vulkan driver. To work around it, don't
  465. // explicitly unload the DLL. Instead, GPU process shutdown will unload all
  466. // loaded DLLs.
  467. // base::UnloadNativeLibrary(*vulkan_library);
  468. return false;
  469. }
  470. bool InitVulkanInstanceProc(
  471. const VkInstance& vk_instance,
  472. const PFN_vkGetInstanceProcAddr& vkGetInstanceProcAddr,
  473. PFN_vkEnumeratePhysicalDevices* vkEnumeratePhysicalDevices,
  474. PFN_vkEnumerateDeviceExtensionProperties*
  475. vkEnumerateDeviceExtensionProperties) {
  476. *vkEnumeratePhysicalDevices =
  477. reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(
  478. vkGetInstanceProcAddr(vk_instance, "vkEnumeratePhysicalDevices"));
  479. *vkEnumerateDeviceExtensionProperties =
  480. reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
  481. vkGetInstanceProcAddr(vk_instance,
  482. "vkEnumerateDeviceExtensionProperties"));
  483. if ((*vkEnumeratePhysicalDevices) &&
  484. (*vkEnumerateDeviceExtensionProperties)) {
  485. return true;
  486. }
  487. return false;
  488. }
  489. uint32_t GetGpuSupportedVulkanVersion(
  490. const gpu::GPUInfo::GPUDevice& gpu_device) {
  491. TRACE_EVENT0("gpu", "GetGpuSupportedVulkanVersion");
  492. base::NativeLibrary vulkan_library;
  493. PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
  494. PFN_vkCreateInstance vkCreateInstance;
  495. PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
  496. PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
  497. VkInstance vk_instance = VK_NULL_HANDLE;
  498. uint32_t physical_device_count = 0;
  499. // Skip if the system has an older AMD Vulkan driver amdvlk64.dll or
  500. // amdvlk32.dll which crashes when vkCreateInstance() is called. This bug has
  501. // been fixed in the latest AMD driver.
  502. // Detected by the file version of amdvlk64.dll.
  503. if (BadAMDVulkanDriverVersion()) {
  504. return 0;
  505. }
  506. // Don't collect any info if the graphics vulkan driver is blocklisted or
  507. // doesn't support Vulkan 1.1
  508. // Detected by the graphic driver version returned by DXGI
  509. if (BadGraphicsDriverVersions(gpu_device))
  510. return 0;
  511. // Only supports a version >= 1.1.0.
  512. uint32_t vulkan_version = 0;
  513. if (!InitVulkan(&vulkan_library, &vkGetInstanceProcAddr, &vkCreateInstance,
  514. &vulkan_version)) {
  515. return 0;
  516. }
  517. VkApplicationInfo app_info = {};
  518. app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  519. const std::vector<const char*> enabled_instance_extensions = {
  520. "VK_KHR_surface", "VK_KHR_win32_surface"};
  521. VkInstanceCreateInfo create_info = {};
  522. create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  523. create_info.pApplicationInfo = &app_info;
  524. create_info.enabledExtensionCount = enabled_instance_extensions.size();
  525. create_info.ppEnabledExtensionNames = enabled_instance_extensions.data();
  526. // Get the Vulkan API version supported in the GPU driver
  527. int highest_minor_version = VK_VERSION_MINOR(vulkan_version);
  528. for (int minor_version = highest_minor_version; minor_version >= 1;
  529. --minor_version) {
  530. app_info.apiVersion = VK_MAKE_VERSION(1, minor_version, 0);
  531. VkResult result = vkCreateInstance(&create_info, nullptr, &vk_instance);
  532. if (result == VK_SUCCESS && vk_instance &&
  533. InitVulkanInstanceProc(vk_instance, vkGetInstanceProcAddr,
  534. &vkEnumeratePhysicalDevices,
  535. &vkEnumerateDeviceExtensionProperties)) {
  536. result = vkEnumeratePhysicalDevices(vk_instance, &physical_device_count,
  537. nullptr);
  538. if (result == VK_SUCCESS && physical_device_count > 0) {
  539. return app_info.apiVersion;
  540. } else {
  541. // Skip destroy here. GPU process shutdown will unload all loaded DLLs.
  542. // vkDestroyInstance(vk_instance, nullptr);
  543. vk_instance = VK_NULL_HANDLE;
  544. }
  545. }
  546. }
  547. // From the crash reports, calling the following two functions might cause a
  548. // crash in the Vulkan loader or in the Vulkan driver. To work around it,
  549. // don't explicitly unload the DLL. Instead, GPU process shutdown will unload
  550. // all loaded DLLs.
  551. // if (vk_instance) {
  552. // vkDestroyInstance(vk_instance, nullptr);
  553. // }
  554. // base::UnloadNativeLibrary(vulkan_library);
  555. return 0;
  556. }
  557. void RecordGpuSupportedDx12VersionHistograms(
  558. uint32_t d3d12_feature_level,
  559. uint32_t highest_shader_model_version) {
  560. bool supports_dx12 =
  561. (d3d12_feature_level >= D3D_FEATURE_LEVEL_12_0) ? true : false;
  562. UMA_HISTOGRAM_BOOLEAN("GPU.SupportsDX12", supports_dx12);
  563. UMA_HISTOGRAM_ENUMERATION(
  564. "GPU.D3D12FeatureLevel",
  565. ConvertToHistogramFeatureLevel(d3d12_feature_level));
  566. UMA_HISTOGRAM_ENUMERATION(
  567. "GPU.D3D12HighestShaderModel2",
  568. ConvertToHistogramShaderVersion(highest_shader_model_version));
  569. }
  570. bool CollectD3D11FeatureInfo(D3D_FEATURE_LEVEL* d3d11_feature_level,
  571. bool* has_discrete_gpu) {
  572. Microsoft::WRL::ComPtr<IDXGIFactory1> dxgi_factory;
  573. if (FAILED(::CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory))))
  574. return false;
  575. base::ScopedNativeLibrary d3d11_library(
  576. base::FilePath(FILE_PATH_LITERAL("d3d11.dll")));
  577. if (!d3d11_library.is_valid())
  578. return false;
  579. PFN_D3D11_CREATE_DEVICE D3D11CreateDevice =
  580. reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
  581. d3d11_library.GetFunctionPointer("D3D11CreateDevice"));
  582. if (!D3D11CreateDevice)
  583. return false;
  584. // The order of feature levels to attempt to create in D3D CreateDevice.
  585. // TODO(crbug.com/1312519): Using 12_2 in kFeatureLevels[] will cause failure
  586. // in D3D11CreateDevice(). Limit the highest feature to 12_1.
  587. const D3D_FEATURE_LEVEL kFeatureLevels[] = {
  588. D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1,
  589. D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0,
  590. D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1};
  591. bool detected_discrete_gpu = false;
  592. D3D_FEATURE_LEVEL max_level = D3D_FEATURE_LEVEL_1_0_CORE;
  593. Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
  594. for (UINT ii = 0; SUCCEEDED(dxgi_factory->EnumAdapters(ii, &dxgi_adapter));
  595. ++ii) {
  596. DXGI_ADAPTER_DESC desc;
  597. CHECK_EQ(S_OK, dxgi_adapter->GetDesc(&desc));
  598. if (desc.VendorId == 0x1414) {
  599. // Bypass Microsoft software renderer.
  600. continue;
  601. }
  602. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device;
  603. D3D_FEATURE_LEVEL returned_feature_level = D3D_FEATURE_LEVEL_1_0_CORE;
  604. if (FAILED(D3D11CreateDevice(dxgi_adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN,
  605. /*Software=*/0,
  606. /*Flags=*/0, kFeatureLevels,
  607. _countof(kFeatureLevels), D3D11_SDK_VERSION,
  608. &d3d11_device, &returned_feature_level,
  609. /*ppImmediateContext=*/nullptr))) {
  610. continue;
  611. }
  612. if (returned_feature_level > max_level)
  613. max_level = returned_feature_level;
  614. Microsoft::WRL::ComPtr<ID3D11Device3> d3d11_device_3;
  615. if (FAILED(d3d11_device.As(&d3d11_device_3)))
  616. continue;
  617. D3D11_FEATURE_DATA_D3D11_OPTIONS2 data = {};
  618. if (FAILED(d3d11_device_3->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS2,
  619. &data, sizeof(data)))) {
  620. continue;
  621. }
  622. if (!data.UnifiedMemoryArchitecture)
  623. detected_discrete_gpu = true;
  624. }
  625. if (max_level > D3D_FEATURE_LEVEL_1_0_CORE) {
  626. *d3d11_feature_level = max_level;
  627. *has_discrete_gpu = detected_discrete_gpu;
  628. return true;
  629. }
  630. return false;
  631. }
  632. bool CollectContextGraphicsInfo(GPUInfo* gpu_info) {
  633. TRACE_EVENT0("gpu", "CollectGraphicsInfo");
  634. DCHECK(gpu_info);
  635. if (!CollectGraphicsInfoGL(gpu_info, gl::GetDefaultDisplayEGL()))
  636. return false;
  637. // ANGLE's renderer strings are of the form:
  638. // ANGLE (<adapter_identifier> Direct3D<version> vs_x_x ps_x_x)
  639. std::string direct3d_version;
  640. int vertex_shader_major_version = 0;
  641. int vertex_shader_minor_version = 0;
  642. int pixel_shader_major_version = 0;
  643. int pixel_shader_minor_version = 0;
  644. if (RE2::FullMatch(gpu_info->gl_renderer,
  645. "ANGLE \\(.*\\)") &&
  646. RE2::PartialMatch(gpu_info->gl_renderer,
  647. " Direct3D(\\w+)",
  648. &direct3d_version) &&
  649. RE2::PartialMatch(gpu_info->gl_renderer,
  650. " vs_(\\d+)_(\\d+)",
  651. &vertex_shader_major_version,
  652. &vertex_shader_minor_version) &&
  653. RE2::PartialMatch(gpu_info->gl_renderer,
  654. " ps_(\\d+)_(\\d+)",
  655. &pixel_shader_major_version,
  656. &pixel_shader_minor_version)) {
  657. gpu_info->vertex_shader_version =
  658. base::StringPrintf("%d.%d",
  659. vertex_shader_major_version,
  660. vertex_shader_minor_version);
  661. gpu_info->pixel_shader_version =
  662. base::StringPrintf("%d.%d",
  663. pixel_shader_major_version,
  664. pixel_shader_minor_version);
  665. DCHECK(!gpu_info->vertex_shader_version.empty());
  666. // Note: do not reorder, used by UMA_HISTOGRAM below
  667. enum ShaderModel {
  668. SHADER_MODEL_UNKNOWN,
  669. SHADER_MODEL_2_0,
  670. SHADER_MODEL_3_0,
  671. SHADER_MODEL_4_0,
  672. SHADER_MODEL_4_1,
  673. SHADER_MODEL_5_0,
  674. NUM_SHADER_MODELS
  675. };
  676. ShaderModel shader_model = SHADER_MODEL_UNKNOWN;
  677. if (gpu_info->vertex_shader_version == "5.0") {
  678. shader_model = SHADER_MODEL_5_0;
  679. } else if (gpu_info->vertex_shader_version == "4.1") {
  680. shader_model = SHADER_MODEL_4_1;
  681. } else if (gpu_info->vertex_shader_version == "4.0") {
  682. shader_model = SHADER_MODEL_4_0;
  683. } else if (gpu_info->vertex_shader_version == "3.0") {
  684. shader_model = SHADER_MODEL_3_0;
  685. } else if (gpu_info->vertex_shader_version == "2.0") {
  686. shader_model = SHADER_MODEL_2_0;
  687. }
  688. UMA_HISTOGRAM_ENUMERATION("GPU.D3DShaderModel", shader_model,
  689. NUM_SHADER_MODELS);
  690. // DirectX diagnostics are collected asynchronously because it takes a
  691. // couple of seconds.
  692. }
  693. return true;
  694. }
  695. bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
  696. TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo");
  697. DCHECK(gpu_info);
  698. // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE.
  699. return CollectDriverInfoD3D(gpu_info);
  700. }
  701. bool IdentifyActiveGPUWithLuid(GPUInfo* gpu_info) {
  702. LUID luid;
  703. if (!GetActiveAdapterLuid(&luid))
  704. return false;
  705. gpu_info->gpu.active = false;
  706. for (size_t i = 0; i < gpu_info->secondary_gpus.size(); i++)
  707. gpu_info->secondary_gpus[i].active = false;
  708. if (gpu_info->gpu.luid.HighPart == luid.HighPart &&
  709. gpu_info->gpu.luid.LowPart == luid.LowPart) {
  710. gpu_info->gpu.active = true;
  711. return true;
  712. }
  713. for (size_t i = 0; i < gpu_info->secondary_gpus.size(); i++) {
  714. if (gpu_info->secondary_gpus[i].luid.HighPart == luid.HighPart &&
  715. gpu_info->secondary_gpus[i].luid.LowPart == luid.LowPart) {
  716. gpu_info->secondary_gpus[i].active = true;
  717. return true;
  718. }
  719. }
  720. return false;
  721. }
  722. } // namespace gpu