diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-11-20 18:42:58 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-11-20 18:42:58 +0000 |
commit | 9ab1d1f94e502e5fde87e7c171f3502f8a55f22b (patch) | |
tree | 1e2a3e7224680a52f0a057ae6abf527d0a26248b /src | |
parent | 7a7a76b359f73a4c4bcda0d88004f4dd5e94a186 (diff) |
sna/dri: Queue a vblank-continuation after flip-completion
If a vblank request was delayed due to a pending flip, we need to make
sure that we then queue it after that flip or else progress ceases.
Reported-by: Jiri Slaby <jirislaby@gmail.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=56423
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=57156
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src')
-rw-r--r-- | src/sna/sna_dri.c | 85 |
1 files changed, 58 insertions, 27 deletions
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c index ff1f5193..eb7c8358 100644 --- a/src/sna/sna_dri.c +++ b/src/sna/sna_dri.c @@ -1261,7 +1261,7 @@ sna_dri_exchange_buffers(DrawablePtr draw, static void chain_swap(struct sna *sna, DrawablePtr draw, - struct drm_event_vblank *event, + int frame, unsigned int tv_sec, unsigned int tv_usec, struct sna_dri_frame_event *chain) { drmVBlank vbl; @@ -1300,7 +1300,7 @@ static void chain_swap(struct sna *sna, } DRI2SwapComplete(chain->client, draw, - event->sequence, event->tv_sec, event->tv_usec, + frame, tv_sec, tv_usec, type, chain->client ? chain->event_complete : NULL, chain->event_data); VG_CLEAR(vbl); @@ -1405,7 +1405,9 @@ void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event) if (info->chain) { sna_dri_remove_frame_event((WindowPtr)draw, info); - chain_swap(sna, draw, event, info->chain); + chain_swap(sna, draw, + event->sequence, event->tv_sec, event->tv_usec, + info->chain); draw = NULL; } @@ -1521,6 +1523,17 @@ static void sna_dri_flip_event(struct sna *sna, */ DBG(("%s: flip chain complete, off-delay=%d\n", __FUNCTION__, flip->off_delay)); + if (flip->chain) { + sna_dri_remove_frame_event((WindowPtr)flip->draw, + flip); + chain_swap(sna, flip->draw, + flip->fe_frame, + flip->fe_tv_sec, + flip->fe_tv_usec, + flip->chain); + flip->draw = NULL; + } + if (flip->off_delay-- && flip->draw && can_flip(sna, flip->draw, flip->front, flip->front) && (flip->count = sna_page_flip(sna, @@ -1585,36 +1598,54 @@ static void sna_dri_flip_event(struct sna *sna, flip->count = sna_page_flip(sna, get_private(flip->front)->bo, flip, flip->pipe); - if (flip->count == 0) - goto finish_async_flip; + if (flip->count == 0) { + if (flip->chain) + goto chain_async_flip; + else + goto finish_async_flip; + } flip->next_front.bo = get_private(flip->front)->bo; flip->next_front.name = flip->front->name; flip->off_delay = FLIP_OFF_DELAY; sna->dri.flip_pending = flip; - } else if (flip->draw && - can_flip(sna, flip->draw, flip->front, flip->back) && - flip->off_delay--) { - assert(flip == sna_dri_window_get_chain((WindowPtr)flip->draw)); - DBG(("%s: queuing no-flip [delay=%d]\n", - __FUNCTION__, flip->off_delay)); - /* Just queue a no-op flip to trigger another event */ - flip->count = sna_page_flip(sna, - get_private(flip->front)->bo, - flip, flip->pipe); - if (flip->count == 0) - goto finish_async_flip; + } else { + if (flip->chain) { +chain_async_flip: + sna_dri_remove_frame_event((WindowPtr)flip->draw, + flip); + chain_swap(sna, flip->draw, + flip->fe_frame, + flip->fe_tv_sec, + flip->fe_tv_usec, + flip->chain); + flip->draw = NULL; + } - assert(flip->next_front.bo == get_private(flip->front)->bo); - assert(flip->next_front.name == flip->front->name); + if (flip->draw && + can_flip(sna, flip->draw, flip->front, flip->back) && + flip->off_delay--) { + assert(flip == sna_dri_window_get_chain((WindowPtr)flip->draw)); + DBG(("%s: queuing no-flip [delay=%d]\n", + __FUNCTION__, flip->off_delay)); + /* Just queue a no-op flip to trigger another event */ + flip->count = sna_page_flip(sna, + get_private(flip->front)->bo, + flip, flip->pipe); + if (flip->count == 0) + goto finish_async_flip; + + assert(flip->next_front.bo == get_private(flip->front)->bo); + assert(flip->next_front.name == flip->front->name); - sna->dri.flip_pending = flip; - } else { + sna->dri.flip_pending = flip; + } else { finish_async_flip: - DBG(("%s: async flip completed (drawable gone? %d)\n", - __FUNCTION__, flip->draw == NULL)); - sna_dri_frame_event_info_free(sna, flip->draw, flip); + DBG(("%s: async flip completed (drawable gone? %d)\n", + __FUNCTION__, flip->draw == NULL)); + sna_dri_frame_event_info_free(sna, flip->draw, flip); + } } break; #endif @@ -1890,14 +1921,13 @@ sna_dri_immediate_blit(struct sna *sna, DrawablePtr draw, struct sna_dri_frame_event *info) { - drmVBlank vbl; - DBG(("%s: emitting immediate blit, throttling client\n", __FUNCTION__)); - VG_CLEAR(vbl); if ((sna->flags & SNA_NO_WAIT) == 0) { info->type = DRI2_SWAP_THROTTLE; if (sna_dri_window_get_chain((WindowPtr)draw) == info) { + drmVBlank vbl; + DBG(("%s: no pending blit, starting chain\n", __FUNCTION__)); @@ -1910,6 +1940,7 @@ sna_dri_immediate_blit(struct sna *sna, info->event_complete, info->event_data); + VG_CLEAR(vbl); vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_NEXTONMISS | |