[PATCH 1/3] present: Fall back to modeset for unflip operation

Michel Dänzer michel at daenzer.net
Wed Jul 8 02:25:40 PDT 2015


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

It's not always possible to use the page flip ioctl for this, e.g.
during DPMS off. We were previously just skipping the unflip in that
case, which could result in hangs when setting DPMS off while a
fullscreen Present app is running, e.g. at the GNOME3 lock screen.

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/drmmode_display.c | 19 +++++++++++++++----
 src/drmmode_display.h |  3 +++
 src/radeon_present.c  | 46 ++++++++++++++++++++++++++++++++++------------
 3 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 8483909..ad2f48b 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -769,6 +769,9 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 
 		if (crtc->scrn->pScreen)
 			xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
+
+		drmmode_crtc->need_modeset = FALSE;
+
 		/* go through all the outputs and force DPMS them back on? */
 		for (i = 0; i < xf86_config->num_output; i++) {
 			xf86OutputPtr output = xf86_config->output[i];
@@ -1153,20 +1156,28 @@ static void
 drmmode_output_dpms(xf86OutputPtr output, int mode)
 {
 	drmmode_output_private_ptr drmmode_output = output->driver_private;
+	xf86CrtcPtr crtc = output->crtc;
 	drmModeConnectorPtr koutput = drmmode_output->mode_output;
 	drmmode_ptr drmmode = drmmode_output->drmmode;
 
 	if (!koutput)
 		return;
 
-	if (mode != DPMSModeOn && output->crtc)
-		drmmode_do_crtc_dpms(output->crtc, mode);
+	if (mode != DPMSModeOn && crtc)
+		drmmode_do_crtc_dpms(crtc, mode);
 
 	drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
 				    drmmode_output->dpms_enum_id, mode);
 
-	if (mode == DPMSModeOn && output->crtc)
-		drmmode_do_crtc_dpms(output->crtc, mode);
+	if (mode == DPMSModeOn && crtc) {
+	    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+	    if (drmmode_crtc->need_modeset)
+		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x,
+				       crtc->y);
+	    else
+		drmmode_do_crtc_dpms(crtc, mode);
+	}
 }
 
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index ca42c7d..ab6c590 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -99,6 +99,9 @@ typedef struct {
     uint32_t interpolated_vblanks;
     uint16_t lut_r[256], lut_g[256], lut_b[256];
     int prime_pixmap_x;
+
+    /* Modeset needed for DPMS on */
+    Bool need_modeset;
 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
 
 typedef struct {
diff --git a/src/radeon_present.c b/src/radeon_present.c
index c48df13..bc1053e 100644
--- a/src/radeon_present.c
+++ b/src/radeon_present.c
@@ -341,30 +341,52 @@ radeon_present_unflip(ScreenPtr screen, uint64_t event_id)
 {
     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
     RADEONInfoPtr info = RADEONPTR(scrn);
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
     struct radeon_present_vblank_event *event;
     PixmapPtr pixmap = screen->GetScreenPixmap(screen);
     uint32_t handle;
-    Bool ret;
+    int i;
 
     if (!radeon_present_check_flip(NULL, screen->root, pixmap, TRUE))
-	return;
+	goto modeset;
 
-    if (!radeon_get_pixmap_handle(pixmap, &handle))
-	return;
+    if (!radeon_get_pixmap_handle(pixmap, &handle)) {
+	ErrorF("%s: radeon_get_pixmap_handle failed, display might freeze\n",
+	       __func__);
+	goto modeset;
+    }
 
     event = calloc(1, sizeof(struct radeon_present_vblank_event));
-    if (!event)
-	return;
+    if (!event) {
+	ErrorF("%s: calloc failed, display might freeze\n", __func__);
+	goto modeset;
+    }
 
     event->event_id = event_id;
 
-    ret = radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, handle,
-			     event_id, event, -1, radeon_present_flip_event,
-			     radeon_present_flip_abort);
-    if (!ret) {
-	xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present unflip failed\n");
-	info->drmmode.present_flipping = FALSE;
+    if (radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, handle,
+			   event_id, event, -1, radeon_present_flip_event,
+			   radeon_present_flip_abort))
+	return;
+
+modeset:
+    for (i = 0; i < config->num_crtc; i++) {
+	xf86CrtcPtr crtc = config->crtc[i];
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+	if (!crtc->enabled)
+	    continue;
+
+	if (drmmode_crtc->dpms_mode == DPMSModeOn)
+	    crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
+					crtc->x, crtc->y);
+	else
+	    drmmode_crtc->need_modeset = TRUE;
     }
+
+    present_event_notify(event_id, 0, 0);
+
+    info->drmmode.present_flipping = FALSE;
 }
 
 static present_screen_info_rec radeon_present_screen_info = {
-- 
2.1.4



More information about the xorg-driver-ati mailing list