From: Michel Dänzer <michel.daenzer@xxxxxxx> The xserver Present code can submit a flip in response to notifying it that a vblank event arrived. This can happen before the completion event of the previous flip is processed. In that case, we were clearing the drmmode_crtc->flip_pending field prematurely. Prevent this by only clearing drmmode_crtc->flip_pending when it matches the framebuffer being scanned out since the flip whose completion event we're processing. Signed-off-by: Michel Dänzer <michel.daenzer at amd.com> --- src/drmmode_display.c | 27 ++++++++++++++++----------- src/drmmode_display.h | 3 ++- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 25805c58a..ae8b4a110 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -2401,6 +2401,7 @@ drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) if (!flipdata->fe_crtc) flipdata->fe_crtc = crtc; flipdata->abort(flipdata->fe_crtc, flipdata->event_data); + drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb, NULL); free(flipdata); } @@ -2422,6 +2423,13 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even flipdata->fe_usec = usec; } + drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, + flipdata->fb); + if (drmmode_crtc->flip_pending == flipdata->fb) { + drmmode_fb_reference(pRADEONEnt->fd, + &drmmode_crtc->flip_pending, NULL); + } + if (--flipdata->flip_count == 0) { /* Deliver MSC & UST from reference/current CRTC to flip event * handler @@ -2432,13 +2440,9 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even else flipdata->handler(crtc, frame, usec, flipdata->event_data); + drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb, NULL); free(flipdata); } - - drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, - drmmode_crtc->flip_pending); - drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, - NULL); } @@ -2959,7 +2963,6 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; drmmode_flipdata_ptr flipdata; uintptr_t drm_queue_seq = 0; - struct drmmode_fb *fb; flipdata = calloc(1, sizeof(drmmode_flipdata_rec)); if (!flipdata) { @@ -2968,8 +2971,9 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, goto error; } - fb = radeon_pixmap_get_fb(new_front); - if (!fb) { + drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb, + radeon_pixmap_get_fb(new_front)); + if (!flipdata->fb) { ErrorF("Failed to get FB for flip\n"); goto error; } @@ -3011,7 +3015,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, if (crtc == ref_crtc) { if (drmmode_page_flip_target_absolute(pRADEONEnt, drmmode_crtc, - fb->handle, + flipdata->fb->handle, flip_flags, drm_queue_seq, target_msc) != 0) @@ -3019,14 +3023,14 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, } else { if (drmmode_page_flip_target_relative(pRADEONEnt, drmmode_crtc, - fb->handle, + flipdata->fb->handle, flip_flags, drm_queue_seq, 0) != 0) goto flip_error; } drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, - fb); + flipdata->fb); drm_queue_seq = 0; } @@ -3044,6 +3048,7 @@ error: drmmode_flip_abort(crtc, flipdata); else { abort(NULL, data); + drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb, NULL); free(flipdata); } diff --git a/src/drmmode_display.h b/src/drmmode_display.h index 8acf848c0..fddf0e6a9 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -56,8 +56,9 @@ typedef struct { } drmmode_rec, *drmmode_ptr; typedef struct { - int flip_count; + struct drmmode_fb *fb; void *event_data; + int flip_count; unsigned int fe_frame; uint64_t fe_usec; xf86CrtcPtr fe_crtc; -- 2.14.1