[PATCH xf86-video-amdgpu 07/12] Deal with modesets and page flips crossing on a CRTC

Michel Dänzer michel at daenzer.net
Fri Mar 18 10:01:32 UTC 2016


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

If we set a mode while a flip is pending, the kernel driver may program
the flip to the hardware after the modeset. If that happens, the hardware
will display the BO from the flip, whereas we will assume it displays the
BO from the modeset. In other words, the display will most likely freeze,
at least until another modeset.

Prevent this condition by waiting for a pending flip to finish before
setting a mode.

Fixes display freezing when setting rotation or a transform with
TearFree enabled.

(Ported from radeon commit a88985f5d1e39caca49ceb65678aaa9cb622a0d2)

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/amdgpu_kms.c      |  2 ++
 src/drmmode_display.c | 13 +++++++++++++
 src/drmmode_display.h |  2 ++
 3 files changed, 17 insertions(+)

diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index be8c2bf..e8258f8 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -393,6 +393,7 @@ amdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
 	drmmode_crtc_private_ptr drmmode_crtc = event_data;
 
 	drmmode_crtc->scanout_update_pending = FALSE;
+	drmmode_crtc->flip_pending = FALSE;
 }
 
 static void
@@ -435,6 +436,7 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
 
 	drmmode_crtc->scanout_id = scanout_id;
 	drmmode_crtc->scanout_update_pending = TRUE;
+	drmmode_crtc->flip_pending = TRUE;
 }
 
 static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 2ce9f3d..2c75f82 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -702,6 +702,12 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 				amdgpu_glamor_finish(pScrn);
 			}
 		}
+
+		/* Wait for any pending flip to finish */
+		do {} while (drmmode_crtc->flip_pending &&
+			     drmHandleEvent(pAMDGPUEnt->fd,
+					    &drmmode->event_context) > 0);
+
 		if (drmModeSetCrtc(pAMDGPUEnt->fd,
 				   drmmode_crtc->mode_crtc->crtc_id,
 				   fb_id, x, y, output_ids,
@@ -1857,6 +1863,7 @@ static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
 static void
 drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
 {
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	drmmode_flipdata_ptr flipdata = event_data;
 
 	if (--flipdata->flip_count == 0) {
@@ -1865,11 +1872,14 @@ drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
 		flipdata->abort(crtc, flipdata->event_data);
 		free(flipdata);
 	}
+
+	drmmode_crtc->flip_pending = FALSE;
 }
 
 static void
 drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
 {
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
 	drmmode_flipdata_ptr flipdata = event_data;
 
@@ -1892,6 +1902,8 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even
 
 		free(flipdata);
 	}
+
+	drmmode_crtc->flip_pending = FALSE;
 }
 
 static void drm_wakeup_handler(pointer data, int err, pointer p)
@@ -2405,6 +2417,7 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 				   "flip queue failed: %s\n", strerror(errno));
 			goto error;
 		}
+		drmmode_crtc->flip_pending = TRUE;
 		drm_queue = NULL;
 	}
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index e5e5de6..24d517d 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -97,6 +97,8 @@ typedef struct {
 
 	/* Modeset needed for DPMS on */
 	Bool need_modeset;
+	/* A flip is pending for this CRTC */
+	Bool flip_pending;
 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
 
 typedef struct {
-- 
2.7.0



More information about the xorg-driver-ati mailing list