xf86-video-intel: 3 commits - src/i830_dri.c

Jesse Barnes jbarnes at kemper.freedesktop.org
Fri Mar 5 12:52:55 PST 2010


 src/i830_dri.c |  155 +++++++++++++++++++++++++++++++++------------------------
 1 file changed, 92 insertions(+), 63 deletions(-)

New commits:
commit 1cd556420277f103c47ade422f3ec8f8efb2d282
Author: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
Date:   Fri Mar 5 12:32:18 2010 -0800

    DRI2: handle target_msc, divisor and remainder properly in DRI2ScheduleSwap
    
    The current code in I830DRI2ScheduleSwap() only schedules the correct
    vblank events for the case divisor == 0, i.e., the simple
    glXSwapBuffers() case.
    
    In a glXSwapBuffersMscOML() request, divisor can be > 0, which would go
    wrong.
    
    This modified code should handle target_msc, divisor, remainder and the
    different cases defined in the OML_sync_control extension correctly for
    the divisor > 0 case.
    
    It also tries to make sure that the effective framecount of swap
    satisfies all constraints, taking the 1 frame delay in pageflipping mode
    and possible delays in blitting/exchange mode due to
    DRM_VBLANK_NEXTONMISS into account.
    
    The swap_interval logic in the X-Servers DRI2SwapBuffers() call expects
    the returned swap_target from the DDX to be reasonably accurate,
    otherwise implementation of swap_interval for the glXSwapBuffers() as
    defined in the SGI_swap_interval extension may become unreliable.
    
    For non-pageflipped mode, the returned swap_target is always correct due
    to the adjustments done by drmWaitVBlank(), as DRM_VBLANK_NEXTONMISS is
    set.
    
    In pageflipped mode, DRM_VBLANK_NEXTONMISS can't be used without severe
    impact on performance, so the code in I830DRI2ScheduleSwap() must make
    manual adjustments to the returned vbl.reply.sequence number.
    
    This patch adds the needed adjustments.
    
    Signed-off-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>

diff --git a/src/i830_dri.c b/src/i830_dri.c
index 002f119..96d41e7 100644
--- a/src/i830_dri.c
+++ b/src/i830_dri.c
@@ -641,6 +641,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	int ret, pipe = I830DRI2DrawablePipe(draw), flip = 0;
 	DRI2FrameEventPtr swap_info;
 	enum DRI2FrameEventType swap_type = DRI2_SWAP;
+	CARD64 current_msc;
 	BoxRec box;
 	RegionRec region;
 
@@ -670,6 +671,8 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		goto blit_fallback;
 	}
 
+	current_msc = vbl.reply.sequence;
+
 	/* Flips need to be submitted one frame before */
 	if (DRI2CanFlip(draw) && !intel->shadow_present &&
 	    intel->use_pageflipping) {
@@ -679,6 +682,13 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 
 	swap_info->type = swap_type;
 
+	/* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
+	 * Do it early, so handling of different timing constraints
+	 * for divisor, remainder and msc vs. target_msc works.
+	 */
+	if (*target_msc > 0)
+		*target_msc -= flip;
+
 	if ((*target_msc != 1) && (*target_msc > vbl.reply.sequence) &&
 	    ((*target_msc - vbl.reply.sequence) > 100))
 	    xf86DrvMsg(scrn->scrnIndex, X_WARNING,
@@ -687,17 +697,32 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		       (unsigned long)*target_msc);
 
 	/*
-	 * If divisor is zero, we just need to make sure target_msc passes
-	 * before waking up the client.
+	 * If divisor is zero, or current_msc is smaller than target_msc
+	 * we just need to make sure target_msc passes before initiating
+	 * the swap.
 	 */
-	if (divisor == 0) {
-		vbl.request.type = DRM_VBLANK_NEXTONMISS |
-		    DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
+	if (divisor == 0 || current_msc < *target_msc) {
+		vbl.request.type =  DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
 		if (pipe > 0)
 			vbl.request.type |= DRM_VBLANK_SECONDARY;
 
+		/* If non-pageflipping, but blitting/exchanging, we need to use
+		 * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
+		 * on.
+		 */
+		if (flip == 0)
+			vbl.request.type |= DRM_VBLANK_NEXTONMISS;
+		if (pipe > 0)
+			vbl.request.type |= DRM_VBLANK_SECONDARY;
+
+		/* If target_msc already reached or passed, set it to
+		 * current_msc to ensure we return a reasonable value back
+		 * to the caller. This makes swap_interval logic more robust.
+		 */
+		if (current_msc >= *target_msc)
+			*target_msc = current_msc;
+
 		vbl.request.sequence = *target_msc;
-		vbl.request.sequence -= flip;
 		vbl.request.signal = (unsigned long)swap_info;
 		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
 		if (ret) {
@@ -707,7 +732,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 			goto blit_fallback;
 		}
 
-		*target_msc = vbl.reply.sequence;
+		*target_msc = vbl.reply.sequence + flip;
 		swap_info->frame = *target_msc;
 
 		return TRUE;
@@ -715,42 +740,35 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 
 	/*
 	 * If we get here, target_msc has already passed or we don't have one,
-	 * so we queue an event that will satisfy the divisor/remainderequation.
+	 * and we need to queue an event that will satisfy the divisor/remainder
+	 * equation.
 	 */
-	if ((vbl.reply.sequence % divisor) == remainder) {
-		BoxRec box;
-		RegionRec region;
-
-		box.x1 = 0;
-		box.y1 = 0;
-		box.x2 = draw->width;
-		box.y2 = draw->height;
-		REGION_INIT(pScreen, &region, &box, 0);
-
-		I830DRI2CopyRegion(draw, &region, front, back);
-
-		DRI2SwapComplete(client, draw, 0, 0, 0,
-				 DRI2_BLIT_COMPLETE, func, data);
-		if (swap_info)
-			xfree(swap_info);
-		return TRUE;
-	}
-
 	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
+	if (flip == 0)
+		vbl.request.type |= DRM_VBLANK_NEXTONMISS;
 	if (pipe > 0)
 		vbl.request.type |= DRM_VBLANK_SECONDARY;
 
+	vbl.request.sequence = current_msc - (current_msc % divisor) +
+		remainder;
+
 	/*
-	 * If we have no remainder, and the test above failed, it means we've
-	 * passed the last point where seq % divisor == remainder, so we need
-	 * to wait for the next time that will happen.
+	 * If the calculated deadline vbl.request.sequence is smaller than
+	 * or equal to current_msc, it means we've passed the last point
+	 * when effective onset frame seq could satisfy
+	 * seq % divisor == remainder, so we need to wait for the next time
+	 * this will happen.
+
+	 * This comparison takes the 1 frame swap delay in pageflipping mode
+	 * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
+	 * if we are blitting/exchanging instead of flipping.
 	 */
-	if (!remainder)
+	if (vbl.request.sequence <= current_msc)
 		vbl.request.sequence += divisor;
 
-	vbl.request.sequence = vbl.reply.sequence -
-	    (vbl.reply.sequence % divisor) + remainder;
+	/* Account for 1 frame extra pageflip delay if flip > 0 */
 	vbl.request.sequence -= flip;
+
 	vbl.request.signal = (unsigned long)swap_info;
 	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
 	if (ret) {
@@ -760,7 +778,8 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		goto blit_fallback;
 	}
 
-	*target_msc = vbl.reply.sequence;
+	/* Adjust returned value for 1 fame pageflip offset of flip > 0 */
+	*target_msc = vbl.reply.sequence + flip;
 	swap_info->frame = *target_msc;
 
 	return TRUE;
commit 13119ffc034a3e9d6c76339d4fedc62bb3b41257
Author: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
Date:   Fri Mar 5 11:33:45 2010 -0800

    DRI2: make MSC waits handle specific target_mscs and divisor/remainders
    
    Previous code only handled divisor == 0 case correctly. This should
    honor a given target_msc for the divisor > 0 case and handle the
    (msc % divisor) == remainder constraint correctly.
    
    Signed-off-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>

diff --git a/src/i830_dri.c b/src/i830_dri.c
index 0738cdb..002f119 100644
--- a/src/i830_dri.c
+++ b/src/i830_dri.c
@@ -835,6 +835,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 	DRI2FrameEventPtr wait_info;
 	drmVBlank vbl;
 	int ret, pipe = I830DRI2DrawablePipe(draw);
+	CARD64 current_msc;
 
 	/* Drawable not visible, return immediately */
 	if (pipe == -1) {
@@ -864,9 +865,12 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 		return FALSE;
 	}
 
+	current_msc = vbl.reply.sequence;
+
 	/*
-	 * If divisor is zero, we just need to make sure target_msc passes
-	 * before waking up the client.
+	 * If divisor is zero, or current_msc is smaller than target_msc,
+	 * we just need to make sure target_msc passes  before waking up the
+	 * client.
 	 */
 	if (divisor == 0) {
 		vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
@@ -895,15 +899,13 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 		vbl.request.type |= DRM_VBLANK_SECONDARY;
 
 	/*
-	 * If we have no remainder and the condition isn't satisified, it means
-	 * we've passed the last point where seq % divisor == remainder, so we need
-	 * to wait for the next time that will happen.
+	 * If the calculated  remainder and the condition isn't satisified, it
+	 * means we've passed the last point where seq % divisor == remainder,
+	 * so we need to wait for the next time that will happen.
 	 */
-	if (((vbl.reply.sequence % divisor) != remainder) && !remainder)
+	if ((current_msc % divisor) != remainder)
 		vbl.request.sequence += divisor;
 
-	vbl.request.sequence = vbl.reply.sequence - (vbl.reply.sequence % divisor) +
-		remainder;
 	vbl.request.signal = (unsigned long)wait_info;
 	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
 	if (ret) {
commit b6e0b92f398823629ba8a1ea8f5e62fbf959e725
Author: Jesse Barnes <jbarnes at virtuousgeek.org>
Date:   Thu Mar 4 10:07:26 2010 -0800

    DRI2: handle offscreen drawables better at swap time
    
    If a drawable isn't visible due to DPMS or redirection, we'll just blit
    it rather than schedule a swap event.  However, we didn't reset the
    target_msc, so the swap target we receive from the server could get out
    of sync with the vblank count of the drawable's display.  So at DPMS on
    time, the swap target would be the last good vblank count plus some
    large number (since the swaps won't have been throttled).
    
    Solve this by zeroing out the swap target like we should when we fall
    back to a blit.  Also make the kernel error cases more friendly by
    making them fall back to blits too.
    
    Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>

diff --git a/src/i830_dri.c b/src/i830_dri.c
index 64aeb76..0738cdb 100644
--- a/src/i830_dri.c
+++ b/src/i830_dri.c
@@ -641,28 +641,14 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	int ret, pipe = I830DRI2DrawablePipe(draw), flip = 0;
 	DRI2FrameEventPtr swap_info;
 	enum DRI2FrameEventType swap_type = DRI2_SWAP;
+	BoxRec box;
+	RegionRec region;
 
 	swap_info = xcalloc(1, sizeof(DRI2FrameEventRec));
 
 	/* Drawable not displayed... just complete the swap */
-	if (pipe == -1 || !swap_info) {
-	    BoxRec	    box;
-	    RegionRec	    region;
-
-	    box.x1 = 0;
-	    box.y1 = 0;
-	    box.x2 = draw->width;
-	    box.y2 = draw->height;
-	    REGION_INIT(pScreen, &region, &box, 0);
-
-	    I830DRI2CopyRegion(draw, &region, front, back);
-
-	    DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func,
-			     data);
-	    if (swap_info)
-		xfree(swap_info);
-	    return TRUE;
-	}
+	if (pipe == -1 || !swap_info)
+	    goto blit_fallback;
 
 	swap_info->drawable_id = draw->id;
 	swap_info->client = client;
@@ -681,7 +667,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 			   "first get vblank counter failed: %s\n",
 			   strerror(errno));
-		return FALSE;
+		goto blit_fallback;
 	}
 
 	/* Flips need to be submitted one frame before */
@@ -693,6 +679,13 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 
 	swap_info->type = swap_type;
 
+	if ((*target_msc != 1) && (*target_msc > vbl.reply.sequence) &&
+	    ((*target_msc - vbl.reply.sequence) > 100))
+	    xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		       "vblank event >100 frames away: cur %ld, target %ld\n",
+		       (unsigned long)vbl.reply.sequence,
+		       (unsigned long)*target_msc);
+
 	/*
 	 * If divisor is zero, we just need to make sure target_msc passes
 	 * before waking up the client.
@@ -711,7 +704,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 				   "divisor 0 get vblank counter failed: %s\n",
 				   strerror(errno));
-			return FALSE;
+			goto blit_fallback;
 		}
 
 		*target_msc = vbl.reply.sequence;
@@ -764,13 +757,28 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 			   "final get vblank counter failed: %s\n",
 			   strerror(errno));
-		return FALSE;
+		goto blit_fallback;
 	}
 
 	*target_msc = vbl.reply.sequence;
 	swap_info->frame = *target_msc;
 
 	return TRUE;
+
+blit_fallback:
+	box.x1 = 0;
+	box.y1 = 0;
+	box.x2 = draw->width;
+	box.y2 = draw->height;
+	REGION_INIT(pScreen, &region, &box, 0);
+
+	I830DRI2CopyRegion(draw, &region, front, back);
+
+	DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
+	if (swap_info)
+	    xfree(swap_info);
+	*target_msc = 0; /* offscreen, so zero out target vblank count */
+	return TRUE;
 }
 
 /*


More information about the xorg-commit mailing list