[PATCH xf86-video-ati 09/13] Automatically try re-enabling TearFree after a flip failed

Michel Dänzer michel at daenzer.net
Fri Dec 21 17:49:03 UTC 2018


From: Michel Dänzer <michel.daenzer at amd.com>

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)

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/drmmode_display.h |  7 ++++
 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 bfc130109..f56596644 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 796dac5f1..dd9955da7 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;
 }
-- 
2.20.1



More information about the amd-gfx mailing list