为了获得最佳性能,请使用 DXGI 翻转模型
本主题提供有关如何在新式 Windows 上的演示文稿堆栈中最大程度地提高性能和效率的开发人员指南。 它会选取 DXGI 翻转模型的位置,DirectX 12:Windows 10 中的演示模式(视频),Windows 10 中的演示增强功能:早期外观(视频) 关闭。
行动号召
如果仍在使用 DXGI_SWAP_EFFECT_DISCARD 或 DXGI_SWAP_EFFECT_SEQUENTIAL(即“blt”演示模型),是时候停止了!
切换到 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL 或 DXGI_SWAP_EFFECT_FLIP_DISCARD(a.k.a.翻转模型)将提供更好的性能、更低的功率使用,并提供更丰富的功能集。 (有关这些值的详细信息,请参阅 DXGI_SWAP_EFFECT 枚举。
与经典“全屏独占”模式相比,翻转模型可以有效地使窗口模式等效或更好。 事实上,你可能希望重新考虑应用程序是否确实需要全屏独占模式,因为翻转模型无边框窗口的优点包括更快的 Alt-Tab 切换和更好地与新式显示功能的集成。
为什么现在? 在 2018 年 4 月更新之前,blt 模型呈现可能会导致在混合 GPU 配置上使用时可见撕裂,通常位于高端笔记本电脑(请参阅 KB 3158621)。 在 2018 年 4 月的更新中,这种撕裂已被修复,但代价是一些额外的工作。 如果在混合 GPU 中执行 blt 以高帧速率呈现,尤其是在高分辨率(如 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 种方案之一,以增加功能的顺序:
- DirectFlip:交换链缓冲区与屏幕尺寸匹配,窗口客户端区域覆盖屏幕。 不使用 DWM 交换链在屏幕上显示,而是使用应用程序交换链。
- 带有面板安装器的 DirectFlip:窗口客户端区域覆盖屏幕,交换链缓冲区位于屏幕的某些依赖硬件的缩放因子(例如,0.25x 到 4x)内。 GPU 扫描硬件用于在将缓冲区发送到显示器时缩放缓冲区。
- 具有多平面覆盖(MPO)的 DirectFlip:交换链缓冲区位于窗口维度的某些依赖于硬件的缩放因子内。 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 帧的延迟,在撰写时可以正常回退到最小延迟。
- DXGI_SWAP_EFFECT_FLIP_DISCARD 启用直接翻转的“反向组合”模式,这会导致显示桌面的整体工作较少。 DWM 可以在应用程序缓冲区上进行涂鸦,并将其发送到屏幕,而不是将完整副本复制到自己的交换链中。
- DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING 可以启用比可等待对象更低的延迟,即使在支持多平面覆盖的系统上的窗口中也是如此。
- 应用程序可以使用交换链创建期间设置 DXGI_SCALING 属性来控制窗口大小期间发生的内容缩放。
- HDR 格式(R10G10B10A2_UNORM或R16G16B16A16_FLOAT)的内容不会被固定,除非它由 SDR 桌面组成。
- 当前统计信息在开窗模式下可用。
- 与 UWP(通用 Windows 平台)应用程序模型和 DX12 的兼容性更高,因为这些模型仅与翻转模型兼容。
我必须做什么才能使用翻转模型?
翻转模型交换链在 blt 交换链的基础上有一些附加要求:
- 缓冲区计数必须至少为 2。
- 呈现 调用后,后台缓冲区需要显式绑定到 D3D11 即时上下文,然后才能再次使用它。
- 调用 setFullscreenState 后,应用程序必须在 演示之前调用 resizeBuffers 。
- 翻转模型中不支持 MSAA (多采样抗锯齿)交换链,因此应用程序需要在发出 演示之前执行 MSAA 解析。
如何选择正确的呈现和演示文稿分辨率
过去应用程序的传统模式是为用户提供分辨率列表,以便在用户选择独占全屏模式时从中进行选择。 借助新式显示器无缝开始缩放内容的功能,请考虑为用户提供选择性能缩放的呈现分辨率(独立于输出分辨率,甚至在开窗模式下)。 此外,应用程序应利用 IDXGIOutput6::CheckHardwareCompositionSupport 来确定它们是否需要在呈现内容之前缩放内容,或者它们是否应让硬件为其执行缩放。
内容可能需要从一个 GPU 迁移到另一个 GPU 作为当前或组合作的一部分。 这通常适用于多 GPU 笔记本电脑,或者插入了外部 GPU 的系统。 随着这些配置变得更加常见,随着高分辨率显示器变得越来越常见,呈现完整分辨率交换链的成本会增加。 如果交换链的目标不是用户交互的主要点,通常与将 VR 场景的 2D 预览呈现到辅助窗口中的 VR 游戏的情况一样,请考虑使用较低的分辨率交换链来最大程度地减少需要跨不同 GPU 传输的带宽量。
其他注意事项
首次要求 GPU 写入交换链后缓冲区时,GPU 将停止等待缓冲区可用。 如果可能,请将此点尽可能延迟到帧中。