简体   繁体   English

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

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

I have a Win32 non-game windowed app that uses a Direct2D device context/HWND render target to draw a window.我有一个 Win32 非游戏窗口应用程序,它使用 Direct2D 设备上下文/HWND 渲染目标来绘制窗口。 Currently it uses a DXGI swap chain with the DXGI_SWAP_EFFECT_DISCARD swap effect.目前它使用具有DXGI_SWAP_EFFECT_DISCARD交换效果的 DXGI 交换链。

Microsoft recommends using the new flip model swap effects, either DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL or DXGI_SWAP_EFFECT_FLIP_DISCARD . Microsoft 建议使用新的翻转模型交换效果, DXGI_SWAP_EFFECT_FLIP_SEQUENTIALDXGI_SWAP_EFFECT_FLIP_DISCARD I'm interested in using them primarily because they would allow me to specify a list of dirty rects when calling Present1() , which should improve performance/power usage.我对使用它们很感兴趣,主要是因为它们允许我在调用Present1()时指定一个脏Present1()列表,这应该可以提高性能/功耗。

Simply changing the SwapEffect to either of the new flip model values produces a weird (but actually expected) result of drawing a black window each second frame, with artifacts of the previous frames visible onscreen.简单地将SwapEffect更改为任一新的翻转模型值会产生一个奇怪的(但实际上是预期的)结果,即每第二帧绘制一个黑色窗口,屏幕上可以看到前一帧的伪影。

So the question is: is it possible to use the new flip model swap effects in this situation, and if yes, how should things be set up ?所以问题是:在这种情况下是否可以使用新的翻转模型交换效果,如果是,应该如何设置

Given that the app needs to draw the dirty rects into an otherwise valid buffer, it seems that a correct approach would involve maintaining two buffers with essentially the same content (one to draw into, and one to give to the DWM for composition), so not sure if it would be possible to achieve any performance gains this way in an app that doesn't redraw each frame completely.鉴于应用程序需要将脏矩形绘制到其他有效的缓冲区中,似乎正确的方法是维护两个具有基本相同内容的缓冲区(一个用于绘制,另一个用于 DWM 进行合成),因此不确定在不完全重绘每一帧的应用程序中是否可以通过这种方式实现任何性能提升。 But perhaps I'm missing something important.但也许我错过了一些重要的东西。

The swap chain is currently set up as follows:交换链目前设置如下:

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;

EDIT 1编辑 1

It turns out that DXGI_SWAP_EFFECT_DISCARD forces BufferCount to 1, so my initial value of 2 was somewhat misleading, as only one buffer is used.事实证明DXGI_SWAP_EFFECT_DISCARD强制BufferCount为 1,所以我的初始值 2 有点误导,因为只使用了一个缓冲区。 Source (3rd comment). 来源(第三条评论)。

Also the docs for DXGI_SWAP_EFFECT say that UWP apps are forced into the flip model, so this should be a solvable problem. DXGI_SWAP_EFFECT 的文档DXGI_SWAP_EFFECT说 UWP 应用程序被强制进入翻转模型,所以这应该是一个可以解决的问题。

There are two good ways to do it.有两种好方法可以做到。

The first way is a little heavier on energy usage.第一种方式在能源使用上稍重。 You can draw your contents into an intermediate buffer/render texture, and copy it to swapchain just before every present.您可以将内容绘制到中间缓冲区/渲染纹理中,并在每次出现之前将其复制到交换链。 That way you can only actually render the parts that changed in your intermediate buffer, and not care about what the state of the swapchain is.这样,您实际上只能渲染中间缓冲区中发生更改的部分,而不必关心交换链的状态。

The second way is more complicated, but can yield optimal energy usage.第二种方式更复杂,但可以产生最佳的能源使用。 Instead of using intermediate buffer and drawing only what changes since the last frame there, you draw directly into the swapchain buffer.不是使用中间缓冲区并只绘制自上一帧以来发生的变化,而是直接绘制到交换链缓冲区中。 For this to work correctly, you need to redraw not what changes between current and last frame, but between current and (current - BufferCount) frame.为了使其正常工作,您需要重绘的不是当前帧和上一帧之间的变化,而是当前帧和(当前 - BufferCount)帧之间的变化。 For instance:例如:

Frame 1 - you draw a green rectancle at (200 x 200) with dimensions of (150 x 150).第 1 帧 - 您在 (200 x 200) 处绘制一个尺寸为 (150 x 150) 的绿色矩形。 The dirty region is entire frame because it's the first frame.脏区是整个帧,因为它是第一帧。

Frame 2 - you draw a blue rectangle at (250 x 250) with dimensions of (50 x 50).第 2 帧 - 在 (250 x 250) 处绘制一个尺寸为 (50 x 50) 的蓝色矩形。 The dirty region is (250, 250, 300, 300).脏区是 (250, 250, 300, 300)。

Frame 3 - you draw a red rectangle at (225 x 225) with dimensions of (50 x 50).第 3 帧 - 在 (225 x 225) 处绘制一个尺寸为 (50 x 50) 的红色矩形。 The dirty region is (225, 225, 50, 50).脏区是 (225, 225, 50, 50)。

If your buffer count is 2, that means when you draw frame 3, you need to not only redraw the dirty region of (225, 225, 50, 50), but also the dirty region of (250, 250, 300, 300).如果你的buffer count是2,那意味着你在绘制第3帧时,不仅需要重绘(225, 225, 50, 50)的脏区,还要重绘(250, 250, 300, 300)的脏区.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM