DRI2/xserver: Don't hang in glXSwapBuffers if drawable moves between crtc's (bug 28383)

Detect if a drawable has been moved from an original crtc to a new crtc
with a lower current vblank count than the original crtc inbetween
glXSwapBuffers() calls. Reinitialize drawable's last_swap_target
before scheduling next swap if such a move has taken place.

last_swap_target defines the baseline for scheduling the next swap.
If a movement between crtc's is not taken into account, the swap may
schedule for a vblank count on the new crtc far in the future, resulting
in a apparent "hang" of the drawable for a long time.

Fixes Bugzilla bug #28383.

Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
Mario Kleiner 2010-06-13 18:05:26 +02:00 committed by Keith Packard
parent 868bf3de47
commit 75beadd766

View File

@ -759,6 +759,7 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
DRI2DrawablePtr pPriv;
DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL;
int ret, i;
CARD64 ust, current_msc;
pPriv = DRI2GetDrawable(pDraw);
if (pPriv == NULL) {
@ -803,12 +804,26 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
* need to schedule a swap for the last swap target + the swap interval.
*/
if (target_msc == 0 && divisor == 0 && remainder == 0) {
/* If the current vblank count of the drawable's crtc is lower
* than the count stored in last_swap_target from a previous swap
* then reinitialize last_swap_target to the current crtc's msc,
* otherwise the swap will hang. This will happen if the drawable
* is moved to a crtc with a lower refresh rate, or a crtc that just
* got enabled.
*/
if (!(*ds->GetMSC)(pDraw, &ust, &current_msc))
pPriv->last_swap_target = 0;
if (current_msc < pPriv->last_swap_target)
pPriv->last_swap_target = current_msc;
/*
* Swap target for this swap is last swap target + swap interval since
* we have to account for the current swap count, interval, and the
* number of pending swaps.
*/
*swap_target = pPriv->last_swap_target + pPriv->swap_interval;
} else {
/* glXSwapBuffersMscOML could have a 0 target_msc, honor it */
*swap_target = target_msc;