diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2018-11-21 18:32:04 +0100 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2018-12-13 12:17:30 +0100 |
commit | bcfa6c258fdf41a9928f8a3c78fc528d0fafee25 (patch) | |
tree | 5bd59e6137a5f3f1e13969c37bba17405a26c1a1 | |
parent | 4e7a24ac5a64e402146953ec5850d13c05742116 (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
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | src/amdgpu_kms.c | 75 | ||||
-rw-r--r-- | src/drmmode_display.h | 7 |
2 files changed, 71 insertions, 11 deletions
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c index 44a3c8a..506e5f7 100644 --- a/src/amdgpu_kms.c +++ b/src/amdgpu_kms.c @@ -748,15 +748,32 @@ amdgpu_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(pAMDGPUEnt->fd, 0, 0, 0, (void*)drm_queue_seq); drmmode_crtc->wait_flip_nesting_level++; amdgpu_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 @@ -807,12 +824,22 @@ amdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent) if (drmmode_page_flip_target_relative(pAMDGPUEnt, 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; + } + amdgpu_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; } @@ -1029,15 +1056,32 @@ amdgpu_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(pAMDGPUEnt->fd, 0, 0, 0, (void*)drm_queue_seq); drmmode_crtc->wait_flip_nesting_level++; amdgpu_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 @@ -1089,9 +1133,13 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info, if (drmmode_page_flip_target_relative(pAMDGPUEnt, 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; + } + amdgpu_drm_abort_entry(drm_queue_seq); RegionCopy(DamageRegion(drmmode_crtc->scanout_damage), &drmmode_crtc->scanout_last_region); @@ -1103,6 +1151,11 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr 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; } diff --git a/src/drmmode_display.h b/src/drmmode_display.h index b2b16df..aab330c 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -91,6 +91,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 amdgpu_buffer *bo; PixmapPtr pixmap; @@ -110,6 +116,7 @@ typedef struct { unsigned scanout_id; uintptr_t scanout_update_pending; Bool tear_free; + enum drmmode_scanout_status scanout_status; Bool vrr_enabled; PixmapPtr prime_scanout_pixmap; |