diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2017-02-09 13:01:03 +0900 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2017-08-17 15:52:24 +0900 |
commit | 4445765af5b97d0cfd10889fe6d6f58f2ce85659 (patch) | |
tree | 74939f3b3eb707e68fceed1cd043d5015d57c1d5 | |
parent | 65e0c5ea1b4adff21d673dbf54af99704c429627 (diff) |
Always allow Present page flipping with TearFree
Even if TearFree is active for the the CRTC we're synchronizing to. In
that case, for Present flips synchronized to vertical blank, the other
scanout buffer is immediately synchronized and flipped to during the
target vertical blank period. For Present flips not synchronized to
vertical blank, we simply use the MSC and timestamp values of the last
vertical blank period for timing purposes, and let the normal TearFree
mechanism handle display updates.
v2:
* Move manpage hunk to next change, since TearFree can still prevent
DRI2 page flipping with this change.
Reviewed-by: Alex Deucher <alexander.deucher@amd.com> # v1
-rw-r--r-- | src/drmmode_display.c | 61 | ||||
-rw-r--r-- | src/drmmode_display.h | 12 | ||||
-rw-r--r-- | src/radeon_kms.c | 27 | ||||
-rw-r--r-- | src/radeon_present.c | 75 |
4 files changed, 152 insertions, 23 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 1ce58d1e..90588671 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -612,6 +612,14 @@ error: static void radeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) { + drmmode_crtc_private_ptr drmmode_crtc = closure; + + if (drmmode_crtc->ignore_damage) { + RegionEmpty(&damage->damage); + drmmode_crtc->ignore_damage = FALSE; + return; + } + /* Only keep track of the extents */ RegionUninit(&damage->damage); damage->damage.data = NULL; @@ -2429,7 +2437,8 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, flipdata->fb); - if (drmmode_crtc->flip_pending == flipdata->fb) { + if (drmmode_crtc->tear_free || + drmmode_crtc->flip_pending == flipdata->fb) { drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, NULL); } @@ -2998,13 +3007,16 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, flipdata->fe_crtc = ref_crtc; for (i = 0; i < config->num_crtc; i++) { + struct drmmode_fb *fb = flipdata->fb; + crtc = config->crtc[i]; + drmmode_crtc = crtc->driver_private; - if (!drmmode_crtc_can_flip(crtc)) + if (!drmmode_crtc_can_flip(crtc) || + (drmmode_crtc->tear_free && crtc != ref_crtc)) continue; flipdata->flip_count++; - drmmode_crtc = crtc->driver_private; drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id, flipdata, @@ -3016,10 +3028,39 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, goto error; } + if (drmmode_crtc->tear_free) { + BoxRec extents = { .x1 = 0, .y1 = 0, + .x2 = new_front->drawable.width, + .y2 = new_front->drawable.height }; + int scanout_id = drmmode_crtc->scanout_id ^ 1; + + if (flip_sync == FLIP_ASYNC) { + if (!drmmode_wait_vblank(crtc, + DRM_VBLANK_RELATIVE | + DRM_VBLANK_EVENT, + 0, drm_queue_seq, + NULL, NULL)) + goto flip_error; + goto next; + } + + fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); + if (!fb) { + ErrorF("Failed to get FB for TearFree flip\n"); + goto error; + } + + radeon_scanout_do_update(crtc, scanout_id, + &new_front->drawable, &extents); + + drmmode_crtc_wait_pending_event(drmmode_crtc, pRADEONEnt->fd, + drmmode_crtc->scanout_update_pending); + } + if (crtc == ref_crtc) { if (drmmode_page_flip_target_absolute(pRADEONEnt, drmmode_crtc, - flipdata->fb->handle, + fb->handle, flip_flags, drm_queue_seq, target_msc) != 0) @@ -3027,14 +3068,20 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, } else { if (drmmode_page_flip_target_relative(pRADEONEnt, drmmode_crtc, - flipdata->fb->handle, + fb->handle, flip_flags, drm_queue_seq, 0) != 0) goto flip_error; } - drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, - flipdata->fb); + if (drmmode_crtc->tear_free) { + drmmode_crtc->scanout_id ^= 1; + drmmode_crtc->ignore_damage = TRUE; + } + + next: + drmmode_fb_reference(pRADEONEnt->fd, + &drmmode_crtc->flip_pending, fb); drm_queue_seq = 0; } diff --git a/src/drmmode_display.h b/src/drmmode_display.h index 13f301f7..a6db87f8 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -85,6 +85,7 @@ typedef struct { struct drmmode_scanout rotate; struct drmmode_scanout scanout[2]; DamagePtr scanout_damage; + Bool ignore_damage; RegionRec scanout_last_region; unsigned scanout_id; Bool scanout_update_pending; @@ -106,6 +107,14 @@ typedef struct { struct drmmode_fb *flip_pending; /* The FB currently being scanned out by this CRTC, if any */ struct drmmode_fb *fb; + +#ifdef HAVE_PRESENT_H + /* Deferred processing of Present vblank event */ + uint64_t present_vblank_event_id; + uint64_t present_vblank_usec; + unsigned present_vblank_msc; + Bool present_flip_expected; +#endif } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; typedef struct { @@ -146,7 +155,8 @@ drmmode_crtc_can_flip(xf86CrtcPtr crtc) return crtc->enabled && drmmode_crtc->dpms_mode == DPMSModeOn && !drmmode_crtc->rotate.bo && - !drmmode_crtc->scanout[drmmode_crtc->scanout_id].bo; + (drmmode_crtc->tear_free || + !drmmode_crtc->scanout[drmmode_crtc->scanout_id].bo); } diff --git a/src/radeon_kms.c b/src/radeon_kms.c index 17902334..7febf148 100644 --- a/src/radeon_kms.c +++ b/src/radeon_kms.c @@ -44,6 +44,10 @@ #include "atipciids.h" +#if HAVE_PRESENT_H +#include <present.h> +#endif + /* DPMS */ #ifdef HAVE_XEXTPROTO_71 #include <X11/extensions/dpmsconst.h> @@ -779,6 +783,15 @@ radeon_prime_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec, drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, drmmode_crtc->flip_pending); radeon_prime_scanout_flip_abort(crtc, event_data); + +#ifdef HAVE_PRESENT_H + if (drmmode_crtc->present_vblank_event_id) { + present_event_notify(drmmode_crtc->present_vblank_event_id, + drmmode_crtc->present_vblank_usec, + drmmode_crtc->present_vblank_msc); + drmmode_crtc->present_vblank_event_id = 0; + } +#endif } static void @@ -1001,10 +1014,14 @@ radeon_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, ScreenPtr screen = crtc->scrn->pScreen; RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage); - radeon_scanout_do_update(crtc, drmmode_crtc->scanout_id, - &screen->GetWindowPixmap(screen->root)->drawable, - ®ion->extents); - RegionEmpty(region); + if (crtc->enabled && + !drmmode_crtc->flip_pending && + drmmode_crtc->dpms_mode == DPMSModeOn) { + if (radeon_scanout_do_update(crtc, drmmode_crtc->scanout_id, + &screen->GetWindowPixmap(screen->root)->drawable, + ®ion->extents)) + RegionEmpty(region); + } radeon_scanout_update_abort(crtc, event_data); } @@ -1021,6 +1038,7 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc) if (!xf86_crtc->enabled || drmmode_crtc->scanout_update_pending || + drmmode_crtc->flip_pending || drmmode_crtc->dpms_mode != DPMSModeOn) return; @@ -1088,6 +1106,7 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info, unsigned scanout_id; if (drmmode_crtc->scanout_update_pending || + drmmode_crtc->flip_pending || drmmode_crtc->dpms_mode != DPMSModeOn) return; diff --git a/src/radeon_present.c b/src/radeon_present.c index c7dde0ec..176853d9 100644 --- a/src/radeon_present.c +++ b/src/radeon_present.c @@ -52,6 +52,7 @@ static present_screen_info_rec radeon_present_screen_info; struct radeon_present_vblank_event { uint64_t event_id; + Bool vblank_for_flip; Bool unflip; }; @@ -119,9 +120,26 @@ static void radeon_present_vblank_handler(xf86CrtcPtr crtc, unsigned int msc, uint64_t usec, void *data) { + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; struct radeon_present_vblank_event *event = data; - present_event_notify(event->event_id, usec, msc); + if (event->vblank_for_flip && + drmmode_crtc->tear_free && + drmmode_crtc->scanout_update_pending) { + if (drmmode_crtc->present_vblank_event_id != 0) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING, + "Need to handle previously deferred vblank event\n"); + present_event_notify(drmmode_crtc->present_vblank_event_id, + drmmode_crtc->present_vblank_usec, + drmmode_crtc->present_vblank_msc); + } + + drmmode_crtc->present_vblank_event_id = event->event_id; + drmmode_crtc->present_vblank_msc = msc; + drmmode_crtc->present_vblank_usec = usec; + } else + present_event_notify(event->event_id, usec, msc); + free(event); } @@ -144,6 +162,7 @@ static int radeon_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) { xf86CrtcPtr xf86_crtc = crtc->devPrivate; + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; ScreenPtr screen = crtc->pScreen; struct radeon_present_vblank_event *event; uintptr_t drm_queue_seq; @@ -152,6 +171,9 @@ radeon_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) if (!event) return BadAlloc; event->event_id = event_id; + event->vblank_for_flip = drmmode_crtc->present_flip_expected; + drmmode_crtc->present_flip_expected = FALSE; + drm_queue_seq = radeon_drm_queue_alloc(xf86_crtc, RADEON_DRM_QUEUE_CLIENT_DEFAULT, event_id, event, @@ -226,8 +248,17 @@ radeon_present_check_unflip(ScrnInfoPtr scrn) return FALSE; for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { - if (drmmode_crtc_can_flip(config->crtc[i])) - num_crtcs_on++; + xf86CrtcPtr crtc = config->crtc[i]; + + if (drmmode_crtc_can_flip(crtc)) { + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (drmmode_crtc->flip_pending) + return FALSE; + + if (!drmmode_crtc->tear_free) + num_crtcs_on++; + } } return num_crtcs_on > 0; @@ -240,10 +271,20 @@ static Bool radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip) { + xf86CrtcPtr xf86_crtc = crtc->devPrivate; + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; ScreenPtr screen = window->drawable.pScreen; - ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + ScrnInfoPtr scrn = xf86_crtc->scrn; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); RADEONInfoPtr info = RADEONPTR(scrn); PixmapPtr screen_pixmap; + int num_crtcs_on; + int i; + + drmmode_crtc->present_flip_expected = FALSE; + + if (!scrn->vtSema) + return FALSE; if (!info->allowPageFlip) return FALSE; @@ -262,10 +303,18 @@ radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, radeon_present_get_pixmap_tiling_flags(info, screen_pixmap)) return FALSE; - if (!drmmode_crtc_can_flip(crtc->devPrivate)) + for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { + if (drmmode_crtc_can_flip(config->crtc[i])) + num_crtcs_on++; + else if (config->crtc[i] == crtc->devPrivate) + return FALSE; + } + + if (num_crtcs_on == 0) return FALSE; - return radeon_present_check_unflip(scrn); + drmmode_crtc->present_flip_expected = TRUE; + return TRUE; } /* @@ -304,18 +353,20 @@ static Bool radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, PixmapPtr pixmap, Bool sync_flip) { + xf86CrtcPtr xf86_crtc = crtc->devPrivate; + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; ScreenPtr screen = crtc->pScreen; - ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + ScrnInfoPtr scrn = xf86_crtc->scrn; RADEONInfoPtr info = RADEONPTR(scrn); struct radeon_present_vblank_event *event; - Bool ret; + Bool ret = FALSE; if (!radeon_present_check_flip(crtc, screen->root, pixmap, sync_flip)) - return FALSE; + goto out; event = calloc(1, sizeof(struct radeon_present_vblank_event)); if (!event) - return FALSE; + goto out; event->event_id = event_id; @@ -332,6 +383,8 @@ radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, else info->drmmode.present_flipping = TRUE; + out: + drmmode_crtc->present_flip_expected = FALSE; return ret; } @@ -376,7 +429,7 @@ modeset: xf86CrtcPtr crtc = config->crtc[i]; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - if (!crtc->enabled) + if (!crtc->enabled || drmmode_crtc->tear_free) continue; if (drmmode_crtc->dpms_mode == DPMSModeOn) |