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

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

行动号召

如果仍在使用 DXGI_SWAP_EFFECT_DISCARDDXGI_SWAP_EFFECT_SEQUENTIAL (即“blt”当前模型) ,是时候停止了!

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

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

为什么是现在? 在 2018 年 4 月更新之前,blt 模型呈现在混合 GPU 配置上使用时可能会导致可见撕裂,通常出现在高端笔记本电脑中, (看到 KB 3158621) 。 在 2018 年 4 月更新中,这种撕裂已修复,但代价是一些额外的工作。 如果跨混合 GPU(尤其是在 4K 等高分辨率下)执行 blt 演示,则此额外工作可能会影响整体性能。 若要在这些系统上保持最佳性能,请从 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:演示文稿模式 in Windows 10,你将看到谈论“直接翻转”和“独立翻转”。这些是针对使用翻转模型交换链的应用程序启用的优化。 根据窗口和缓冲区配置,可以完全绕过桌面组合,并直接将应用程序帧发送到屏幕,其方式与独占全屏相同。

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

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

使用窗口翻转模型,应用程序可以查询不同 DirectFlip 方案的硬件支持,并通过使用 IDXGIOutput6::CheckHardwareCompositionSupport 实现不同类型的动态缩放。 需要记住的一个注意事项是,如果使用面板安装器,光标可能会遭受拉伸副作用,这是通过 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 属性来控制窗口大小期间发生的内容缩放。
  • HDR 格式 (R10G10B10A2_UNORM或R16G16B16A16_FLOAT) 的内容不会被固定,除非它已组合到 SDR 桌面。
  • 当前统计信息在窗口模式下可用。
  • UWP (通用 Windows 平台) 应用程序模型和 DX12 具有更高的兼容性,因为它们仅与翻转模型兼容。

使用翻转模型需要执行什么操作?

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

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

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

过去,应用程序的传统模式是为用户提供一个分辨率列表,当用户选择独占全屏模式时可供选择。 借助新式显示器无缝开始缩放内容的功能,请考虑为用户提供独立于输出分辨率,甚至在窗口模式下选择性能缩放的呈现分辨率。 此外,应用程序应利用 IDXGIOutput6::CheckHardwareCompositionSupport 来确定它们是否需要在呈现内容之前缩放内容,或者是否应该让硬件为其执行缩放。

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

其他注意事项

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