diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2018-12-21 12:49:27 +0100 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2018-12-28 12:07:49 +0100 |
commit | f66254c171f5a3b052a2a9e0339f17dfb5a60dc2 (patch) | |
tree | 2662b4709e1c20c2877c4c7f4597462d22415dc3 | |
parent | ce7db51020d32f17e442338bfd305220feb51630 (diff) |
Automatically try re-enabling TearFree after a flip failed
Specifically, after both the page flip and vblank ioctls failed, but
then the vblank ioctl started working again. This can happen
intermittently e.g. when hotplugging a DP display. Previously, TearFree
would stay disabled in that case until a modeset was triggered somehow.
Bugzilla: https://bugs.freedesktop.org/103791
(Ported from amdgpu commit bcfa6c258fdf41a9928f8a3c78fc528d0fafee25)
-rw-r--r-- | src/drmmode_display.h | 7 | ||||
-rw-r--r-- | src/radeon_kms.c | 75 |
2 files changed, 71 insertions, 11 deletions
diff --git a/src/drmmode_display.h b/src/drmmode_display.h index bfc13010..f5659664 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -71,6 +71,12 @@ struct drmmode_fb { uint32_t handle; }; +enum drmmode_scanout_status { + DRMMODE_SCANOUT_OK, + DRMMODE_SCANOUT_FLIP_FAILED = 1u << 0, + DRMMODE_SCANOUT_VBLANK_FAILED = 1u << 1, +}; + struct drmmode_scanout { struct radeon_buffer *bo; PixmapPtr pixmap; @@ -90,6 +96,7 @@ typedef struct { unsigned scanout_id; uintptr_t scanout_update_pending; Bool tear_free; + enum drmmode_scanout_status scanout_status; PixmapPtr prime_scanout_pixmap; diff --git a/src/radeon_kms.c b/src/radeon_kms.c index 796dac5f..dd9955da 100644 --- a/src/radeon_kms.c +++ b/src/radeon_kms.c @@ -783,15 +783,32 @@ radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty) if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT, 1, drm_queue_seq, NULL, NULL)) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "drmmode_wait_vblank failed for PRIME update: %s\n", - strerror(errno)); + if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "drmmode_wait_vblank failed for PRIME update: %s\n", + strerror(errno)); + drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED; + } + drmmode_crtc->drmmode->event_context.vblank_handler(pRADEONEnt->fd, 0, 0, 0, (void*)drm_queue_seq); drmmode_crtc->wait_flip_nesting_level++; radeon_drm_queue_handle_deferred(xf86_crtc); + return; + } + + if (drmmode_crtc->scanout_status == + (DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) { + /* The page flip and vblank ioctls failed before, but the vblank + * ioctl is working again, so we can try re-enabling TearFree + */ + xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode, + xf86_crtc->rotation, + xf86_crtc->x, xf86_crtc->y); } + + drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED; } static void @@ -842,12 +859,22 @@ radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent) if (drmmode_page_flip_target_relative(pRADEONEnt, drmmode_crtc, drmmode_crtc->flip_pending->handle, 0, drm_queue_seq, 0) != 0) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s\n", - __func__, strerror(errno)); + if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue failed in %s: %s, TearFree inactive\n", + __func__, strerror(errno)); + drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED; + } + radeon_drm_abort_entry(drm_queue_seq); return; } + if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n"); + drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED; + } + drmmode_crtc->scanout_id = scanout_id; drmmode_crtc->scanout_update_pending = drm_queue_seq; } @@ -1072,15 +1099,32 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc) if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT, 1, drm_queue_seq, NULL, NULL)) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "drmmode_wait_vblank failed for scanout update: %s\n", - strerror(errno)); + if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "drmmode_wait_vblank failed for scanout update: %s\n", + strerror(errno)); + drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED; + } + drmmode_crtc->drmmode->event_context.vblank_handler(pRADEONEnt->fd, 0, 0, 0, (void*)drm_queue_seq); drmmode_crtc->wait_flip_nesting_level++; radeon_drm_queue_handle_deferred(xf86_crtc); + return; + } + + if (drmmode_crtc->scanout_status == + (DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) { + /* The page flip and vblank ioctls failed before, but the vblank + * ioctl is working again, so we can try re-enabling TearFree + */ + xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode, + xf86_crtc->rotation, + xf86_crtc->x, xf86_crtc->y); } + + drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED; } static void @@ -1132,9 +1176,13 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info, if (drmmode_page_flip_target_relative(pRADEONEnt, drmmode_crtc, drmmode_crtc->flip_pending->handle, 0, drm_queue_seq, 0) != 0) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s, " - "TearFree inactive until next modeset\n", - __func__, strerror(errno)); + if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue failed in %s: %s, TearFree inactive\n", + __func__, strerror(errno)); + drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED; + } + radeon_drm_abort_entry(drm_queue_seq); RegionCopy(DamageRegion(drmmode_crtc->scanout_damage), &drmmode_crtc->scanout_last_region); @@ -1146,6 +1194,11 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info, return; } + if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n"); + drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED; + } + drmmode_crtc->scanout_id = scanout_id; drmmode_crtc->scanout_update_pending = drm_queue_seq; } |