xf86-video-intel: 2 commits - src/intel_display.c src/intel_dri.c src/intel.h

Chris Wilson ickle at kemper.freedesktop.org
Thu Dec 16 04:02:21 PST 2010


 src/intel.h         |    2 -
 src/intel_display.c |   55 ++++++++++++++++++++++++++++++++++++++++++++++------
 src/intel_dri.c     |   23 ++++++++++++++++++---
 3 files changed, 70 insertions(+), 10 deletions(-)

New commits:
commit 5743c223877fbff710cdd5114cff6d3ee3108309
Author: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
Date:   Thu Dec 9 03:27:59 2010 +0100

    Check consistency of pageflip completion vblank count.
    
    Implements a consistency check on returned vblank
    count values of pageflip completion. Impossible
    values are detected, a x-warning is logged and
    returned (msc,ust) values are marked invalid,
    so clients could perform error handling. Such
    a warning would indicate bugs in the pageflip
    completion routine of future kms drivers or the
    ddx and thereby aid driver debugging.
    
    Signed-off-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/intel_dri.c b/src/intel_dri.c
index e383548..a41555c 100644
--- a/src/intel_dri.c
+++ b/src/intel_dri.c
@@ -629,7 +629,8 @@ I830DRI2ExchangeBuffers(DrawablePtr draw, DRI2BufferPtr front,
 static Bool
 I830DRI2ScheduleFlip(struct intel_screen_private *intel,
 		     ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
-		     DRI2BufferPtr back, DRI2SwapEventPtr func, void *data)
+		     DRI2BufferPtr back, DRI2SwapEventPtr func, void *data,
+		     unsigned int target_msc)
 {
 	I830DRI2BufferPrivatePtr back_priv;
 	DRI2FrameEventPtr flip_info;
@@ -646,6 +647,7 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel,
 	flip_info->type = DRI2_SWAP;
 	flip_info->event_complete = func;
 	flip_info->event_data = data;
+	flip_info->frame = target_msc;
 
 	/* Page flip the full screen buffer */
 	back_priv = back->driverPrivate;
@@ -712,7 +714,7 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
 		    I830DRI2ScheduleFlip(intel,
 					 event->client, drawable, event->front,
 					 event->back, event->event_complete,
-					 event->event_data)) {
+					 event->event_data, event->frame)) {
 			I830DRI2ExchangeBuffers(drawable,
 						event->front, event->back);
 			break;
@@ -783,6 +785,18 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
 	/* We assume our flips arrive in order, so we don't check the frame */
 	switch (flip->type) {
 	case DRI2_SWAP:
+		/* Check for too small vblank count of pageflip completion, taking wraparound
+		 * into account. This usually means some defective kms pageflip completion,
+		 * causing wrong (msc, ust) return values and possible visual corruption.
+		 */
+		if ((frame < flip->frame) && (flip->frame - frame < 5)) {
+			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+				   "%s: Pageflip completion has impossible msc %d < target_msc %d\n",
+				   __func__, frame, flip->frame);
+			/* All-Zero values signal failure of timestamping to client. */
+			frame = tv_sec = tv_usec = 0;
+		}
+
 		DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
 				 DRI2_FLIP_COMPLETE, flip->event_complete,
 				 flip->event_data);
commit 2177e6032146f4720f244e98f7c0d6df1b925784
Author: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
Date:   Thu Dec 9 03:12:35 2010 +0100

    Fix reporting of pageflip completion events on multi-head.
    
    When a drawable is page-flipped on multiple crtc's (fullscreen
    drawable on mirror-mode or multi-head x-screen), only one pageflip
    event is finally delivered, after the last participating crtc signals
    flip completion, this to avoid visual corruption.
    
    Old code returned vblank count and timestamps of flip completion
    of this last crtc, instead of the values of the "master crtc", the
    one that was used for initially scheduling/triggering the pagflip
    via vblank events. (master = I830DRI2DrawablePipe(drawable))
    
    This patch makes sure that the pageflip completion values of the
    "master" crtc are returned, otherwise client applications will
    get confused by the random (msc, ust) values returned by whichever
    crtc was the last to complete its flip. Without this, the returned
    values change randomly and jump forward and backward in time and
    count.
    
    Signed-off-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/intel.h b/src/intel.h
index dc88d74..8d31ac1 100644
--- a/src/intel.h
+++ b/src/intel.h
@@ -503,7 +503,7 @@ extern int intel_output_dpms_status(xf86OutputPtr output);
 
 extern Bool intel_do_pageflip(intel_screen_private *intel,
 			      dri_bo *new_front,
-			      void *data);
+			      void *data, int ref_crtc_hw_id);
 
 static inline intel_screen_private *
 intel_get_screen_private(ScrnInfoPtr scrn)
diff --git a/src/intel_display.c b/src/intel_display.c
index bb8d708..1198013 100644
--- a/src/intel_display.c
+++ b/src/intel_display.c
@@ -53,11 +53,19 @@ struct intel_mode {
 	void *event_data;
 	int old_fb_id;
 	int flip_count;
+	unsigned int fe_frame;
+	unsigned int fe_tv_sec;
+	unsigned int fe_tv_usec;
 
 	struct list outputs;
 	struct list crtcs;
 };
 
+struct intel_pageflip {
+	struct intel_mode *mode;
+	Bool dispatch_me;
+};
+
 struct intel_crtc {
 	struct intel_mode *mode;
 	drmModeModeInfo kmode;
@@ -1416,13 +1424,14 @@ fail:
 Bool
 intel_do_pageflip(intel_screen_private *intel,
 		  dri_bo *new_front,
-		  void *data)
+		  void *data, int ref_crtc_hw_id)
 {
 	ScrnInfoPtr scrn = intel->scrn;
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
 	struct intel_crtc *crtc = config->crtc[0]->driver_private;
 	struct intel_mode *mode = crtc->mode;
 	unsigned int pitch = scrn->displayWidth * intel->cpp;
+	struct intel_pageflip *flip;
 	int i, old_fb_id;
 
 	/*
@@ -1443,18 +1452,39 @@ intel_do_pageflip(intel_screen_private *intel,
 	 * Also, flips queued on disabled or incorrectly configured displays
 	 * may never complete; this is a configuration error.
 	 */
+	mode->fe_frame = 0;
+	mode->fe_tv_sec = 0;
+	mode->fe_tv_usec = 0;
+
 	for (i = 0; i < config->num_crtc; i++) {
 		if (!config->crtc[i]->enabled)
 			continue;
 
 		mode->event_data = data;
 		mode->flip_count++;
+
+		crtc = config->crtc[i]->driver_private;
+
+		flip = calloc(1, sizeof(struct intel_pageflip));
+		if (flip == NULL) {
+			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+				   "flip queue: carrier alloc failed.\n");
+			goto error_undo;
+		}
+
+		/* Only the reference crtc will finally deliver its page flip
+		 * completion event. All other crtc's events will be discarded.
+		 */
+		flip->dispatch_me = (intel_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id);
+		flip->mode = mode;
+
 		if (drmModePageFlip(mode->fd,
-				    crtc_id(config->crtc[i]->driver_private),
+				    crtc_id(crtc),
 				    mode->fb_id,
-				    DRM_MODE_PAGE_FLIP_EVENT, mode)) {
+				    DRM_MODE_PAGE_FLIP_EVENT, flip)) {
 			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 				   "flip queue failed: %s\n", strerror(errno));
+			free(flip);
 			goto error_undo;
 		}
 	}
@@ -1487,19 +1517,32 @@ static void
 intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
 			  unsigned int tv_usec, void *event_data)
 {
-	struct intel_mode *mode = event_data;
-
+	struct intel_pageflip *flip = event_data;
+	struct intel_mode *mode = flip->mode;
+
+	/* Is this the event whose info shall be delivered to higher level? */
+	if (flip->dispatch_me) {
+		/* Yes: Cache msc, ust for later delivery. */
+		mode->fe_frame = frame;
+		mode->fe_tv_sec = tv_sec;
+		mode->fe_tv_usec = tv_usec;
+	}
+	free(flip);
 
+	/* Last crtc completed flip? */
 	mode->flip_count--;
 	if (mode->flip_count > 0)
 		return;
 
+	/* Release framebuffer */
 	drmModeRmFB(mode->fd, mode->old_fb_id);
 
 	if (mode->event_data == NULL)
 		return;
 
-	I830DRI2FlipEventHandler(frame, tv_sec, tv_usec, mode->event_data);
+	/* Deliver cached msc, ust from reference crtc to flip event handler */
+	I830DRI2FlipEventHandler(mode->fe_frame, mode->fe_tv_sec,
+				 mode->fe_tv_usec, mode->event_data);
 }
 
 static void
diff --git a/src/intel_dri.c b/src/intel_dri.c
index 67f7be9..e383548 100644
--- a/src/intel_dri.c
+++ b/src/intel_dri.c
@@ -634,6 +634,9 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel,
 	I830DRI2BufferPrivatePtr back_priv;
 	DRI2FrameEventPtr flip_info;
 
+	/* Main crtc for this drawable shall finally deliver pageflip event. */
+	int ref_crtc_hw_id = I830DRI2DrawablePipe(draw);
+
 	flip_info = calloc(1, sizeof(DRI2FrameEventRec));
 	if (!flip_info)
 	    return FALSE;
@@ -648,7 +651,7 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel,
 	back_priv = back->driverPrivate;
 	return intel_do_pageflip(intel,
 				 intel_get_pixmap_bo(back_priv->pixmap),
-				 flip_info);
+				 flip_info, ref_crtc_hw_id);
 }
 
 static Bool


More information about the xorg-commit mailing list