diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2017-08-03 18:16:36 +0900 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2017-08-17 15:45:37 +0900 |
commit | 7c10ee9c88378d773c0bcf651fdc5d9f2c6dc5e5 (patch) | |
tree | 9cd2926173baa0b5855206bdc313fbd81e37c832 | |
parent | e6d7dc2070f4d21a6900916bb70a31839112882c (diff) |
Handle multiple "pending" Present flips
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.
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | src/drmmode_display.c | 27 | ||||
-rw-r--r-- | 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 2692f697..d86c4ba9 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -2403,6 +2403,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); } @@ -2424,6 +2425,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 @@ -2434,13 +2442,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); } @@ -2961,7 +2965,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) { @@ -2970,8 +2973,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; } @@ -3013,7 +3017,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) @@ -3021,14 +3025,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; } @@ -3046,6 +3050,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 52b76f05..13f301f7 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; |