direct_composition_support.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. // Copyright 2022 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 "ui/gl/direct_composition_support.h"
  5. #include <dxgi1_6.h>
  6. #include "base/command_line.h"
  7. #include "base/metrics/histogram_functions.h"
  8. #include "base/metrics/histogram_macros.h"
  9. #include "base/synchronization/lock.h"
  10. #include "base/win/windows_version.h"
  11. #include "ui/gfx/geometry/rect.h"
  12. #include "ui/gl/gl_angle_util_win.h"
  13. #include "ui/gl/gl_bindings.h"
  14. #include "ui/gl/gl_display.h"
  15. #include "ui/gl/gl_features.h"
  16. #include "ui/gl/gl_implementation.h"
  17. #include "ui/gl/gl_switches.h"
  18. namespace gl {
  19. namespace {
  20. // Whether the overlay caps are valid or not. GUARDED_BY GetOverlayLock().
  21. bool g_overlay_caps_valid = false;
  22. // Indicates support for either NV12 or YUY2 overlays. GUARDED_BY
  23. // GetOverlayLock().
  24. bool g_supports_overlays = false;
  25. // Whether the GPU can support hardware overlays or not.
  26. bool g_supports_hardware_overlays = false;
  27. // Whether the DecodeSwapChain is disabled or not.
  28. bool g_decode_swap_chain_disabled = false;
  29. // Whether to force the nv12 overlay support.
  30. bool g_force_nv12_overlay_support = false;
  31. // Whether software overlays have been disabled.
  32. bool g_disable_sw_overlays = false;
  33. // The lock to guard g_overlay_caps_valid and g_supports_overlays.
  34. base::Lock& GetOverlayLock() {
  35. static base::NoDestructor<base::Lock> overlay_lock;
  36. return *overlay_lock;
  37. }
  38. bool SupportsOverlays() {
  39. base::AutoLock auto_lock(GetOverlayLock());
  40. return g_supports_overlays;
  41. }
  42. bool SupportsHardwareOverlays() {
  43. base::AutoLock auto_lock(GetOverlayLock());
  44. return g_supports_hardware_overlays;
  45. }
  46. void SetSupportsOverlays(bool support) {
  47. base::AutoLock auto_lock(GetOverlayLock());
  48. g_supports_overlays = support;
  49. }
  50. void SetSupportsHardwareOverlays(bool support) {
  51. base::AutoLock auto_lock(GetOverlayLock());
  52. g_supports_hardware_overlays = support;
  53. }
  54. bool SupportsSoftwareOverlays() {
  55. return base::FeatureList::IsEnabled(
  56. features::kDirectCompositionSoftwareOverlays) &&
  57. !g_disable_sw_overlays;
  58. }
  59. bool OverlayCapsValid() {
  60. base::AutoLock auto_lock(GetOverlayLock());
  61. return g_overlay_caps_valid;
  62. }
  63. void SetOverlayCapsValid(bool valid) {
  64. base::AutoLock auto_lock(GetOverlayLock());
  65. g_overlay_caps_valid = valid;
  66. }
  67. // A warpper of IDXGIOutput4::CheckOverlayColorSpaceSupport()
  68. bool CheckOverlayColorSpaceSupport(
  69. DXGI_FORMAT dxgi_format,
  70. DXGI_COLOR_SPACE_TYPE dxgi_color_space,
  71. Microsoft::WRL::ComPtr<IDXGIOutput> output,
  72. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device) {
  73. UINT color_space_support_flags = 0;
  74. Microsoft::WRL::ComPtr<IDXGIOutput4> output4;
  75. if (FAILED(output.As(&output4)) ||
  76. FAILED(output4->CheckOverlayColorSpaceSupport(
  77. dxgi_format, dxgi_color_space, d3d11_device.Get(),
  78. &color_space_support_flags)))
  79. return false;
  80. return (color_space_support_flags &
  81. DXGI_OVERLAY_COLOR_SPACE_SUPPORT_FLAG_PRESENT);
  82. }
  83. // Used for adjusting overlay size to monitor size.
  84. gfx::Size g_primary_monitor_size;
  85. // The number of all visible display monitors on a desktop.
  86. int g_num_monitors = 0;
  87. // Global direct composition device.
  88. IDCompositionDevice2* g_dcomp_device = nullptr;
  89. // Whether swap chain present failed and direct composition should be disabled.
  90. bool g_direct_composition_swap_chain_failed = false;
  91. // Preferred overlay format set when detecting overlay support during
  92. // initialization. Set to NV12 by default so that it's used when enabling
  93. // overlays using command line flags.
  94. DXGI_FORMAT g_overlay_format_used = DXGI_FORMAT_NV12;
  95. DXGI_FORMAT g_overlay_format_used_hdr = DXGI_FORMAT_UNKNOWN;
  96. // These are the raw support info, which shouldn't depend on field trial state,
  97. // or command line flags. GUARDED_BY GetOverlayLock().
  98. UINT g_nv12_overlay_support_flags = 0;
  99. UINT g_yuy2_overlay_support_flags = 0;
  100. UINT g_bgra8_overlay_support_flags = 0;
  101. UINT g_rgb10a2_overlay_support_flags = 0;
  102. // When this is set, if NV12 or YUY2 overlays are supported, set BGRA8 overlays
  103. // as supported as well.
  104. bool g_enable_bgra8_overlays_with_yuv_overlay_support = false;
  105. // Force enabling DXGI_FORMAT_R10G10B10A2_UNORM format for overlay. Intel
  106. // celake and Tigerlake fail to report the cap of this HDR overlay format.
  107. // TODO(magchen@): Remove this workaround when this cap is fixed in the Intel
  108. // drivers.
  109. bool g_force_rgb10a2_overlay_support = false;
  110. // Per Intel's request, only use NV12 for overlay when
  111. // COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 is also supported. At least one Intel
  112. // Gen9 SKU does not support NV12 overlays and it cannot be screened by the
  113. // device id.
  114. bool g_check_ycbcr_studio_g22_left_p709_for_nv12_support = false;
  115. void SetOverlaySupportFlagsForFormats(UINT nv12_flags,
  116. UINT yuy2_flags,
  117. UINT bgra8_flags,
  118. UINT rgb10a2_flags) {
  119. base::AutoLock auto_lock(GetOverlayLock());
  120. g_nv12_overlay_support_flags = nv12_flags;
  121. g_yuy2_overlay_support_flags = yuy2_flags;
  122. g_bgra8_overlay_support_flags = bgra8_flags;
  123. g_rgb10a2_overlay_support_flags = rgb10a2_flags;
  124. }
  125. bool FlagsSupportsOverlays(UINT flags) {
  126. return (flags & (DXGI_OVERLAY_SUPPORT_FLAG_DIRECT |
  127. DXGI_OVERLAY_SUPPORT_FLAG_SCALING));
  128. }
  129. void GetGpuDriverOverlayInfo(bool* supports_overlays,
  130. bool* supports_hardware_overlays,
  131. DXGI_FORMAT* overlay_format_used,
  132. DXGI_FORMAT* overlay_format_used_hdr,
  133. UINT* nv12_overlay_support_flags,
  134. UINT* yuy2_overlay_support_flags,
  135. UINT* bgra8_overlay_support_flags,
  136. UINT* rgb10a2_overlay_support_flags) {
  137. // Initialization
  138. *supports_overlays = false;
  139. *supports_hardware_overlays = false;
  140. *overlay_format_used = DXGI_FORMAT_NV12;
  141. *overlay_format_used_hdr = DXGI_FORMAT_R10G10B10A2_UNORM;
  142. *nv12_overlay_support_flags = 0;
  143. *yuy2_overlay_support_flags = 0;
  144. *bgra8_overlay_support_flags = 0;
  145. *rgb10a2_overlay_support_flags = 0;
  146. // Check for DirectComposition support first to prevent likely crashes.
  147. if (!DirectCompositionSupported())
  148. return;
  149. // Before Windows 10 Anniversary Update (Redstone 1), overlay planes wouldn't
  150. // be assigned to non-UWP apps.
  151. if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
  152. return;
  153. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  154. QueryD3D11DeviceObjectFromANGLE();
  155. if (!d3d11_device) {
  156. DLOG(ERROR) << "Failed to retrieve D3D11 device";
  157. return;
  158. }
  159. Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
  160. if (FAILED(d3d11_device.As(&dxgi_device))) {
  161. DLOG(ERROR) << "Failed to retrieve DXGI device";
  162. return;
  163. }
  164. Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
  165. if (FAILED(dxgi_device->GetAdapter(&dxgi_adapter))) {
  166. DLOG(ERROR) << "Failed to retrieve DXGI adapter";
  167. return;
  168. }
  169. // This will fail if the D3D device is "Microsoft Basic Display Adapter".
  170. Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device;
  171. if (FAILED(d3d11_device.As(&video_device))) {
  172. DLOG(ERROR) << "Failed to retrieve video device";
  173. return;
  174. }
  175. unsigned int i = 0;
  176. while (true) {
  177. Microsoft::WRL::ComPtr<IDXGIOutput> output;
  178. if (FAILED(dxgi_adapter->EnumOutputs(i++, &output)))
  179. break;
  180. DCHECK(output);
  181. Microsoft::WRL::ComPtr<IDXGIOutput3> output3;
  182. if (FAILED(output.As(&output3)))
  183. continue;
  184. DCHECK(output3);
  185. output3->CheckOverlaySupport(DXGI_FORMAT_NV12, d3d11_device.Get(),
  186. nv12_overlay_support_flags);
  187. output3->CheckOverlaySupport(DXGI_FORMAT_YUY2, d3d11_device.Get(),
  188. yuy2_overlay_support_flags);
  189. output3->CheckOverlaySupport(DXGI_FORMAT_B8G8R8A8_UNORM, d3d11_device.Get(),
  190. bgra8_overlay_support_flags);
  191. // Today it still returns false, which blocks Chrome from using HDR
  192. // overlays.
  193. output3->CheckOverlaySupport(DXGI_FORMAT_R10G10B10A2_UNORM,
  194. d3d11_device.Get(),
  195. rgb10a2_overlay_support_flags);
  196. if (FlagsSupportsOverlays(*nv12_overlay_support_flags)) {
  197. // NV12 format is preferred if it's supported.
  198. *overlay_format_used = DXGI_FORMAT_NV12;
  199. *supports_hardware_overlays = true;
  200. if (g_check_ycbcr_studio_g22_left_p709_for_nv12_support &&
  201. !CheckOverlayColorSpaceSupport(
  202. DXGI_FORMAT_NV12, DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709,
  203. output, d3d11_device)) {
  204. // Some new Intel drivers only claim to support unscaled overlays, but
  205. // scaled overlays still work. It's possible DWM works around it by
  206. // performing an extra scaling Blt before calling the driver. Even when
  207. // scaled overlays aren't actually supported, presentation using the
  208. // overlay path should be relatively efficient.
  209. *supports_hardware_overlays = false;
  210. }
  211. }
  212. if (!*supports_hardware_overlays &&
  213. FlagsSupportsOverlays(*yuy2_overlay_support_flags)) {
  214. // If NV12 isn't supported, fallback to YUY2 if it's supported.
  215. *overlay_format_used = DXGI_FORMAT_YUY2;
  216. *supports_hardware_overlays = true;
  217. }
  218. if (g_enable_bgra8_overlays_with_yuv_overlay_support) {
  219. if (FlagsSupportsOverlays(*nv12_overlay_support_flags))
  220. *bgra8_overlay_support_flags = *nv12_overlay_support_flags;
  221. else if (FlagsSupportsOverlays(*yuy2_overlay_support_flags))
  222. *bgra8_overlay_support_flags = *yuy2_overlay_support_flags;
  223. }
  224. // RGB10A2 overlay is used for displaying HDR content. In Intel's
  225. // platform, RGB10A2 overlay is enabled only when
  226. // DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 is supported.
  227. if (FlagsSupportsOverlays(*rgb10a2_overlay_support_flags)) {
  228. if (!CheckOverlayColorSpaceSupport(
  229. DXGI_FORMAT_R10G10B10A2_UNORM,
  230. DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, output, d3d11_device))
  231. *rgb10a2_overlay_support_flags = 0;
  232. }
  233. if (g_force_rgb10a2_overlay_support) {
  234. *rgb10a2_overlay_support_flags = DXGI_OVERLAY_SUPPORT_FLAG_SCALING;
  235. }
  236. // Early out after the first output that reports overlay support. All
  237. // outputs are expected to report the same overlay support according to
  238. // Microsoft's WDDM documentation:
  239. // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/multiplane-overlay-hardware-requirements
  240. // TODO(sunnyps): If the above is true, then we can only look at first
  241. // output instead of iterating over all outputs.
  242. if (*supports_hardware_overlays)
  243. break;
  244. }
  245. *supports_overlays = *supports_hardware_overlays;
  246. if (*supports_hardware_overlays || !SupportsSoftwareOverlays()) {
  247. return;
  248. }
  249. // If no devices with hardware overlay support were found use software ones.
  250. *supports_overlays = true;
  251. *nv12_overlay_support_flags = 0;
  252. *yuy2_overlay_support_flags = 0;
  253. *bgra8_overlay_support_flags = 0;
  254. *rgb10a2_overlay_support_flags = 0;
  255. // Software overlays always use NV12 because it's slightly more efficient and
  256. // YUY2 was only used because Skylake doesn't support NV12 hardware overlays.
  257. *overlay_format_used = DXGI_FORMAT_NV12;
  258. }
  259. void UpdateOverlaySupport() {
  260. if (OverlayCapsValid())
  261. return;
  262. SetOverlayCapsValid(true);
  263. bool supports_overlays = false;
  264. bool supports_hardware_overlays = false;
  265. DXGI_FORMAT overlay_format_used = DXGI_FORMAT_NV12;
  266. DXGI_FORMAT overlay_format_used_hdr = DXGI_FORMAT_R10G10B10A2_UNORM;
  267. UINT nv12_overlay_support_flags = 0;
  268. UINT yuy2_overlay_support_flags = 0;
  269. UINT bgra8_overlay_support_flags = 0;
  270. UINT rgb10a2_overlay_support_flags = 0;
  271. GetGpuDriverOverlayInfo(
  272. &supports_overlays, &supports_hardware_overlays, &overlay_format_used,
  273. &overlay_format_used_hdr, &nv12_overlay_support_flags,
  274. &yuy2_overlay_support_flags, &bgra8_overlay_support_flags,
  275. &rgb10a2_overlay_support_flags);
  276. if (g_force_nv12_overlay_support) {
  277. supports_overlays = true;
  278. nv12_overlay_support_flags = DXGI_OVERLAY_SUPPORT_FLAG_SCALING;
  279. overlay_format_used = DXGI_FORMAT_NV12;
  280. }
  281. if (base::CommandLine::ForCurrentProcess()->HasSwitch(
  282. switches::kDirectCompositionVideoSwapChainFormat)) {
  283. std::string override_format =
  284. base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
  285. switches::kDirectCompositionVideoSwapChainFormat);
  286. if (override_format == kSwapChainFormatNV12) {
  287. overlay_format_used = DXGI_FORMAT_NV12;
  288. } else if (override_format == kSwapChainFormatYUY2) {
  289. overlay_format_used = DXGI_FORMAT_YUY2;
  290. } else if (override_format == kSwapChainFormatBGRA) {
  291. overlay_format_used = DXGI_FORMAT_B8G8R8A8_UNORM;
  292. } else {
  293. DLOG(ERROR) << "Invalid value for switch "
  294. << switches::kDirectCompositionVideoSwapChainFormat;
  295. }
  296. }
  297. // Record histograms.
  298. if (supports_overlays) {
  299. base::UmaHistogramSparse("GPU.DirectComposition.OverlayFormatUsed3",
  300. overlay_format_used);
  301. }
  302. base::UmaHistogramBoolean("GPU.DirectComposition.OverlaysSupported",
  303. supports_overlays);
  304. base::UmaHistogramBoolean("GPU.DirectComposition.HardwareOverlaysSupported",
  305. supports_hardware_overlays);
  306. // Update global caps.
  307. SetSupportsOverlays(supports_overlays);
  308. SetSupportsHardwareOverlays(supports_hardware_overlays);
  309. SetOverlaySupportFlagsForFormats(
  310. nv12_overlay_support_flags, yuy2_overlay_support_flags,
  311. bgra8_overlay_support_flags, rgb10a2_overlay_support_flags);
  312. g_overlay_format_used = overlay_format_used;
  313. g_overlay_format_used_hdr = overlay_format_used_hdr;
  314. }
  315. void UpdateMonitorInfo() {
  316. g_num_monitors = GetSystemMetrics(SM_CMONITORS);
  317. MONITORINFO monitor_info;
  318. monitor_info.cbSize = sizeof(monitor_info);
  319. if (GetMonitorInfo(MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY),
  320. &monitor_info)) {
  321. g_primary_monitor_size = gfx::Rect(monitor_info.rcMonitor).size();
  322. } else {
  323. g_primary_monitor_size = gfx::Size();
  324. }
  325. }
  326. } // namespace
  327. void InitializeDirectComposition(GLDisplayEGL* display) {
  328. DCHECK(!g_dcomp_device);
  329. if (base::CommandLine::ForCurrentProcess()->HasSwitch(
  330. switches::kDisableDirectComposition))
  331. return;
  332. // Direct composition can only be used with ANGLE.
  333. if (gl::GetGLImplementation() != gl::kGLImplementationEGLANGLE)
  334. return;
  335. // Blocklist direct composition if MCTU.dll or MCTUX.dll are injected. These
  336. // are user mode drivers for display adapters from Magic Control Technology
  337. // Corporation.
  338. if (GetModuleHandle(TEXT("MCTU.dll")) || GetModuleHandle(TEXT("MCTUX.dll"))) {
  339. DLOG(ERROR) << "Blocklisted due to third party modules";
  340. return;
  341. }
  342. // EGL_KHR_no_config_context surface compatibility is required to be able to
  343. // MakeCurrent with the default pbuffer surface.
  344. if (!display->ext->b_EGL_KHR_no_config_context) {
  345. DLOG(ERROR) << "EGL_KHR_no_config_context not supported";
  346. return;
  347. }
  348. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  349. QueryD3D11DeviceObjectFromANGLE();
  350. if (!d3d11_device) {
  351. DLOG(ERROR) << "Failed to retrieve D3D11 device";
  352. return;
  353. }
  354. // This will fail if the D3D device is "Microsoft Basic Display Adapter".
  355. Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device;
  356. if (FAILED(d3d11_device.As(&video_device))) {
  357. DLOG(ERROR) << "Failed to retrieve video device";
  358. return;
  359. }
  360. // Load DLL at runtime since older Windows versions don't have dcomp.
  361. HMODULE dcomp_module = ::GetModuleHandle(L"dcomp.dll");
  362. if (!dcomp_module) {
  363. DLOG(ERROR) << "Failed to load dcomp.dll";
  364. return;
  365. }
  366. using PFN_DCOMPOSITION_CREATE_DEVICE2 = HRESULT(WINAPI*)(
  367. IUnknown * renderingDevice, REFIID iid, void** dcompositionDevice);
  368. PFN_DCOMPOSITION_CREATE_DEVICE2 create_device_function =
  369. reinterpret_cast<PFN_DCOMPOSITION_CREATE_DEVICE2>(
  370. ::GetProcAddress(dcomp_module, "DCompositionCreateDevice2"));
  371. if (!create_device_function) {
  372. DLOG(ERROR) << "GetProcAddress failed for DCompositionCreateDevice2";
  373. return;
  374. }
  375. Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
  376. d3d11_device.As(&dxgi_device);
  377. Microsoft::WRL::ComPtr<IDCompositionDesktopDevice> desktop_device;
  378. HRESULT hr =
  379. create_device_function(dxgi_device.Get(), IID_PPV_ARGS(&desktop_device));
  380. if (FAILED(hr)) {
  381. DLOG(ERROR) << "DCompositionCreateDevice2 failed with error 0x" << std::hex
  382. << hr;
  383. return;
  384. }
  385. Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device;
  386. hr = desktop_device.As(&dcomp_device);
  387. if (FAILED(hr)) {
  388. DLOG(ERROR) << "Failed to retrieve IDCompositionDevice2 with error 0x"
  389. << std::hex << hr;
  390. return;
  391. }
  392. g_dcomp_device = dcomp_device.Detach();
  393. DCHECK(g_dcomp_device);
  394. }
  395. void ShutdownDirectComposition() {
  396. if (g_dcomp_device) {
  397. g_dcomp_device->Release();
  398. g_dcomp_device = nullptr;
  399. }
  400. }
  401. IDCompositionDevice2* GetDirectCompositionDevice() {
  402. return g_dcomp_device;
  403. }
  404. bool DirectCompositionSupported() {
  405. return g_dcomp_device && !g_direct_composition_swap_chain_failed;
  406. }
  407. bool DirectCompositionOverlaysSupported() {
  408. // Always initialize and record overlay support information irrespective of
  409. // command line flags.
  410. UpdateOverlaySupport();
  411. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  412. // Enable flag should be checked before the disable flag, so we could
  413. // overwrite GPU driver bug workarounds in testing.
  414. if (command_line->HasSwitch(switches::kEnableDirectCompositionVideoOverlays))
  415. return true;
  416. if (command_line->HasSwitch(switches::kDisableDirectCompositionVideoOverlays))
  417. return false;
  418. return SupportsOverlays();
  419. }
  420. bool DirectCompositionHardwareOverlaysSupported() {
  421. UpdateOverlaySupport();
  422. return SupportsHardwareOverlays();
  423. }
  424. bool DirectCompositionDecodeSwapChainSupported() {
  425. if (!g_decode_swap_chain_disabled) {
  426. UpdateOverlaySupport();
  427. return GetDirectCompositionSDROverlayFormat() == DXGI_FORMAT_NV12;
  428. }
  429. return false;
  430. }
  431. void DisableDirectCompositionDecodeSwapChain() {
  432. g_decode_swap_chain_disabled = true;
  433. }
  434. void DisableDirectCompositionOverlays() {
  435. SetSupportsOverlays(false);
  436. DirectCompositionOverlayCapsMonitor::GetInstance()
  437. ->NotifyOverlayCapsChanged();
  438. }
  439. void DisableDirectCompositionSoftwareOverlays() {
  440. g_disable_sw_overlays = true;
  441. }
  442. bool DirectCompositionScaledOverlaysSupported() {
  443. UpdateOverlaySupport();
  444. if (g_overlay_format_used == DXGI_FORMAT_NV12) {
  445. return (g_nv12_overlay_support_flags & DXGI_OVERLAY_SUPPORT_FLAG_SCALING) ||
  446. (SupportsOverlays() && SupportsSoftwareOverlays());
  447. } else if (g_overlay_format_used == DXGI_FORMAT_YUY2) {
  448. return !!(g_yuy2_overlay_support_flags & DXGI_OVERLAY_SUPPORT_FLAG_SCALING);
  449. } else {
  450. DCHECK_EQ(g_overlay_format_used, DXGI_FORMAT_B8G8R8A8_UNORM);
  451. // Assume scaling is supported for BGRA overlays.
  452. return true;
  453. }
  454. }
  455. UINT GetDirectCompositionOverlaySupportFlags(DXGI_FORMAT format) {
  456. UpdateOverlaySupport();
  457. base::AutoLock auto_lock(GetOverlayLock());
  458. UINT support_flag = 0;
  459. switch (format) {
  460. case DXGI_FORMAT_NV12:
  461. support_flag = g_nv12_overlay_support_flags;
  462. break;
  463. case DXGI_FORMAT_YUY2:
  464. support_flag = g_yuy2_overlay_support_flags;
  465. break;
  466. case DXGI_FORMAT_B8G8R8A8_UNORM:
  467. support_flag = g_bgra8_overlay_support_flags;
  468. break;
  469. case DXGI_FORMAT_R10G10B10A2_UNORM:
  470. support_flag = g_rgb10a2_overlay_support_flags;
  471. break;
  472. default:
  473. NOTREACHED();
  474. break;
  475. }
  476. return support_flag;
  477. }
  478. gfx::Size GetDirectCompositionPrimaryMonitorSize() {
  479. if (g_primary_monitor_size.IsEmpty())
  480. UpdateMonitorInfo();
  481. return g_primary_monitor_size;
  482. }
  483. int GetDirectCompositionNumMonitors() {
  484. if (g_num_monitors == 0)
  485. UpdateMonitorInfo();
  486. return g_num_monitors;
  487. }
  488. DXGI_FORMAT GetDirectCompositionSDROverlayFormat() {
  489. return g_overlay_format_used;
  490. }
  491. void SetDirectCompositionScaledOverlaysSupportedForTesting(bool supported) {
  492. UpdateOverlaySupport();
  493. if (supported) {
  494. g_nv12_overlay_support_flags |= DXGI_OVERLAY_SUPPORT_FLAG_SCALING;
  495. g_yuy2_overlay_support_flags |= DXGI_OVERLAY_SUPPORT_FLAG_SCALING;
  496. g_rgb10a2_overlay_support_flags |= DXGI_OVERLAY_SUPPORT_FLAG_SCALING;
  497. } else {
  498. g_nv12_overlay_support_flags &= ~DXGI_OVERLAY_SUPPORT_FLAG_SCALING;
  499. g_yuy2_overlay_support_flags &= ~DXGI_OVERLAY_SUPPORT_FLAG_SCALING;
  500. g_rgb10a2_overlay_support_flags &= ~DXGI_OVERLAY_SUPPORT_FLAG_SCALING;
  501. }
  502. g_disable_sw_overlays = !supported;
  503. SetSupportsHardwareOverlays(supported);
  504. DCHECK_EQ(supported, DirectCompositionScaledOverlaysSupported());
  505. }
  506. void SetDirectCompositionOverlayFormatUsedForTesting(DXGI_FORMAT format) {
  507. DCHECK(format == DXGI_FORMAT_NV12 || format == DXGI_FORMAT_YUY2 ||
  508. format == DXGI_FORMAT_B8G8R8A8_UNORM);
  509. UpdateOverlaySupport();
  510. g_overlay_format_used = format;
  511. DCHECK_EQ(format, GetDirectCompositionSDROverlayFormat());
  512. }
  513. gfx::mojom::DXGIInfoPtr GetDirectCompositionHDRMonitorDXGIInfo() {
  514. auto result_info = gfx::mojom::DXGIInfo::New();
  515. // HDR support was introduced in Windows 10 Creators Update.
  516. if (base::win::GetVersion() < base::win::Version::WIN10_RS2)
  517. return result_info;
  518. // Only direct composition surface can allocate HDR swap chains.
  519. if (!DirectCompositionSupported())
  520. return result_info;
  521. HRESULT hr = S_OK;
  522. Microsoft::WRL::ComPtr<IDXGIFactory1> factory;
  523. hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
  524. if (FAILED(hr)) {
  525. DLOG(ERROR) << "Failed to create DXGI factory.";
  526. return result_info;
  527. }
  528. bool hdr_monitor_found = false;
  529. for (UINT adapter_index = 0;; ++adapter_index) {
  530. Microsoft::WRL::ComPtr<IDXGIAdapter> adapter;
  531. hr = factory->EnumAdapters(adapter_index, &adapter);
  532. if (hr == DXGI_ERROR_NOT_FOUND)
  533. break;
  534. if (FAILED(hr)) {
  535. DLOG(ERROR) << "Unexpected error creating DXGI adapter.";
  536. break;
  537. }
  538. for (UINT output_index = 0;; ++output_index) {
  539. Microsoft::WRL::ComPtr<IDXGIOutput> output;
  540. hr = adapter->EnumOutputs(output_index, &output);
  541. if (hr == DXGI_ERROR_NOT_FOUND)
  542. break;
  543. if (FAILED(hr)) {
  544. DLOG(ERROR) << "Unexpected error creating DXGI adapter.";
  545. break;
  546. }
  547. Microsoft::WRL::ComPtr<IDXGIOutput6> output6;
  548. hr = output->QueryInterface(IID_PPV_ARGS(&output6));
  549. if (FAILED(hr)) {
  550. DLOG(WARNING) << "IDXGIOutput6 is required for HDR detection.";
  551. continue;
  552. }
  553. DXGI_OUTPUT_DESC1 desc;
  554. if (FAILED(output6->GetDesc1(&desc))) {
  555. DLOG(ERROR) << "Unexpected error getting output descriptor.";
  556. continue;
  557. }
  558. auto result_output = gfx::mojom::DXGIOutputDesc::New();
  559. result_output->device_name = desc.DeviceName;
  560. result_output->hdr_enabled =
  561. desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
  562. result_output->min_luminance = desc.MinLuminance;
  563. result_output->max_luminance = desc.MaxLuminance;
  564. result_output->max_full_frame_luminance = desc.MaxFullFrameLuminance;
  565. hdr_monitor_found |= result_output->hdr_enabled;
  566. result_info->output_descs.push_back(std::move(result_output));
  567. }
  568. }
  569. UMA_HISTOGRAM_BOOLEAN("GPU.Output.HDR", hdr_monitor_found);
  570. return result_info;
  571. }
  572. bool DXGISwapChainTearingSupported() {
  573. static const bool supported = [] {
  574. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  575. QueryD3D11DeviceObjectFromANGLE();
  576. if (!d3d11_device) {
  577. DLOG(ERROR) << "Not using swap chain tearing because failed to retrieve "
  578. "D3D11 device from ANGLE";
  579. return false;
  580. }
  581. Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
  582. d3d11_device.As(&dxgi_device);
  583. DCHECK(dxgi_device);
  584. Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
  585. dxgi_device->GetAdapter(&dxgi_adapter);
  586. DCHECK(dxgi_adapter);
  587. Microsoft::WRL::ComPtr<IDXGIFactory5> dxgi_factory;
  588. if (FAILED(dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)))) {
  589. DLOG(ERROR) << "Not using swap chain tearing because failed to retrieve "
  590. "IDXGIFactory5 interface";
  591. return false;
  592. }
  593. BOOL present_allow_tearing = FALSE;
  594. DCHECK(dxgi_factory);
  595. if (FAILED(dxgi_factory->CheckFeatureSupport(
  596. DXGI_FEATURE_PRESENT_ALLOW_TEARING, &present_allow_tearing,
  597. sizeof(present_allow_tearing)))) {
  598. DLOG(ERROR)
  599. << "Not using swap chain tearing because CheckFeatureSupport failed";
  600. return false;
  601. }
  602. return !!present_allow_tearing;
  603. }();
  604. return supported;
  605. }
  606. bool DirectCompositionSwapChainTearingEnabled() {
  607. return DXGISwapChainTearingSupported() && !features::UseGpuVsync();
  608. }
  609. void SetDirectCompositionOverlayWorkarounds(
  610. const DirectCompositionOverlayWorkarounds& workarounds) {
  611. // This has to be set before initializing overlay caps.
  612. DCHECK(!OverlayCapsValid());
  613. g_enable_bgra8_overlays_with_yuv_overlay_support =
  614. workarounds.enable_bgra8_overlays_with_yuv_overlay_support;
  615. g_force_nv12_overlay_support = workarounds.force_nv12_overlay_support;
  616. g_force_rgb10a2_overlay_support = workarounds.force_rgb10a2_overlay_support;
  617. g_check_ycbcr_studio_g22_left_p709_for_nv12_support =
  618. workarounds.check_ycbcr_studio_g22_left_p709_for_nv12_support;
  619. }
  620. void SetDirectCompositionSwapChainFailed() {
  621. if (!g_direct_composition_swap_chain_failed) {
  622. g_direct_composition_swap_chain_failed = true;
  623. DirectCompositionOverlayCapsMonitor::GetInstance()
  624. ->NotifyOverlayCapsChanged();
  625. }
  626. }
  627. void SetDirectCompositionMonitorInfoForTesting(
  628. int num_monitors,
  629. const gfx::Size& primary_monitor_size) {
  630. g_num_monitors = num_monitors;
  631. g_primary_monitor_size = primary_monitor_size;
  632. }
  633. // For DirectComposition Display Monitor.
  634. DirectCompositionOverlayCapsMonitor::DirectCompositionOverlayCapsMonitor()
  635. : observer_list_(new base::ObserverListThreadSafe<
  636. DirectCompositionOverlayCapsObserver>()) {
  637. ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
  638. }
  639. DirectCompositionOverlayCapsMonitor::~DirectCompositionOverlayCapsMonitor() {
  640. ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
  641. }
  642. // static
  643. DirectCompositionOverlayCapsMonitor*
  644. DirectCompositionOverlayCapsMonitor::GetInstance() {
  645. static base::NoDestructor<DirectCompositionOverlayCapsMonitor>
  646. direct_compoisition_overlay_cap_monitor;
  647. return direct_compoisition_overlay_cap_monitor.get();
  648. }
  649. void DirectCompositionOverlayCapsMonitor::AddObserver(
  650. DirectCompositionOverlayCapsObserver* observer) {
  651. observer_list_->AddObserver(observer);
  652. }
  653. void DirectCompositionOverlayCapsMonitor::RemoveObserver(
  654. DirectCompositionOverlayCapsObserver* observer) {
  655. observer_list_->RemoveObserver(observer);
  656. }
  657. void DirectCompositionOverlayCapsMonitor::NotifyOverlayCapsChanged() {
  658. observer_list_->Notify(
  659. FROM_HERE, &DirectCompositionOverlayCapsObserver::OnOverlayCapsChanged);
  660. }
  661. // Called from GpuSwitchingObserver on the GPU main thread.
  662. void DirectCompositionOverlayCapsMonitor::OnGpuSwitched(
  663. gl::GpuPreference active_gpu_heuristic) {}
  664. // Called from GpuSwitchingObserver on the GPU main thread.
  665. void DirectCompositionOverlayCapsMonitor::OnDisplayAdded() {
  666. SetOverlayCapsValid(false);
  667. UpdateOverlaySupport();
  668. UpdateMonitorInfo();
  669. NotifyOverlayCapsChanged();
  670. }
  671. // Called from GpuSwitchingObserver on the GPU main thread.
  672. void DirectCompositionOverlayCapsMonitor::OnDisplayRemoved() {
  673. SetOverlayCapsValid(false);
  674. UpdateOverlaySupport();
  675. UpdateMonitorInfo();
  676. NotifyOverlayCapsChanged();
  677. }
  678. // Called from GpuSwitchingObserver on the GPU main thread.
  679. void DirectCompositionOverlayCapsMonitor::OnDisplayMetricsChanged() {
  680. UpdateMonitorInfo();
  681. }
  682. } // namespace gl