diff options
-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) |