为了获得最佳性能,请使用 DXGI 翻转模型

本主题提供有关如何在新式Windows的演示文稿堆栈中最大程度地提高性能和效率的开发人员指南。 它会选取 DXGI 翻转模型DirectX 12:Windows 10 (视频) 中的演示模式Windows 10中的演示增强功能:早期外观 (视频) 离开的位置。

行动号召

如果仍在使用 DXGI_SWAP_EFFECT_DISCARDDXGI_SWAP_EFFECT_SEQUENTIAL ( a.k.a. “blt”演示模型) ,是时候停止了!

切换到 DXGI_SWAP_EFFECT_FLIP_SEQUENTIALDXGI_SWAP_EFFECT_FLIP_DISCARD ( a.k.a. 翻转模型) 将提供更好的性能,降低功率,并提供更丰富的功能集。 (有关这些值的详细信息,请参阅 DXGI_SWAP_EFFECT枚举 。)

与经典“全屏独占”模式相比,翻转模型可以有效地使窗口模式等效或更好。 事实上,你可能希望重新考虑应用程序是否实际需要全屏独占模式,因为翻转模型无边框窗口的优点包括更快的Alt-Tab切换和更好地与新式显示功能的集成。

为什么是现在? 在 2018 年 4 月更新之前,blt 模型呈现可能会导致在混合 GPU 配置上使用时可见撕裂,通常在高端笔记本电脑中找到, (看到 KB 3158621) 。 在 2018 年 4 月的更新中,这种撕裂已被修复,代价是一些额外的工作。 如果在混合 GPU 中执行高帧速率演示,尤其是在高分辨率(如 4K)时,此额外工作可能会影响整体性能。 若要在这些系统上保持最佳性能,请从 blt 切换到翻转演示模型。 此外,请考虑减少交换链的分辨率,尤其是在用户交互的主要点 (与 VR 预览窗口) 的情况一样。

简要历史记录

什么是翻转模型? 什么是替代方法?

在Windows 7 之前,显示 D3D 中内容的唯一方法是“blt”或将其复制到窗口或屏幕拥有的图面中。 从 D3D9 的 FLIPEX 交换效果开始,并通过Windows 8中的FLIP_SEQUENTIAL交换效果来到 DXGI,我们开发了一种更高效的方法,通过直接与桌面合成器共享内容,以最少的副本将其放在屏幕上。 有关技术的高级概述,请参阅 DXGI 翻转模型

由于 DWM (桌面窗口管理器) ,这是驱动Windows桌面的合成器,因此可以实现此优化。

何时应使用 blt 模型?

翻转模型不提供一项功能:能够生成多个不同的 API,这些 API 在当前的基础上将所有层组合到同一 HWND 中。 例如,使用 D3D 绘制窗口背景,然后Windows GDI 在顶部绘制内容,或使用同一 API 中的两个不同的图形 API 或两个交换链生成交替帧。 如果不需要图形组件之间的 HWND 级互操作,则不需要 blt 模型。

原始翻转模型设计中没有提供第二个功能,但现在可用,这是在不受限制的帧速率中呈现的功能。 对于使用同步间隔 0 的应用程序,建议不要切换到翻转模型,除非 IDXGIFactory5::CheckFeatureSupport API 可用,并且报告对 DXGI_FEATURE_PRESENT_ALLOW_TEARING的支持。 此功能在最新版本的Windows 10和现代硬件上几乎无处不在。

DirectFlip

如果观看了 DirectX 12:Windows 10中的演示模式,你将看到“直接翻转”和“独立翻转”。这些是使用翻转模型交换链为应用程序启用的优化。 根据窗口和缓冲区配置,可以完全绕过桌面合成,并直接将应用程序帧发送到屏幕,就像独占全屏一样。

这些天来,这些优化可以参与 3 种方案之一,以增加功能:

  1. DirectFlip:交换链缓冲区与屏幕尺寸匹配,窗口客户端区域覆盖屏幕。 不使用 DWM 交换链在屏幕上显示,而是使用应用程序交换链。
  2. DirectFlip 与面板拟合器:窗口客户端区域覆盖屏幕,交换链缓冲区位于一些依赖于硬件的缩放因子 (中,例如,屏幕的 0.25x 到 4 倍) 。 GPU 扫描硬件用于在将缓冲区发送到显示器时缩放缓冲区。
  3. 具有多平面覆盖的 DirectFlip (MPO) :交换链缓冲区位于窗口维度的某些依赖于硬件的缩放因子内。 DWM 可以保留应用程序的专用硬件扫描平面,然后扫描出来,并可能拉伸到屏幕的 alpha 混合子区域。

使用窗口翻转模型,应用程序可以通过 IDXGIOutput6::CheckHardwareCompositionSupport 查询不同 DirectFlip 方案的硬件支持,并实现不同类型的动态缩放。 需要注意的一个注意事项是,如果利用面板拟合器,光标可能会遭受拉伸副作用,这通过 DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_CURSOR_STRETCHED指示。

交换链“DirectFlipped”后,DWM 可以进入睡眠状态,并且仅在应用程序外部发生更改时唤醒。 应用程序帧将直接发送到屏幕,其效率与全屏独占相同。 这是“独立翻转”,可以参与上述所有方案。 如果其他桌面内容位于顶部,DWM 可以无缝地转换回撰写模式,在翻转应用程序之前有效地“反向撰写”应用程序顶部的内容,或者利用 MPO 维护独立的翻转模式。

查看 PresentMon 工具,深入了解使用了上述内容。

翻转模型中还有什么新增功能?

除了上述改进适用于标准交换链,没有任何特殊之处,还有几种功能可用于翻转模型应用程序使用:

  • 使用 DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT 减少延迟。 在独立翻转模式下,可以在最新版本的 Windows 上降低到 1 帧的延迟,在撰写时可以正常回退到最小延迟。
    • 注意:在Windows 10周年更新和更早版本中,存在至少两帧延迟的问题。 有关详细信息,请参阅 此论坛主题 。 在 Fall Creator 的更新中修复了此问题。
  • DXGI_SWAP_EFFECT_FLIP_DISCARD 启用直接翻转的“反向组合”模式,这会导致显示桌面的整体工作较少。 DWM 可以在应用程序缓冲区上进行涂鸦,并将其发送到屏幕,而不是在自己的交换链中执行完整副本。
  • DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING 可以启用比可等待对象更低的延迟,即使在具有多平面覆盖支持的系统上的窗口中也是如此。
  • 应用程序可以使用交换链创建期间设置 DXGI_SCALING 属性控制窗口大小期间发生的内容缩放。
  • 除非将内容组合到 SDR 桌面,否则不会固定 HDR 格式 (R10G10B10A2_UNORM或R16G16B16A16_FLOAT) 。
  • 当前统计信息在开窗模式下可用。
  • 与 UWP (通用 Windows 平台) 应用程序模型和 DX12 的兼容性更大,因为这些模型仅与翻转模型兼容。

我必须执行哪些操作才能使用翻转模型?

翻转模型交换链在 blt 交换链的基础上有一些附加要求:

  1. 缓冲区计数必须至少为 2。
  2. 在当前调用后,后台缓冲区需要显式重新绑定到 D3D11 即时上下文,然后才能再次使用它。
  3. 调用 SetFullscreenState 后,应用程序必须在 Present 之前调用 ResizeBuffers
  4. 在翻转模型中,MSAA (多采样反别名) 交换链不受直接支持,因此应用程序需要在发出 Present 之前执行 MSAA 解析。

如何选择正确的呈现和演示文稿分辨率

过去应用程序的传统模式是为用户提供一系列解决方案,以便在用户选择独占全屏模式时从中进行选择。 借助新式显示器无缝开始缩放内容的功能,请考虑让用户能够选择呈现分辨率以实现性能缩放,与输出分辨率无关,甚至处于窗口模式。 此外,应用程序应利用 IDXGIOutput6::CheckHardwareCompositionSupport 来确定它们是否需要在呈现内容之前缩放内容,或者它们是否应让硬件为其执行缩放。

内容可能需要从一个 GPU 迁移到另一个 GPU,作为当前或合成操作的一部分。 这通常适用于多 GPU 笔记本电脑,或者插入了外部 GPU 的系统。 随着这些配置变得更加常见,并且高分辨率显示器变得更加常见,呈现完整分辨率交换链的成本将增加。 如果交换链的目标不是用户交互的主要点,与将 VR 场景的 2D 预览呈现到辅助窗口中的 VR 游戏一样,请考虑使用较低的分辨率交换链来最大程度地减少需要跨不同 GPU 传输的带宽量。

其他注意事项

首次要求 GPU 写入交换链后缓冲区是 GPU 停止等待缓冲区可用的时间。 如果可能,请将此点尽可能延迟到帧中。