summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2016-04-05 17:53:55 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2016-04-05 18:09:21 +0100
commit65dc4176d84e1d1764a6fa1edc972aa7f1dcd2ba (patch)
tree1f2b6f8cf53d3336ed20c817caf0d71ddd579aaa
parentbb5194eebd72e828a46f504d91f1ecd5b5804f57 (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.c14
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;