[PATCH] Don't attempt a DRI2/Present page flip while the other one is flipping

Michel Dänzer michel at daenzer.net
Thu Jun 11 02:59:50 PDT 2015


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

Fixes corrupted display and hangs when switching between DRI2 and DRI3
fullscreen apps, e.g. a compositor using DRI3 and a fullscreen app using
DRI2 or vice versa.

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/drmmode_display.h |  3 +++
 src/radeon_dri2.c     | 23 +++++++++++++++++------
 src/radeon_present.c  | 17 ++++++++++++++++-
 3 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 2fdd3e0..ca42c7d 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -54,6 +54,9 @@ typedef struct {
   int count_crtcs;
 
   Bool delete_dp_12_displays;
+
+  Bool dri2_flipping;
+  Bool present_flipping;
 } drmmode_rec, *drmmode_ptr;
 
 typedef struct {
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index a1f0145..7587a0c 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -584,6 +584,7 @@ static void
 radeon_dri2_flip_event_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
 			       void *event_data)
 {
+    RADEONInfoPtr info = RADEONPTR(scrn);
     DRI2FrameEventPtr flip = event_data;
     unsigned tv_sec, tv_usec;
     DrawablePtr drawable;
@@ -627,6 +628,7 @@ radeon_dri2_flip_event_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
 	DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
 			 DRI2_FLIP_COMPLETE, flip->event_complete,
 			 flip->event_data);
+	info->drmmode.dri2_flipping = FALSE;
 	break;
     default:
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__);
@@ -644,6 +646,7 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
 			  DRI2BufferPtr back, DRI2SwapEventPtr func,
 			  void *data, unsigned int target_msc)
 {
+    RADEONInfoPtr info = RADEONPTR(scrn);
     struct dri2_buffer_priv *back_priv;
     struct radeon_bo *bo;
     DRI2FrameEventPtr flip_info;
@@ -670,11 +673,16 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
     back_priv = back->driverPrivate;
     bo = radeon_get_pixmap_bo(back_priv->pixmap);
 
-    return radeon_do_pageflip(scrn, client, bo->handle,
-			      RADEON_DRM_QUEUE_ID_DEFAULT, flip_info,
-			      ref_crtc_hw_id,
-			      radeon_dri2_flip_event_handler,
-			      radeon_dri2_flip_event_abort);
+    if (radeon_do_pageflip(scrn, client, bo->handle,
+			   RADEON_DRM_QUEUE_ID_DEFAULT, flip_info,
+			   ref_crtc_hw_id,
+			   radeon_dri2_flip_event_handler,
+			   radeon_dri2_flip_event_abort)) {
+	info->drmmode.dri2_flipping = TRUE;
+	return TRUE;
+    }
+
+    return FALSE;
 }
 
 static Bool
@@ -742,8 +750,11 @@ static Bool
 can_flip(ScrnInfoPtr pScrn, DrawablePtr draw,
 	 DRI2BufferPtr front, DRI2BufferPtr back)
 {
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+
     return draw->type == DRAWABLE_WINDOW &&
-	   RADEONPTR(pScrn)->allowPageFlip &&
+	   info->allowPageFlip &&
+	   !info->drmmode.present_flipping &&
 	   pScrn->vtSema &&
 	   DRI2CanFlip(draw) &&
 	   can_exchange(pScrn, draw, front, back);
diff --git a/src/radeon_present.c b/src/radeon_present.c
index 2626044..c48df13 100644
--- a/src/radeon_present.c
+++ b/src/radeon_present.c
@@ -50,6 +50,7 @@
 
 struct radeon_present_vblank_event {
     uint64_t event_id;
+    xf86CrtcPtr crtc;
 };
 
 static uint32_t crtc_select(int crtc_id)
@@ -238,6 +239,9 @@ radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap,
     if (!sync_flip)
 	return FALSE;
 
+    if (info->drmmode.dri2_flipping)
+	return FALSE;
+
     /* The kernel driver doesn't handle flipping between BOs with different
      * tiling parameters correctly yet
      */
@@ -266,8 +270,12 @@ radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap,
 static void
 radeon_present_flip_event(ScrnInfoPtr scrn, uint32_t msc, uint64_t ust, void *pageflip_data)
 {
+    RADEONInfoPtr info = RADEONPTR(scrn);
     struct radeon_present_vblank_event *event = pageflip_data;
 
+    if (!event->crtc)
+	info->drmmode.present_flipping = FALSE;
+
     present_event_notify(event->event_id, ust, msc);
     free(event);
 }
@@ -293,6 +301,7 @@ radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc,
 {
     ScreenPtr screen = crtc->pScreen;
     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    RADEONInfoPtr info = RADEONPTR(scrn);
     struct radeon_present_vblank_event *event;
     xf86CrtcPtr xf86_crtc = crtc->devPrivate;
     int crtc_id = xf86_crtc ? drmmode_get_crtc_id(xf86_crtc) : -1;
@@ -310,6 +319,7 @@ radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc,
 	return FALSE;
 
     event->event_id = event_id;
+    event->crtc = xf86_crtc;
 
     ret = radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, handle,
 			     event_id, event, crtc_id,
@@ -317,6 +327,8 @@ radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc,
 			     radeon_present_flip_abort);
     if (!ret)
 	xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n");
+    else
+	info->drmmode.present_flipping = TRUE;
 
     return ret;
 }
@@ -328,6 +340,7 @@ static void
 radeon_present_unflip(ScreenPtr screen, uint64_t event_id)
 {
     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    RADEONInfoPtr info = RADEONPTR(scrn);
     struct radeon_present_vblank_event *event;
     PixmapPtr pixmap = screen->GetScreenPixmap(screen);
     uint32_t handle;
@@ -348,8 +361,10 @@ radeon_present_unflip(ScreenPtr screen, uint64_t 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)
+    if (!ret) {
 	xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present unflip failed\n");
+	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