如何在 Direct2D 窗口应用程序中使用 DXGI 翻转模型?

How to use the DXGI flip model in a Direct2D windowed app?

我有一个 Win32 非游戏 windowed 应用程序,它使用 Direct2D 设备 context/HWND 渲染目标来绘制 window。目前它使用具有 DXGI_SWAP_EFFECT_DISCARD 交换效果的 DXGI 交换链。

Microsoft recommends 使用新的翻转模型交换效果,DXGI_SWAP_EFFECT_FLIP_SEQUENTIALDXGI_SWAP_EFFECT_FLIP_DISCARD。我对使用它们很感兴趣,主要是因为它们允许我在调用 Present1() 时指定一个脏矩形列表,这应该会提高 performance/power 的使用率。

简单地将 SwapEffect 更改为任一新的翻转模型值会产生一个奇怪的(但实际上是预期的)结果,即每秒绘制一个黑色 window,并且可以看到之前帧的伪像在屏幕上。

所以问题是:在这种情况下是否可以使用新的翻转模型交换效果,如果可以,应该如何设置

考虑到应用程序需要将脏矩形绘制到一个有效的缓冲区中,似乎正确的方法是维护两个内容基本相同的缓冲区(一个绘制,一个提供给 DWM用于组合),因此不确定是否有可能在不完全重绘每一帧的应用程序中以这种方式实现任何性能提升。但也许我遗漏了一些重要的东西。

交换链目前设置如下:

swapChainDesc.Width = ...;
swapChainDesc.Height = ...;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapChainDesc.Flags = 0;

编辑 1

原来 DXGI_SWAP_EFFECT_DISCARD 强制 BufferCount 为 1,所以我的初始值 2 有点误导,因为只使用了一个缓冲区。 Source (3rd comment).

还有the docs for DXGI_SWAP_EFFECT 说UWP 应用程序被强制进入翻转模式,所以这应该是一个可以解决的问题。

有两种好方法。

第一种方式在能源使用上有点重。您可以将您的内容绘制到中间 buffer/render 纹理中,并在每次呈现之前将其复制到交换链。这样,您实际上只能渲染中间缓冲区中发生变化的部分,而不用关心交换链的状态。

第二种方式更复杂,但可以产生最佳的能量使用。您无需使用中间缓冲区并仅绘制自上一帧以来发生的变化,而是直接绘制到交换链缓冲区中。为了使其正常工作,您需要重绘的不是当前帧和上一帧之间的变化,而是当前帧和(当前 - BufferCount)帧之间的变化。例如:

第 1 帧 - 您在 (200 x 200) 处绘制了一个尺寸为 (150 x 150) 的绿色矩形。脏区是整个帧,因为它是第一帧。

第 2 帧 - 您在 (250 x 250) 处绘制了一个尺寸为 (50 x 50) 的蓝色矩形。脏区是 (250, 250, 300, 300).

第 3 帧 - 您在 (225 x 225) 处绘制了一个尺寸为 (50 x 50) 的红色矩形。脏区是 (225, 225, 50, 50).

如果你的buffer count是2,那就意味着当你绘制第3帧时,你不仅需要重绘(225, 225, 50, 50)的脏区域,还需要重绘(250, 250)的脏区域, 300, 300).