我有一个Win32非游戏窗口应用程序,它使用Direct2D设备上下文/ HWND渲染目标来绘制窗口。当前,它使用具有DXGI_SWAP_EFFECT_DISCARD
交换效果的DXGI交换链。
Microsoft recommends使用新的翻转模型交换效果,DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
或DXGI_SWAP_EFFECT_FLIP_DISCARD
。我对使用它们很感兴趣,主要是因为它们允许我在调用Present1()
时指定一个脏矩形列表,这将改善性能/功耗。
仅将SwapEffect
更改为新的翻转模型值中的任何一个都会产生奇怪的(但实际上是预期的)结果,即每第二帧绘制一个黑色窗口,并且先前帧的伪像在屏幕上可见。
所以问题是:在这种情况下是否可以使用新的翻转模型交换效果,如果可以,应该如何设置?
[鉴于应用程序需要将脏矩形绘制到其他有效缓冲区中,看来正确的方法将包括维护两个内容基本相同的缓冲区(一个用于绘制,一个用于提供给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的DXGI_SWAP_EFFECT
也说,UWP应用被强制进入了翻转模型,因此这应该是一个可解决的问题。
有两种好的方法。
第一种方法是在能源使用上增加一些。您可以将内容绘制到中间缓冲区/渲染纹理中,然后在每次出现之前将其复制到swapchain。这样,您实际上只能渲染中间缓冲区中已更改的部分,而不必关心交换链的状态是什么。
第二种方法更复杂,但可以产生最佳的能源使用。您可以直接绘制到交换链缓冲区中,而不是使用中间缓冲区并仅绘制自上一帧以来的变化。为了使它正常工作,您不需要重绘当前帧和最后一帧之间的变化,而是重绘当前帧与(当前-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)。
[如果缓冲区数为2,这意味着绘制第3帧时,不仅需要重新绘制(225,225,50,50)的脏区域,而且还需要重新绘制(250,250,300, 300)。