[Nouveau] [PATCH 3/3] dri2: Fixes to swap scheduling, especially for copy-swaps.

Mario Kleiner mario.kleiner at tuebingen.mpg.de
Fri Sep 2 10:33:21 PDT 2011


Treats vblank event scheduling for the non-pageflip swap
case correctly. Allows vblank controlled swaps for redirected
windows. Fixes some corner-cases in OML_sync_control scheduling
when divisor and remainder parameters are used.

Signed-off-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
---
 src/nouveau_dri2.c |   71 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 61 insertions(+), 10 deletions(-)

diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index 9f0ee97..f14dea4 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -196,10 +196,8 @@ can_sync_to_vblank(DrawablePtr draw)
 {
 	ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
 	NVPtr pNv = NVPTR(scrn);
-	PixmapPtr pix = NVGetDrawablePixmap(draw);
 
 	return pNv->glx_vblank &&
-		nouveau_exa_pixmap_is_onscreen(pix) &&
 		nv_window_belongs_to_crtc(scrn, draw->x, draw->y,
 					  draw->width, draw->height);
 }
@@ -344,9 +342,40 @@ nouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 			   CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
 			   DRI2SwapEventPtr func, void *data)
 {
+	PixmapPtr dst_pix;
+	PixmapPtr src_pix = nouveau_dri2_buffer(src)->ppix;
 	struct nouveau_dri2_vblank_state *s;
 	CARD64 current_msc, expect_msc;
-	int ret;
+	int ret, flip = 0;
+	Bool front_updated;
+
+	/* Truncate to match kernel interfaces; means occasional overflow
+	 * misses, but that's generally not a big deal.
+	 */
+	*target_msc &= 0xffffffff;
+	divisor &= 0xffffffff;
+	remainder &= 0xffffffff;
+
+	/* Update frontbuffer pixmap and name: Could have changed due to
+	 * window (un)redirection as part of compositing.
+	 */
+	front_updated = update_front(draw, dst);
+
+	/* Assign frontbuffer pixmap, after update in update_front() */
+	dst_pix = nouveau_dri2_buffer(dst)->ppix;
+
+	/* Flips need to be submitted one frame before */
+	if (DRI2CanFlip(draw) && front_updated &&
+	    can_exchange(draw, dst_pix, src_pix)) {
+		flip = 1;
+	}
+
+	/* Correct target_msc by 'flip' if this is a page-flipped swap.
+	 * Do it early, so handling of different timing constraints
+	 * for divisor, remainder and msc vs. target_msc works.
+	 */
+	if (*target_msc > 0)
+		*target_msc -= (CARD64) flip;
 
 	/* Initialize a swap structure */
 	s = malloc(sizeof(*s));
@@ -363,19 +392,34 @@ nouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 		if (ret)
 			goto fail;
 
-		/* Calculate a swap target if we don't have one */
-		if (current_msc >= *target_msc && divisor)
+		/* Calculate a swap target if we don't have one or if
+		 * divisor/remainder relationship must be satisfied.
+		 */
+		if (current_msc >= *target_msc && divisor) {
 			*target_msc = current_msc + divisor
 				- (current_msc - remainder) % divisor;
 
-		/* Request a vblank event one frame before the target */
+			/* Account for extra pageflip delay if flip > 0 */
+			*target_msc -= (CARD64) flip;
+		}
+
+		/* Request a vblank event one frame before the target, unless
+		 * this is a copy-swap, in which case we need to make sure
+		 * it is only dispatched at the target frame or later.
+		 */
 		ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE |
-					  DRM_VBLANK_EVENT,
-					  max(current_msc, *target_msc - 1),
+					  DRM_VBLANK_EVENT |
+					  ((flip) ? 0 : DRM_VBLANK_NEXTONMISS),
+					  max(current_msc, *target_msc),
 					  &expect_msc, NULL, s);
 		if (ret)
 			goto fail;
-		s->frame = (unsigned int) expect_msc & 0xffffffff;
+
+		/* Store expected target_msc for later consistency check and
+		 * return it to server for proper swap_interval implementation.
+		 */
+		s->frame = ((unsigned int) (expect_msc & 0xffffffff)) + flip ;
+		*target_msc = s->frame;
 	} else {
 		/* We can't/don't want to sync to vblank, just swap. */
 		nouveau_dri2_finish_swap(draw, 0, 0, 0, s);
@@ -396,6 +440,13 @@ nouveau_dri2_schedule_wait(ClientPtr client, DrawablePtr draw,
 	CARD64 current_msc;
 	int ret;
 
+	/* Truncate to match kernel interfaces; means occasional overflow
+	 * misses, but that's generally not a big deal.
+	 */
+	target_msc &= 0xffffffff;
+	divisor &= 0xffffffff;
+	remainder &= 0xffffffff;
+
 	if (!can_sync_to_vblank(draw)) {
 		DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
 		return TRUE;
@@ -415,7 +466,7 @@ nouveau_dri2_schedule_wait(ClientPtr client, DrawablePtr draw,
 		goto fail;
 
 	/* Calculate a wait target if we don't have one */
-	if (current_msc > target_msc && divisor)
+	if (current_msc >= target_msc && divisor)
 		target_msc = current_msc + divisor
 			- (current_msc - remainder) % divisor;
 
-- 
1.7.1



More information about the Nouveau mailing list