Glitches with flip model swap chain

Started by
8 comments, last by ciel123 7 years, 4 months ago

I have a program where I used a bitblt model swap chain (DXGI_SWAP_EFFECT_DISCARD, the default used by most samples), and it worked fine.

But now I want to use a flip model swap chain (DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL), and I'm getting some glitches. Basically, it keeps rendering a pair (2) of old frames over and over, and the two frames only get updated at random times. (Unfortunately, posting a screenshot wouldn't help because it only shows a normal frame.)

I've tried just about every relevant combination of the two parameters for IDXGISwapChain::Present, particularly with the flags DXGI_PRESENT_RESTART and DXGI_PRESENT_DO_NOT_SEQUENCE, but nothing changes.

If it matters, the program also uses Direct2D. I did see this MSDN page ( https://msdn.microsoft.com/en-us/library/windows/desktop/hh706346(v=vs.85).aspx ), which says "Use flip model in an HWND that is not also targeted by other APIs, including DXGI bitblt presentation model, other versions of Direct3D, or GDI." But it doesn't mention Direct2D, so I'm not sure if this could be the problem.

A couple of other points:

- I create the swap chain with two buffers, as the debug layer told me to.

- Direct3D 11.1, Windows 8.1, Visual Studio 2013

Advertisement

Are you re-binding your swapchain back buffers? That's the big difference between DISCARD and FLIP_SEQUENTIAL - if your back buffer was bound as a render target when you call Present, it gets unbound and you need to re-bind it.

I did read about that but, how do I rebind them? The back buffers are not being used with an ID3D11RenderTargetView, but with an ID2D1RenderTarget, so I can't use ID3D11DeviceContext::OMSetRenderTargets to bind it. Sorry if it's a silly question, I'm still learning.

Got it, so you're only using D2D. I assumed D3D + D2D.

Are you calling ID2D1RenderTarget::EndDraw() every frame? If not, you'd switch back and forth between the last two frames that actually drew, until a flush was triggered - somewhat randomly.

Well I'm using D2D to do all the drawing but I do create a D3D device and swap chain (for now just to set fullscreen mode). The D2D render target is created with ID2D1Factory::CreateDxgiSurfaceRenderTarget, which indeed binds it to the swap chain's back buffer. But I can't find any method to rebind it like you can with D3D render target views and OMSetRenderTargets.

About the EndDraw call, yes I call it. My render method looks basically like this:


void Render()
{
    m_pRenderTarget->BeginDraw();
    m_pRenderTarget->Clear(m_backgroundColor);

    // ... draw calls here ...

    HRESULT hr = m_pRenderTarget->EndDraw();
    ThrowIfFailed(hr);

    hr = m_pSwapChain->Present(0, 0);
    ThrowIfFailed(hr);
}

I think I solved it. Apparently the glitch was caused because sometimes I only drew part of the window. If I always draw the entire window (starting with a ID2D1RenderTarget::Clear call), it works fine. I guess with a flip model swap chain, I always have to draw the entire window?

There's still another issue. The program has a menu bar, but any coordinates I pass to D2D draw calls are being treated as relative to the window's client area (as if the window didn't have a menu bar). It doesn't draw on top of the menu bar, but rather, the menu bar obstructs whatever is drawn below it. This doesn't happen with the DXGI_SWAP_EFFECT_DISCARD swap chain.

The easy solution is to create the swap chain with the height of the window's client area (not including the height of the menu bar), and position it below the menu bar. Is there a way to do the latter (reposition the swap chain, or the swap chain's back buffers)?

For your first problem, you'd have that issue anytime you have multiple buffers in your swapchain, such as a regular SEQUENTIAL swapchain with 2 buffers or a fullscreen DISCARD swapchain. Additionally, you can't rely on a DISCARD swapchain preserving its contents - the DISCARD implies they may have been discarded.

As an alternative workaround for that, you can use partial presentation. See this article on DXGI_PRESENT_PARAMETERS.

For the menu bar issue, this is a difference between the blt models (DISCARD/SEQUENTIAL) and flip model swapchains. WIth blt, the menu bar and DX contents end up in the same surface. With flip, you provide the window contents, and the compositor adds the menu later. There is no way to reposition the swapchain buffers - they replace the entire window contents.

Can you describe how the coordinates were treated with DISCARD? This might be a difference I'm not sure we've really payed attention to.

With DISCARD, the coordinates are treated how you'd expect them to: with the top left coordinate (0, 0) starting just after the menu bar.

Another thing I noticed with FLIP_SEQUENTIAL is, sometimes when I resize the window (manually while the app is running), it will sometimes render correctly, as it does with DISCARD. But as soon as it's rendered for any other reason, it goes back to drawing below the menu bar.

Anyway, thanks for your continued support. I feel like I'm becoming annoying at this point, but these APIs just have so many quirks, I wish they'd just work out of the box...

You mentioned you're on Windows 8.1. That sounds like a familiar bug actually... do you have access to a Windows 10 machine? It might work correctly there.

Nope, unfortunately I don't. I guess for now I'll just stick with DISCARD. Thanks again.

This topic is closed to new replies.

Advertisement