diff --git a/src/sna/sna.h b/src/sna/sna.h index 74a03f3c..3f01d55e 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -354,6 +354,7 @@ struct sna { bool available; bool open; #if HAVE_PRESENT + uint64_t unflip; #endif } present; diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c index 035a54b7..90d08b57 100644 --- a/src/sna/sna_present.c +++ b/src/sna/sna_present.c @@ -42,6 +42,8 @@ struct sna_present_event { xf86CrtcPtr crtc; }; +static void sna_present_unflip(ScreenPtr screen, uint64_t event_id); + static inline struct sna_present_event * to_present_event(uintptr_t data) { @@ -201,11 +203,21 @@ check_flip__crtc(struct sna *sna, assert(sna->scrn->vtSema); + if (!sna->mode.front_active) { + DBG(("%s: DPMS off, no flips\n", __FUNCTION__)); + return FALSE; + } + if (sna->mode.shadow_active) { DBG(("%s: shadow buffer active\n", __FUNCTION__)); return false; } + if (sna->mode.flip_active) { + DBG(("%s: flips still pending\n", __FUNCTION__)); + return false; + } + return true; } @@ -229,11 +241,6 @@ sna_present_check_flip(RRCrtcPtr crtc, return FALSE; } - if (!sna->mode.front_active) { - DBG(("%s: DPMS off, no flips\n", __FUNCTION__)); - return FALSE; - } - if (sna->flags & SNA_NO_FLIP) { DBG(("%s: flips not suported\n", __FUNCTION__)); return FALSE; @@ -312,6 +319,7 @@ present_flip_handler(struct drm_event_vblank *event, void *data) { struct sna_present_event *info = data; struct ust_msc swap; + struct sna *sna; DBG(("%s(sequence=%d)\n", __FUNCTION__, event->sequence)); @@ -327,6 +335,14 @@ present_flip_handler(struct drm_event_vblank *event, void *data) swap.tv_sec, swap.tv_usec, (long long)swap.msc, (long long)info->event_id)); present_event_notify(info->event_id, ust64(swap.tv_sec, swap.tv_usec), swap.msc); + + sna = info->crtc ? to_sna(info->crtc->scrn) : NULL; + if (sna && sna->present.unflip) { + DBG(("%s: executing queued unflip\n", __FUNCTION__)); + sna_present_unflip(xf86ScrnToScreen(sna->scrn), + sna->present.unflip); + sna->present.unflip = 0; + } free(info); } @@ -412,6 +428,8 @@ sna_present_flip(RRCrtcPtr crtc, return FALSE; } + assert(to_sna_from_pixmap(pixmap)->present.unflip == 0); + bo = get_flip_bo(pixmap); if (bo == NULL) { DBG(("%s: flip invalid bo\n", __FUNCTION__)); @@ -448,6 +466,13 @@ notify: return; } + if (sna->mode.flip_active) { + DBG(("%s: outstanding flips, queueing unflip\n", __FUNCTION__)); + assert(sna->present.unflip == 0); + sna->present.unflip = event_id; + return; + } + bo = get_flip_bo(screen->GetScreenPixmap(screen)); if (bo == NULL || !page_flip(screen, NULL, event_id, bo)) { DBG(("%s: failed, trying to restore original mode\n", __FUNCTION__));