On 15/04/14 19:55, Keith Packard wrote:
Frank Binns <[email protected]> writes:
Hi,
I've been working on adding support for the present extension in the PVR
video driver and I've hit a couple of issues related to flipping:
Awesome. As you may know, this has only been implemented in the Intel
driver and hasn't been accepted upstream yet. The server API closely
matches the internals of that driver, and while I spent a week trying to
rewrite that this spring, I didn't succeed. I'd love to clean it up and
make it actually usable.
1) When the display driver supports async flipping this mode of
operation is always used. This means that, when the swap interval is
none 0, the present extension relies on vblank events to get
synchronised flips. However, by the time we get the event, wait for any
outstanding rendering and do the flip we have probably missed the vblank
period meaning we get screen artefacts.
Right, this is fast enough on my laptop GPU to work. I wonder why you're
waiting for the GPU to flush all of the rendering though? You should
only need to flush rendering targeting the new back buffer and then flip
the scanout engine to that.
The driver is only waiting for any rendering to the back buffer before
doing the flip.
Is there a good reason (other
than simplifying the code) why present isn't relying on the default
behaviour of drmModePageFlip() to get synchronised flips?
Yes, there's a really good reason -- the drm interface doesn't provide
for any way to replace the pending buffer. Once you've queued it, you're
stuck until that buffer becomes active, tying down *two* buffers in the
kernel. And, you don't get the benefit of providing a new buffer after
the swap is first queued.
This happens in the non-async case in that once the the flip is
initiated, i.e. we now have a pending flip, if another swap comes in for
the same MSC then we can't abort the pending flip.
2) When the display driver doesn't support async flipping and the swap
interval is 0 we see swaps alternating between flipping and blitting.
This results in a back buffer continually being created and destroyed on
the client side, which is obviously highly undesirable.
That's a bug. I know I've fixed similar things several times; which X
server version are you running?
We're currently using 1.15.0.
My understanding is that, in the async case, a vblank event gets
requested for the next vblank. Any swaps that come in before this
event's received never get presented to the screen. In addition to this,
it's fairly unlikely that we catch things in the middle of a flip, i.e.
we've called drmModePageFlip() but not got back the flip event, meaning
that any queued vblank events, i.e. queued swaps, are going to be
completed via a flip. However, in the non-async case we're very likely
to catch things in the middle of a flip as a flip can only be completed
during a vblank period. The result is this ping-ponging between flipping
and blitting.
My current thoughts are that two things probably need to be done to fix
this:
a) If present gets a swap for the same MSC as a pending flip then it
should never try to do the presentation and send back
PresentCompleteModeSkip in the reply.
No, this is wrong -- you want to *replace* the old presentation with the
new one. Leaving the old one in place is not what the application wants
at all.
b) If present gets a swap for an MSC in the future then it shouldn't be
prevented from completing the swap via a flip just because there is
currently a pending flip.
Agreed. I think this is fixed in the current code.
I've looked at the git history and I can only see one present related
commit since 1.15.0:
60014a4 Replace 'pointer' type with 'void *'
I couldn't see anything in your git repo either.
Does this sound reasonable, is there a better way of fixing this or am I
missing something?
As I said, the current driver API was designed with the Intel driver in
mind, and using the current DRM kernel interface's limitations. It may
be that the current DRM kernel API just isn't suitable for async
updates.
I'm probably missing something so correct me if I'm wrong but it seems
that maybe the scheme being used needs reversing. Currently if we get
multiple swaps for the same MSC then we only execute the most recent
swap when the MSC is met (skipping the preceding swaps). However, this
doesn't work in the non-async swap interval 0 case and it only works for
none 0 swap intervals because there are only 2 back buffers.
By reversing things, so that if we get multiple swaps for the same MSC
then we execute the oldest swap (skipping the later swaps), we're able
to properly support the non-async swap interval 0 case. It also means
that we can take advantage of the default drmModePageFlip() behaviour in
the async none 0 swap interval case. Of course, this would mean that
we'd always need 3 back buffers when flipping.
Thanks
Frank
_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel