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. (Ported from radeon commit 7c10ee9c88378d773c0bcf651fdc5d9f2c6dc5e5) 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 0d5aa26d2..eb701a89a 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -2227,6 +2227,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(pAMDGPUEnt->fd, &flipdata->fb, NULL); free(flipdata); } @@ -2248,6 +2249,13 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even flipdata->fe_usec = usec; } + drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, + flipdata->fb); + if (drmmode_crtc->flip_pending == flipdata->fb) { + drmmode_fb_reference(pAMDGPUEnt->fd, + &drmmode_crtc->flip_pending, NULL); + } + if (--flipdata->flip_count == 0) { /* Deliver MSC & UST from reference/current CRTC to flip event * handler @@ -2258,13 +2266,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(pAMDGPUEnt->fd, &flipdata->fb, NULL); free(flipdata); } - - drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, - drmmode_crtc->flip_pending); - drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, - NULL); } #if HAVE_NOTIFY_FD @@ -2761,7 +2765,6 @@ Bool amdgpu_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) { @@ -2770,8 +2773,9 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, goto error; } - fb = amdgpu_pixmap_get_fb(new_front); - if (!fb) { + drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb, + amdgpu_pixmap_get_fb(new_front)); + if (!flipdata->fb) { ErrorF("Failed to get FB for flip\n"); goto error; } @@ -2813,7 +2817,7 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, if (crtc == ref_crtc) { if (drmmode_page_flip_target_absolute(pAMDGPUEnt, drmmode_crtc, - fb->handle, + flipdata->fb->handle, flip_flags, drm_queue_seq, target_msc) != 0) @@ -2821,14 +2825,14 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, } else { if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc, - fb->handle, + flipdata->fb->handle, flip_flags, drm_queue_seq, 0) != 0) goto flip_error; } drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, - fb); + flipdata->fb); drm_queue_seq = 0; } @@ -2846,6 +2850,7 @@ error: drmmode_flip_abort(crtc, flipdata); else { abort(NULL, data); + drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb, NULL); free(flipdata); } diff --git a/src/drmmode_display.h b/src/drmmode_display.h index 38bf14494..b5788e295 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -52,8 +52,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