diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2016-04-05 17:53:55 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2016-04-05 18:09:21 +0100 |
commit | 65dc4176d84e1d1764a6fa1edc972aa7f1dcd2ba (patch) | |
tree | 1f2b6f8cf53d3336ed20c817caf0d71ddd579aaa | |
parent | bb5194eebd72e828a46f504d91f1ecd5b5804f57 (diff) |
sna/present: Prevent reporting an incomplete event
If we cancel a flip, we may try to restore the current mode and this may
flush the partial flip (in a multi-monitor setup). We report the completed
event back to present and free the event info. Then we report the error
back to present, and free the event info a second time. Chaos and
corruption ensues.
Reported-and-tested-by: Christoph Haag <haagch@frickel.club>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94829
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/sna_present.c | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c index e08afe56..727fa877 100644 --- a/src/sna/sna_present.c +++ b/src/sna/sna_present.c @@ -45,6 +45,7 @@ struct sna_present_event { uint64_t *event_id; uint64_t target_msc; int n_event_id; + bool queued; }; static void sna_present_unflip(ScreenPtr screen, uint64_t event_id); @@ -260,6 +261,7 @@ static bool sna_present_queue(struct sna_present_event *info, if (!sna_fake_vblank(info)) return false; } else { + info->queued = true; if (info->target_msc - last_msc == 1) { sna_crtc_set_vblank(info->crtc); info->crtc = mark_crtc(info->crtc); @@ -334,6 +336,11 @@ sna_present_vblank_handler(struct drm_event_vblank *event) struct sna_present_event *info = to_present_event(event->user_data); xf86CrtcPtr crtc = info->crtc; + if (!info->queued) { + DBG(("%s: arrived unexpectedly early (not queued)\n", __FUNCTION__)); + return; + } + vblank_complete(info, ust64(event->tv_sec, event->tv_usec), sna_crtc_record_event(unmask_crtc(crtc), event)); @@ -406,6 +413,7 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) info->event_id[0] = event_id; info->n_event_id = 1; list_add_tail(&info->link, &tmp->link); + info->queued = false; if (!sna_present_queue(info, swap->msc)) { list_del(&info->link); @@ -569,6 +577,10 @@ present_flip_handler(struct drm_event_vblank *event, void *data) DBG(("%s(sequence=%d): event=%lld\n", __FUNCTION__, event->sequence, (long long)info->event_id[0])); assert(info->n_event_id == 1); + if (!info->queued) { + DBG(("%s: arrived unexpectedly early (not queued)\n", __FUNCTION__)); + return; + } if (info->crtc == NULL) { swap.tv_sec = event->tv_sec; @@ -621,6 +633,7 @@ flip(struct sna *sna, info->event_id[0] = event_id; info->n_event_id = 1; info->target_msc = target_msc; + info->queued = false; if (!sna_page_flip(sna, bo, present_flip_handler, info)) { DBG(("%s: pageflip failed\n", __FUNCTION__)); @@ -628,6 +641,7 @@ flip(struct sna *sna, return FALSE; } + info->queued = true; if (info->crtc) sna_crtc_set_vblank(info->crtc); return TRUE; |