这篇文章最初发表在 NVIDIA 技术博客上。
交换链是如何将渲染数据输出到屏幕的不可或缺的一部分。它们通常由一组输出就绪型缓冲区组成,每个缓冲区都可以旋转渲染为一个缓冲区。在渲染到交换链的某个缓冲区的同时,交换链中的其他缓冲区通常被读取以进行显示输出。
本文介绍了在 NVIDIA GPU 上使用交换链时的最佳实践。要在您的应用中获得稳定的高帧率,请参阅我们的 高级 API 性能提示。
在寻求提高渲染性能时,通常会专注于渲染管线中更频繁优化的部分。但是,交换链通常会被忽略,从而将潜在性能和延迟放在桌面上。
以下建议和注意事项可让您更深入地了解确保最佳交换链性能的最佳方法。
推荐
- 使用翻转模式交换链。这对于利用多平面叠加支持尤为重要,因为在窗口模式下运行时,多平面叠加支持可提供全屏性能和延迟。
- 使用
SetFullScreenState(TRUE)
(无边框)全屏窗口和非窗口翻转模型交换链,可切换到真正的即时独立翻转模式。- 这是唯一支持无限帧速率的模式,在调用 Direct 3D 12 时,该模式会导致 Direct 3D 12 出现撕裂,
Present(0,0)
. - 如需为支持可变刷新率的显示器提供适当的无限帧率支持,您还必须使用
DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING
交换链标志,以及DXGI_PRESENT_ALLOW_TEARING
Present
标志
- 这是唯一支持无限帧速率的模式,在调用 Direct 3D 12 时,该模式会导致 Direct 3D 12 出现撕裂,
- 使用
DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
会有意识地显示出来。- 如果窗口大小与当前屏幕分辨率相匹配,则无需使用该标志即可实现无限帧率(请参阅前面的注释)
- 如果设置了此标志,请尝试使用 ResizeTarget 更改分辨率,然后再调用
SetFullScreenState(TRUE)
工作正常,帧速率将无限 - 如果未设置此标志,请尝试使用
ResizeTarget
然后再调用SetFullScreenState(TRUE)
不会导致显示分辨率发生变化。您的目标已扩展到当前分辨率,且帧率受限。
- 如果不处于全屏状态(真正的即时独立翻转模式),请仔细控制交换链中的延迟和缓冲区数量,以获得所需的帧速率和延迟。
- 使用
IDXGISwapChain2::SetMaximumFrameLatency(MaxLatency)
来设置所需的延迟,MaxLatency
是一定数量的帧(按队列中的帧数计算)Present
调用)。 - 要做到这一点,您必须使用
DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
设置的标志。 - DXGI 开始阻塞
Present
在您拥有MaxLatency
当前调用的数量。 - 在此窗口状态下,同步间隔为 0
Present
call 可确保所呈现的帧是可供下次进行桌面合成时使用的最新帧(将窗口渲染的帧与桌面的其余部分结合使用),并且丢弃之前完成的所有帧,转而使用最新的帧。在合成发生之前不会显示任何渲染帧,这发生在VSYNC
时间。这个最新完成的帧是所显示的
- 使用
- 使用的交换链缓冲区比打算排队的最大帧数多约 1-2 倍(就命令分配器、动态数据和关联的帧围栏而言)。通过将最大帧延迟设置为交换链缓冲区的这个数量,
IDXGISwapChain2::SetMaximumFrameLatency(MaxLatency)
.- 这可确保您可以从应用程序逻辑中以最佳方式明确限制队列中的帧和延迟,而不是依靠操作系统在意外的时间阻止或阻止它。
不推荐
- 忘记了这一点,默认情况下,在 DXGI 开始阻塞之前,每个交换链限制为三个排队帧
Present
.这意味着,如果当前有三个 Present 调用,它将在第四次 Present 调用中阻塞Present
呼叫排队。- 设置
DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
交换链创建和使用的标志IDXGISwapChain2::SetMaximumFrameLatency
来修改此默认值,
- 设置
- 忘记通话
ResizeBuffers
切换到真正的即时独立翻转模式后,SetFullScreenState(TRUE)
.
致谢
感谢 Cody Robson、Kumaresan Gnanasekaran、Adrian Muntianu 和 Meenal Nachnani 提供的建议和帮助。