glx/dri3: Use four buffers until X driver supports async flips

Graphics / Mesa 3D Graphics Library / Mesa - Keith Packard [keithp.com] - 30 September 2014 22:08 UTC

A driver which doesn't have async flip support will queue up flips without any way to replace them afterwards. This means we've got a scanout buffer pinned as soon as we schedule a flip and so we need another buffer to keep from stalling.

When vblank_mode=0, if there are only three buffers we do:

current scanout buffer = 0 at MSC 0

Render frame 1 to buffer 1 PresentPixmap for buffer 1 at MSC 1

This is sitting down in the kernel waiting for vblank to become the next scanout buffer

Render frame 2 to buffer 2 PresentPixmap for buffer 2 at MSC 1

This cannot be displayed at MSC 1 because the kernel doesn't have any way to replace buffer 1 as the pending scanout buffer. So, best case this will get displayed at MSC 2.

Now we block after this, waiting for one of the three buffers to become idle. We can't use buffer 0 because it is the scanout buffer. We can't use buffer 1 because it's sitting in the kernel waiting to become the next scanout buffer and we can't use buffer 2 because that's the most recent frame which will become the next scanout buffer if the application doesn't manage to generate another complete frame by MSC 2.

With four buffers, we get:

current scanout buffer = 0 at MSC 0

Render frame 1 to buffer 1 PresentPixmap for buffer 1 at MSC 1

This is sitting down in the kernel waiting for vblank to become the next scanout buffer

Render frame 2 to buffer 2 PresentPixmap for buffer 2 at MSC 1

This cannot be displayed at MSC 1 because the kernel doesn't have any way to replace buffer 1 as the pending scanout buffer. So, best case this will get displayed at MSC 2. The X server will queue this swap until buffer 1 becomes the scanout buffer.

Render frame 3 to buffer 3 PresentPixmap for buffer 3 at MSC 1

As soon as the X server sees this, it will replace the pending buffer 2 swap with this swap and release buffer 2 back to the application

Render frame 4 to buffer 2 PresentPixmap for buffer 2 at MSC 1

Now we're in a steady state, flipping between buffer 2 and 3 waiting for one of them to be queued to the kernel.



current scanout buffer = 1 at MSC 1

Now buffer 0 is free and (e.g.) buffer 2 is queued in the kernel to be the scanout buffer at MSC 2

Render frames, flipping between buffer 0 and 3

When the system can replace a queued buffer, and we update Present to take advantage of that, we can use three buffers and get:

current scanout buffer = 0 at MSC 0

Render frame 1 to buffer 1 PresentPixmap for buffer 1 at MSC 1

This is sitting waiting for vblank to become the next scanout buffer

Render frame 2 to buffer 2 PresentPixmap for buffer 2 at MSC 1

Queue this for display at MSC 1 1. There are three possible results:

1) We're still before MSC 1. Buffer 1 is released, buffer 2 is queued waiting for MSC 1.

2) We're now after MSC 1. Buffer 0 was released at MSC 1. Buffer 1 is the current scanout buffer.

a) If the user asked for a tearing update, we swap scanout from buffer 1 to buffer 2 and release buffer 1.

b) If the user asked for non-tearing update, we queue buffer 2 for the MSC 2.

In all three cases, we have a buffer released (call it 'n'), ready to receive the next frame.

Render frame 3 to buffer n PresentPixmap for buffer n

If we're still before MSC 1, then we'll ask to present at MSC 1. Otherwise, we'll ask to present at MSC 2.

Present already does this if the driver offers async flips, however it does this by waiting for the right vblank event and sending an async flip right at that point.

I've hacked the intel driver to offer this, but I get tearing at the top of the screen. I think this is because flips are always done from within the ring, and so the latency between the vblank event and the async flip happening can cause tearing at the top of the screen.

That's why I'm keying the need for the extra buffer on the lack of 2D driver support for async flips.

f7a3555 glx/dri3: Use four buffers until X driver supports async flips
src/glx/dri3_glx.c | 20 +++++++++++++++++++-
src/glx/dri3_priv.h | 6 +++++-
2 files changed, 24 insertions(+), 2 deletions(-)

Upstream: cgit.freedesktop.org


  • Share