xf86-video-intel: 7 commits - src/sna/sna_present.c test/present-test.c

Chris Wilson ickle at kemper.freedesktop.org
Thu Feb 12 13:04:42 PST 2015


 src/sna/sna_present.c |   75 +++---
 test/present-test.c   |  555 +++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 502 insertions(+), 128 deletions(-)

New commits:
commit 9eb0ab15b1ab09cd6a4e8666b6f488fad1dc36b4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Feb 12 17:05:52 2015 +0000

    test/present: Look for MSC wraparound
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/present-test.c b/test/present-test.c
index aefed73..ec8db6b 100644
--- a/test/present-test.c
+++ b/test/present-test.c
@@ -165,7 +165,7 @@ static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc,
 		free(ev);
 	} while (!complete);
 
-	if (msc < last_msc) {
+	if ((int64_t)(msc - last_msc) < 0) {
 		printf("Invalid MSC: was %llu, now %llu\n",
 		       (long long)last_msc, (long long)msc);
 	}
commit 254f2f2f4b0a4deccec847e46086881c5a2681b1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Feb 12 17:03:46 2015 +0000

    test/present: Check a simple double-buffer sequence
    
    Just check that we can do a present roundtrip in time to submit a new
    frame on the next vblank.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/present-test.c b/test/present-test.c
index 35ae8d3..aefed73 100644
--- a/test/present-test.c
+++ b/test/present-test.c
@@ -324,6 +324,87 @@ static uint64_t flush_flips(Display *dpy, Window win, Pixmap pixmap, void *Q, ui
 	return check_msc(dpy, win, Q, msc, ust);
 }
 
+static int test_double(Display *dpy, void *Q)
+{
+#define COUNT (15*60)
+	xcb_connection_t *c = XGetXCBConnection(dpy);
+	Pixmap pixmap;
+	Window root;
+	unsigned int width, height;
+	unsigned border, depth;
+	int x, y, n, ret;
+	struct {
+		uint64_t msc, ust;
+	} frame[COUNT+1];
+	int offset = 0;
+
+	XGetGeometry(dpy, DefaultRootWindow(dpy),
+		     &root, &x, &y, &width, &height, &border, &depth);
+
+	printf("Testing whole screen flip double buffering: %dx%d\n", width, height);
+	_x_error_occurred = 0;
+
+	pixmap = XCreatePixmap(dpy, root, width, height, depth);
+	flush_flips(dpy, root, pixmap, Q, NULL);
+	for (n = 0; n <= COUNT; n++) {
+		int complete;
+
+		xcb_present_pixmap(c, root, pixmap, n,
+				   0, /* valid */
+				   0, /* update */
+				   0, /* x_off */
+				   0, /* y_off */
+				   None,
+				   None, /* wait fence */
+				   None,
+				   XCB_PRESENT_OPTION_NONE,
+				   0, /* target msc */
+				   0, /* divisor */
+				   0, /* remainder */
+				   0, NULL);
+		xcb_flush(c);
+
+		complete = 0;
+		do {
+			xcb_present_complete_notify_event_t *ce;
+			xcb_generic_event_t *ev;
+
+			ev = xcb_wait_for_special_event(c, Q);
+			if (ev == NULL)
+				break;
+
+			ce = (xcb_present_complete_notify_event_t *)ev;
+			if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP &&
+			    ce->serial == n) {
+				frame[n].msc = ce->msc;
+				frame[n].ust = ce->ust;
+				complete = 1;
+			}
+			free(ev);
+		} while (!complete);
+	}
+	XFreePixmap(dpy, pixmap);
+
+	XSync(dpy, True);
+	ret = !!_x_error_occurred;
+
+	if (frame[COUNT].msc - frame[0].msc != COUNT) {
+		printf("Expected %d frames interval, %d elapsed instead\n",
+		       COUNT, (int)(frame[COUNT].msc - frame[0].msc));
+		for (n = 0; n <= COUNT; n++) {
+			if (frame[n].msc - frame[0].msc != n + offset) {
+				printf("frame[%d]: msc=%03lld, ust=%lld\n", n,
+				       (long long)(frame[n].msc - frame[0].msc),
+				       (long long)(frame[n].ust - frame[0].ust));
+				offset = frame[n].msc - frame[0].msc - n;
+				ret++;
+			}
+		}
+	}
+
+	return ret;
+}
+
 static int test_future(Display *dpy, void *Q)
 {
 	xcb_connection_t *c = XGetXCBConnection(dpy);
@@ -1285,6 +1366,9 @@ int main(void)
 	error += test_whole(dpy);
 	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
 
+	error += test_double(dpy, queue);
+	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
+
 	error += test_future(dpy, queue);
 	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
 
commit 92f74186b0b329e7ede53153a6b5f953c5cad2a1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Feb 12 14:24:38 2015 +0000

    test/present: Include test for timing accuracy
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/present-test.c b/test/present-test.c
index c8f340b..35ae8d3 100644
--- a/test/present-test.c
+++ b/test/present-test.c
@@ -136,7 +136,7 @@ static void *setup_msc(Display *dpy,  Window win)
 	return q;
 }
 
-static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc)
+static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc, uint64_t *ust)
 {
 	xcb_connection_t *c = XGetXCBConnection(dpy);
 	static uint32_t serial = 1;
@@ -158,6 +158,8 @@ static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc)
 		if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
 		    ce->serial == serial) {
 			msc = ce->msc;
+			if (ust)
+				*ust = ce->ust;
 			complete = 1;
 		}
 		free(ev);
@@ -174,6 +176,46 @@ static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc)
 	return msc;
 }
 
+static uint64_t msc_interval(Display *dpy, Window win, void *q)
+{
+	xcb_connection_t *c = XGetXCBConnection(dpy);
+	uint64_t msc, ust;
+	int complete = 0;
+
+	msc = check_msc(dpy, win, q, 0, NULL);
+
+	xcb_present_notify_msc(c, win, 0xc0ffee00, msc, 0, 0);
+	xcb_present_notify_msc(c, win, 0xc0ffee01, msc + 10, 0, 0);
+	xcb_flush(c);
+
+	ust = msc = 0;
+	do {
+		xcb_present_complete_notify_event_t *ce;
+		xcb_generic_event_t *ev;
+
+		ev = xcb_wait_for_special_event(c, q);
+		if (ev == NULL)
+			break;
+
+		ce = (xcb_present_complete_notify_event_t *)ev;
+		if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
+		    ce->serial == 0xc0ffee00) {
+			msc -= ce->msc;
+			ust -= ce->ust;
+			complete++;
+		}
+		if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
+		    ce->serial == 0xc0ffee01) {
+			msc += ce->msc;
+			ust += ce->ust;
+			complete++;
+		}
+		free(ev);
+	} while (complete != 2);
+
+	return (ust + msc/2) / msc;
+}
+
 static void teardown_msc(Display *dpy, void *q)
 {
 	xcb_unregister_for_special_event(XGetXCBConnection(dpy), q);
@@ -241,32 +283,14 @@ static int test_whole(Display *dpy)
 	return ret;
 }
 
-static int test_future(Display *dpy, void *Q)
+static uint64_t flush_flips(Display *dpy, Window win, Pixmap pixmap, void *Q, uint64_t *ust)
 {
 	xcb_connection_t *c = XGetXCBConnection(dpy);
-	Pixmap pixmap;
-	struct dri3_fence fence;
-	Window root;
-	unsigned int width, height;
-	unsigned border, depth;
-	int x, y, ret = 0, n;
-	uint64_t target;
+	uint64_t msc;
 	int complete;
-	int early = 0, late = 0;
-	int earliest = 0, latest = 0;
-
-	XGetGeometry(dpy, DefaultRootWindow(dpy),
-		     &root, &x, &y, &width, &height, &border, &depth);
-
-	if (dri3_create_fence(dpy, root, &fence))
-		return 0;
-
-	printf("Testing whole screen flips into the future: %dx%d\n", width, height);
-	_x_error_occurred = 0;
 
-	target = check_msc(dpy, root, Q, 0);
-	pixmap = XCreatePixmap(dpy, root, width, height, depth);
-	xcb_present_pixmap(c, root, pixmap,
+	msc = check_msc(dpy, win, Q, 0, NULL);
+	xcb_present_pixmap(c, win, pixmap,
 			   0xdeadbeef, /* serial */
 			   0, /* valid */
 			   0, /* update */
@@ -276,7 +300,7 @@ static int test_future(Display *dpy, void *Q)
 			   None, /* wait fence */
 			   None,
 			   XCB_PRESENT_OPTION_NONE,
-			   target + 60, /* target msc */
+			   msc + 60, /* target msc */
 			   0, /* divisor */
 			   0, /* remainder */
 			   0, NULL);
@@ -291,18 +315,46 @@ static int test_future(Display *dpy, void *Q)
 			break;
 
 		ce = (xcb_present_complete_notify_event_t *)ev;
-		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
-			break;
-
-		complete = ce->serial == 0xdeadbeef;
+		complete = (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP &&
+			    ce->serial == 0xdeadbeef);
 		free(ev);
 	} while (!complete);
 	XSync(dpy, True);
 
-	target = check_msc(dpy, root, Q, 0);
-	for (n = 0; n <= 10; n++)
+	return check_msc(dpy, win, Q, msc, ust);
+}
+
+static int test_future(Display *dpy, void *Q)
+{
+	xcb_connection_t *c = XGetXCBConnection(dpy);
+	Pixmap pixmap;
+	struct dri3_fence fence;
+	Window root;
+	unsigned int width, height;
+	unsigned border, depth;
+	int x, y, ret = 0, n;
+	uint64_t msc, ust;
+	int complete;
+	int early = 0, late = 0;
+	int earliest = 0, latest = 0;
+	uint64_t interval;
+
+	XGetGeometry(dpy, DefaultRootWindow(dpy),
+		     &root, &x, &y, &width, &height, &border, &depth);
+
+	if (dri3_create_fence(dpy, root, &fence))
+		return 0;
+
+	printf("Testing whole screen flips into the future: %dx%d\n", width, height);
+	_x_error_occurred = 0;
+
+	interval = msc_interval(dpy, root, Q);
+
+	pixmap = XCreatePixmap(dpy, root, width, height, depth);
+	msc = flush_flips(dpy, root, pixmap, Q, &ust);
+	for (n = 1; n <= 10; n++)
 		xcb_present_pixmap(c, root, pixmap,
-				   target + 60 + n*15*60, /* serial */
+				   n, /* serial */
 				   0, /* valid */
 				   0, /* update */
 				   0, /* x_off */
@@ -311,7 +363,7 @@ static int test_future(Display *dpy, void *Q)
 				   None, /* wait fence */
 				   None,
 				   XCB_PRESENT_OPTION_NONE,
-				   target + 60 + n*15*60, /* target msc */
+				   msc + 60 + n*15*60, /* target msc */
 				   0, /* divisor */
 				   0, /* remainder */
 				   0, NULL);
@@ -325,7 +377,7 @@ static int test_future(Display *dpy, void *Q)
 			   None, /* wait fence */
 			   None,
 			   XCB_PRESENT_OPTION_NONE,
-			   target + 60 + n*15*60, /* target msc */
+			   msc + 60 + n*15*60, /* target msc */
 			   0, /* divisor */
 			   0, /* remainder */
 			   0, NULL);
@@ -341,29 +393,38 @@ static int test_future(Display *dpy, void *Q)
 			break;
 
 		ce = (xcb_present_complete_notify_event_t *)ev;
-		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
-			break;
-
-		assert(ce->serial);
+		assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
 
 		if (ce->serial == 0xdeadbeef) {
+			int64_t time;
+
+			time = ce->ust - (ust + (60 + 15*60*n) * interval);
+			if (time < -(int64_t)interval) {
+				fprintf(stderr,
+					"\tflips completed too early by %lldms\n",
+					(long long)(-time / 1000));
+			} else if (time > (int64_t)interval) {
+				fprintf(stderr,
+					"\tflips completed too late by %lldms\n",
+					(long long)(time / 1000));
+			}
 			complete = 1;
 		} else {
-			int msc = (uint32_t)ce->msc - ce->serial;
-			if (msc < 0) {
-				ret += -msc;
-				if (-msc > earliest) {
-					fprintf(stderr, "\tframe %d displayed early by %lld frames\n", (int)(ce->serial - target - 60)/(15*60), (long long)msc);
-					earliest = -msc;
+			int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60));
+			if (diff < 0) {
+				if (-diff > earliest) {
+					fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, diff);
+					earliest = -diff;
 				}
 				early++;
-			} else if (msc > 0) {
-				ret += msc;
-				if (msc > latest) {
-					fprintf(stderr, "\tframe %d displayed late by %lld frames\n", (int)(ce->serial - target - 60), (long long)msc);
-					latest = msc;
+				ret++;
+			} else if (diff > 0) {
+				if (diff > latest) {
+					fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff);
+					latest = diff;
 				}
 				late++;
+				ret++;
 			}
 		}
 		free(ev);
@@ -391,7 +452,6 @@ static int test_exhaustion(Display *dpy, void *Q)
 	unsigned border, depth;
 	int x, y, ret = 0, n;
 	uint64_t target, final;
-	int complete;
 
 	XGetGeometry(dpy, DefaultRootWindow(dpy),
 		     &root, &x, &y, &width, &height, &border, &depth);
@@ -405,7 +465,7 @@ static int test_exhaustion(Display *dpy, void *Q)
 	region = xcb_generate_id(c);
 	xcb_xfixes_create_region(c, region, 0, NULL);
 
-	target = check_msc(dpy, root, Q, 0);
+	target = check_msc(dpy, root, Q, 0, NULL);
 	pixmap = XCreatePixmap(dpy, root, width, height, depth);
 	xshmfence_reset(fence.addr);
 	for (n = N_VBLANKS; n--; )
@@ -440,7 +500,7 @@ static int test_exhaustion(Display *dpy, void *Q)
 	XSync(dpy, True);
 	ret += !!xshmfence_await(fence.addr);
 
-	final = check_msc(dpy, root, Q, 0);
+	final = check_msc(dpy, root, Q, 0, NULL);
 	if (final < target) {
 		printf("\tFirst flip too early, MSC was %llu, expected %llu\n",
 		       (long long)final, (long long)target);
@@ -468,7 +528,7 @@ static int test_exhaustion(Display *dpy, void *Q)
 	xcb_flush(c);
 	ret += !!xshmfence_await(fence.addr);
 
-	final = check_msc(dpy, root, Q, 0);
+	final = check_msc(dpy, root, Q, 0, NULL);
 	if (final < target + N_VBLANKS) {
 		printf("\tLast flip too early, MSC was %llu, expected %llu\n",
 		       (long long)final, (long long)(target + N_VBLANKS));
@@ -479,36 +539,7 @@ static int test_exhaustion(Display *dpy, void *Q)
 		ret++;
 	}
 
-	xcb_present_pixmap(c, root, pixmap, 0xdeadbeef,
-			   0, /* valid */
-			   0, /* update */
-			   0, /* x_off */
-			   0, /* y_off */
-			   None,
-			   None, /* wait fence */
-			   0,
-			   XCB_PRESENT_OPTION_NONE,
-			   final + N_VBLANKS + 1, /* target msc */
-			   0, /* divisor */
-			   0, /* remainder */
-			   0, NULL);
-	xcb_flush(c);
-	complete = 0;
-	do {
-		xcb_present_complete_notify_event_t *ce;
-		xcb_generic_event_t *ev;
-
-		ev = xcb_wait_for_special_event(c, Q);
-		if (ev == NULL)
-			break;
-
-		ce = (xcb_present_complete_notify_event_t *)ev;
-		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
-			break;
-
-		complete = ce->serial == 0xdeadbeef;
-		free(ev);
-	} while (!complete);
+	flush_flips(dpy, root, pixmap, Q, NULL);
 
 	XFreePixmap(dpy, pixmap);
 	xcb_xfixes_destroy_region(c, region);
@@ -538,48 +569,14 @@ static int test_accuracy(Display *dpy, void *Q)
 	XGetGeometry(dpy, DefaultRootWindow(dpy),
 		     &root, &x, &y, &width, &height, &border, &depth);
 
-	printf("Testing whole screen flip acccuracy: %dx%d\n", width, height);
+	printf("Testing whole screen flip accuracy: %dx%d\n", width, height);
 	_x_error_occurred = 0;
 
-	target = check_msc(dpy, root, Q, 0);
 	pixmap = XCreatePixmap(dpy, root, width, height, depth);
-	xcb_present_pixmap(c, root, pixmap,
-			   0xdeadbeef, /* serial */
-			   0, /* valid */
-			   0, /* update */
-			   0, /* x_off */
-			   0, /* y_off */
-			   None,
-			   None, /* wait fence */
-			   None,
-			   XCB_PRESENT_OPTION_NONE,
-			   target + 60, /* target msc */
-			   0, /* divisor */
-			   0, /* remainder */
-			   0, NULL);
-	xcb_flush(c);
-	complete = 0;
-	do {
-		xcb_present_complete_notify_event_t *ce;
-		xcb_generic_event_t *ev;
-
-		ev = xcb_wait_for_special_event(c, Q);
-		if (ev == NULL)
-			break;
-
-		ce = (xcb_present_complete_notify_event_t *)ev;
-		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
-			break;
-
-		complete = ce->serial == 0xdeadbeef;
-		free(ev);
-	} while (!complete);
-	XSync(dpy, True);
-
-	target = check_msc(dpy, root, Q, target);
+	target = flush_flips(dpy, root, pixmap, Q, NULL);
 	for (n = 0; n <= N_VBLANKS; n++)
 		xcb_present_pixmap(c, root, pixmap,
-				   target + 60 + n, /* serial */
+				   n, /* serial */
 				   0, /* valid */
 				   0, /* update */
 				   0, /* x_off */
@@ -592,41 +589,53 @@ static int test_accuracy(Display *dpy, void *Q)
 				   0, /* divisor */
 				   0, /* remainder */
 				   0, NULL);
+	xcb_present_pixmap(c, root, pixmap,
+			   0xdeadbeef, /* serial */
+			   0, /* valid */
+			   0, /* update */
+			   0, /* x_off */
+			   0, /* y_off */
+			   None,
+			   None, /* wait fence */
+			   None,
+			   XCB_PRESENT_OPTION_NONE,
+			   target + 60 + n, /* target msc */
+			   0, /* divisor */
+			   0, /* remainder */
+			   0, NULL);
 	xcb_flush(c);
 
 	complete = 0;
 	do {
 		xcb_present_complete_notify_event_t *ce;
 		xcb_generic_event_t *ev;
-		int64_t msc;
 
 		ev = xcb_wait_for_special_event(c, Q);
 		if (ev == NULL)
 			break;
 
 		ce = (xcb_present_complete_notify_event_t *)ev;
-		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
-			break;
-
-		assert(ce->serial);
+		assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
 
-		msc = (uint32_t)ce->msc - ce->serial;
-		if (msc < 0) {
-			ret += -msc;
-			if (-msc > earliest) {
-				fprintf(stderr, "\tframe %d displayed early by %lld frames\n", (int)(ce->serial - target - 60), (long long)msc);
-				earliest = -msc;
-			}
-			early++;
-		} else if (msc > 0) {
-			ret += msc;
-			if (msc > latest) {
-				fprintf(stderr, "\tframe %d displayed late by %lld frames\n", (int)(ce->serial - target - 60), (long long)msc);
-				latest = msc;
+		if (ce->serial != 0xdeadbeef) {
+			int diff = (int64_t)(ce->msc - (target + ce->serial + 60));
+			if (diff < 0) {
+				if (-diff > earliest) {
+					fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff);
+					earliest = -diff;
+				}
+				early++;
+				ret++;
+			} else if (diff > 0) {
+				if (diff > latest) {
+					fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff);
+					latest = diff;
+				}
+				ret++;
+				late++;
 			}
-			late++;
-		}
-		complete = ce->serial == target + 60 + N_VBLANKS;
+		} else
+			complete = 1;
 		free(ev);
 	} while (!complete);
 
@@ -664,45 +673,11 @@ static int test_modulus(Display *dpy, void *Q)
 	printf("Testing whole screen flip modulus: %dx%d\n", width, height);
 	_x_error_occurred = 0;
 
-	target = check_msc(dpy, root, Q, 0);
-	pixmap = XCreatePixmap(dpy, root, width, height, depth);
-	xcb_present_pixmap(c, root, pixmap,
-			   0xdeadbeef, /* serial */
-			   0, /* valid */
-			   0, /* update */
-			   0, /* x_off */
-			   0, /* y_off */
-			   None,
-			   None, /* wait fence */
-			   None,
-			   XCB_PRESENT_OPTION_NONE,
-			   target + 60, /* target msc */
-			   0, /* divisor */
-			   0, /* remainder */
-			   0, NULL);
-	xcb_flush(c);
-	complete = 0;
-	do {
-		xcb_present_complete_notify_event_t *ce;
-		xcb_generic_event_t *ev;
-
-		ev = xcb_wait_for_special_event(c, Q);
-		if (ev == NULL)
-			break;
-
-		ce = (xcb_present_complete_notify_event_t *)ev;
-		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
-			break;
-
-		complete = ce->serial == 0xdeadbeef;
-		free(ev);
-	} while (!complete);
-	XSync(dpy, True);
-
 	region = xcb_generate_id(c);
 	xcb_xfixes_create_region(c, region, 0, NULL);
 
-	target = check_msc(dpy, root, Q, target);
+	pixmap = XCreatePixmap(dpy, root, width, height, depth);
+	target = flush_flips(dpy, root, pixmap, Q, NULL);
 	for (x = 1; x <= 7; x++) {
 		for (y = 0; y < x; y++) {
 			xcb_present_pixmap(c, root, pixmap,
@@ -908,7 +883,7 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
 	Pixmap pixmap;
 	int err = 0;
 
-	test->msc = check_msc(dpy, test->win, test->queue, test->msc);
+	test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL);
 
 	if (test->flags & SYNC)
 		xshmfence_reset(test->fence.addr);
@@ -952,7 +927,7 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
 	}
 	XFreePixmap(dpy, pixmap);
 
-	test->msc = check_msc(dpy, test->win, test->queue, test->msc);
+	test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL);
 	return err;
 }
 
@@ -973,21 +948,21 @@ static int test_crtc(Display *dpy, void *queue, uint64_t last_msc)
 
 	printf("Testing each crtc, without waiting for each flip\n");
 	test.flags = 0;
-	test.msc = check_msc(dpy, test.win, test.queue, test.msc);
+	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
 	err += for_each_crtc(dpy, __test_crtc, &test);
-	test.msc = check_msc(dpy, test.win, test.queue, test.msc);
+	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
 
 	printf("Testing each crtc, waiting for flips to complete\n");
 	test.flags = SYNC;
-	test.msc = check_msc(dpy, test.win, test.queue, test.msc);
+	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
 	err += for_each_crtc(dpy, __test_crtc, &test);
-	test.msc = check_msc(dpy, test.win, test.queue, test.msc);
+	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
 
 	printf("Testing each crtc, with future flips\n");
 	test.flags = FUTURE | SYNC;
-	test.msc = check_msc(dpy, test.win, test.queue, test.msc);
+	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
 	err += for_each_crtc(dpy, __test_crtc, &test);
-	test.msc = check_msc(dpy, test.win, test.queue, test.msc);
+	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
 
 	dri3_fence_free(dpy, &test.fence);
 	XSync(dpy, True);
@@ -1305,31 +1280,31 @@ int main(void)
 	XSetErrorHandler(_check_error_handler);
 
 	queue = setup_msc(dpy, root);
-	last_msc = check_msc(dpy, root, queue, 0);
+	last_msc = check_msc(dpy, root, queue, 0, NULL);
 
 	error += test_whole(dpy);
-	last_msc = check_msc(dpy, root, queue, last_msc);
+	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
 
 	error += test_future(dpy, queue);
-	last_msc = check_msc(dpy, root, queue, last_msc);
+	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
 
 	error += test_accuracy(dpy, queue);
-	last_msc = check_msc(dpy, root, queue, last_msc);
+	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
 
 	error += test_modulus(dpy, queue);
-	last_msc = check_msc(dpy, root, queue, last_msc);
+	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
 
 	error += test_exhaustion(dpy, queue);
-	last_msc = check_msc(dpy, root, queue, last_msc);
+	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
 
 	error += test_crtc(dpy, queue, last_msc);
-	last_msc = check_msc(dpy, root, queue, last_msc);
+	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
 
 	error += test_shm(dpy);
-	last_msc = check_msc(dpy, root, queue, last_msc);
+	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
 
 	error += test_dri3(dpy);
-	last_msc = check_msc(dpy, root, queue, last_msc);
+	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
 
 	teardown_msc(dpy, queue);
 
commit 9d4df75edb21b8fdef4b45cc8cda114ca55c54cb
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Feb 12 13:46:05 2015 +0000

    test/present: Check modulus computation
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/present-test.c b/test/present-test.c
index 3c84359..c8f340b 100644
--- a/test/present-test.c
+++ b/test/present-test.c
@@ -576,7 +576,7 @@ static int test_accuracy(Display *dpy, void *Q)
 	} while (!complete);
 	XSync(dpy, True);
 
-	target = check_msc(dpy, root, Q, 0);
+	target = check_msc(dpy, root, Q, target);
 	for (n = 0; n <= N_VBLANKS; n++)
 		xcb_present_pixmap(c, root, pixmap,
 				   target + 60 + n, /* serial */
@@ -635,12 +635,170 @@ static int test_accuracy(Display *dpy, void *Q)
 	if (late)
 		printf("\t%d frames shown too late (worst %d)!\n", late, latest);
 
+	XFreePixmap(dpy, pixmap);
+
+	XSync(dpy, True);
 	ret += !!_x_error_occurred;
 
 	return ret;
 #undef N_VBLANKS
 }
 
+static int test_modulus(Display *dpy, void *Q)
+{
+	xcb_connection_t *c = XGetXCBConnection(dpy);
+	Pixmap pixmap;
+	Window root;
+	unsigned int width, height;
+	unsigned border, depth;
+	xcb_xfixes_region_t region;
+	int x, y, ret = 0;
+	uint64_t target;
+	int early = 0, late = 0;
+	int earliest = 0, latest = 0;
+	int complete;
+
+	XGetGeometry(dpy, DefaultRootWindow(dpy),
+		     &root, &x, &y, &width, &height, &border, &depth);
+
+	printf("Testing whole screen flip modulus: %dx%d\n", width, height);
+	_x_error_occurred = 0;
+
+	target = check_msc(dpy, root, Q, 0);
+	pixmap = XCreatePixmap(dpy, root, width, height, depth);
+	xcb_present_pixmap(c, root, pixmap,
+			   0xdeadbeef, /* serial */
+			   0, /* valid */
+			   0, /* update */
+			   0, /* x_off */
+			   0, /* y_off */
+			   None,
+			   None, /* wait fence */
+			   None,
+			   XCB_PRESENT_OPTION_NONE,
+			   target + 60, /* target msc */
+			   0, /* divisor */
+			   0, /* remainder */
+			   0, NULL);
+	xcb_flush(c);
+	complete = 0;
+	do {
+		xcb_present_complete_notify_event_t *ce;
+		xcb_generic_event_t *ev;
+
+		ev = xcb_wait_for_special_event(c, Q);
+		if (ev == NULL)
+			break;
+
+		ce = (xcb_present_complete_notify_event_t *)ev;
+		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
+			break;
+
+		complete = ce->serial == 0xdeadbeef;
+		free(ev);
+	} while (!complete);
+	XSync(dpy, True);
+
+	region = xcb_generate_id(c);
+	xcb_xfixes_create_region(c, region, 0, NULL);
+
+	target = check_msc(dpy, root, Q, target);
+	for (x = 1; x <= 7; x++) {
+		for (y = 0; y < x; y++) {
+			xcb_present_pixmap(c, root, pixmap,
+					   y << 16 | x, /* serial */
+					   region, /* valid */
+					   region, /* update */
+					   0, /* x_off */
+					   0, /* y_off */
+					   None,
+					   None, /* wait fence */
+					   None,
+					   XCB_PRESENT_OPTION_NONE,
+					   0, /* target msc */
+					   x, /* divisor */
+					   y, /* remainder */
+					   0, NULL);
+		}
+	}
+	xcb_present_pixmap(c, root, pixmap,
+			   0xdeadbeef, /* serial */
+			   0, /* valid */
+			   0, /* update */
+			   0, /* x_off */
+			   0, /* y_off */
+			   None,
+			   None, /* wait fence */
+			   None,
+			   XCB_PRESENT_OPTION_NONE,
+			   target + 2*x, /* target msc */
+			   0, /* divisor */
+			   0, /* remainder */
+			   0, NULL);
+	xcb_flush(c);
+
+	complete = 0;
+	do {
+		xcb_present_complete_notify_event_t *ce;
+		xcb_generic_event_t *ev;
+
+		ev = xcb_wait_for_special_event(c, Q);
+		if (ev == NULL)
+			break;
+
+		ce = (xcb_present_complete_notify_event_t *)ev;
+		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
+			break;
+
+		assert(ce->serial);
+		if (ce->serial != 0xdeadbeef) {
+			uint64_t msc;
+			int diff;
+
+			x = ce->serial & 0xffff;
+			y = ce->serial >> 16;
+
+			msc = target;
+			msc -= target % x;
+			msc += y;
+			if (msc <= target)
+				msc += x;
+
+			diff = (int64_t)(ce->msc - msc);
+			if (diff < 0) {
+				ret += -diff;
+				if (-diff > earliest) {
+					fprintf(stderr, "\tframe (%d, %d) displayed early by %d frames\n", y, x, -diff);
+					earliest = -diff;
+				}
+				early++;
+			} else if (diff > 0) {
+				ret += diff;
+				if (diff > latest) {
+					fprintf(stderr, "\tframe (%d, %d) displayed late by %d frames\n", y, x, diff);
+					latest = diff;
+				}
+				late++;
+			}
+		} else
+			complete = 1;
+		free(ev);
+	} while (!complete);
+
+	if (early)
+		printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
+	if (late)
+		printf("\t%d frames shown too late (worst %d)!\n", late, latest);
+
+	XFreePixmap(dpy, pixmap);
+	xcb_xfixes_destroy_region(c, region);
+
+	XSync(dpy, True);
+	ret += !!_x_error_occurred;
+
+	return ret;
+}
+
 static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
 {
 	XRRScreenResources *res;
@@ -1158,6 +1316,9 @@ int main(void)
 	error += test_accuracy(dpy, queue);
 	last_msc = check_msc(dpy, root, queue, last_msc);
 
+	error += test_modulus(dpy, queue);
+	last_msc = check_msc(dpy, root, queue, last_msc);
+
 	error += test_exhaustion(dpy, queue);
 	last_msc = check_msc(dpy, root, queue, last_msc);
 
commit 51f184edfb2c09ea512c45cfe468a68406a8f6da
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Feb 12 12:49:57 2015 +0000

    test/present: Tighten the accuracy requirements
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/present-test.c b/test/present-test.c
index bd38977..3c84359 100644
--- a/test/present-test.c
+++ b/test/present-test.c
@@ -351,15 +351,18 @@ static int test_future(Display *dpy, void *Q)
 		} else {
 			int msc = (uint32_t)ce->msc - ce->serial;
 			if (msc < 0) {
-				fprintf(stderr, "\tframe %d displayed early by %lld frames\n", (int)(ce->serial - target - 60)/(15*60), (long long)msc);
 				ret += -msc;
-				if (-msc > earliest)
+				if (-msc > earliest) {
+					fprintf(stderr, "\tframe %d displayed early by %lld frames\n", (int)(ce->serial - target - 60)/(15*60), (long long)msc);
 					earliest = -msc;
+				}
 				early++;
-			} else if (msc > 1) { /* allow the frame to slip by a vblank */
+			} else if (msc > 0) {
 				ret += msc;
-				if (msc > latest)
+				if (msc > latest) {
+					fprintf(stderr, "\tframe %d displayed late by %lld frames\n", (int)(ce->serial - target - 60), (long long)msc);
 					latest = msc;
+				}
 				late++;
 			}
 		}
@@ -609,15 +612,18 @@ static int test_accuracy(Display *dpy, void *Q)
 
 		msc = (uint32_t)ce->msc - ce->serial;
 		if (msc < 0) {
-			fprintf(stderr, "\tframe %d displayed early by %lld frames\n", (int)(ce->serial - target - 60), (long long)msc);
 			ret += -msc;
-			if (-msc > earliest)
+			if (-msc > earliest) {
+				fprintf(stderr, "\tframe %d displayed early by %lld frames\n", (int)(ce->serial - target - 60), (long long)msc);
 				earliest = -msc;
+			}
 			early++;
-		} else if (msc > 1) { /* allow the frame to slip by a vblank */
+		} else if (msc > 0) {
 			ret += msc;
-			if (msc > latest)
+			if (msc > latest) {
+				fprintf(stderr, "\tframe %d displayed late by %lld frames\n", (int)(ce->serial - target - 60), (long long)msc);
 				latest = msc;
+			}
 			late++;
 		}
 		complete = ce->serial == target + 60 + N_VBLANKS;
commit ac1eb7f7c976b45b63b0ca3000ddfe1be2ccce62
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Feb 12 11:23:07 2015 +0000

    test/present: Test accuracy of long pauses
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c
index d9cb8e5..0f507b5 100644
--- a/src/sna/sna_present.c
+++ b/src/sna/sna_present.c
@@ -219,7 +219,7 @@ sna_present_vblank_handler(struct drm_event_vblank *event)
 {
 	struct sna_present_event *info = to_present_event(event->user_data);
 
-	DBG(("%s: pipe=%d tv=%d.%06d msc=%d (target=%lld), event %lld complete%s\n", __FUNCTION__,
+	DBG(("%s: pipe=%d tv=%d.%06d msc=%d (target=%lld), event=%lld complete%s\n", __FUNCTION__,
 	     sna_crtc_to_pipe(info->crtc),
 	     event->tv_sec, event->tv_usec, event->sequence,
 	     (long long)info->target_msc, (long long)info->event_id,
@@ -393,7 +393,7 @@ page_flip__async(struct sna *sna,
 		return FALSE;
 	}
 
-	DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event %lld complete\n", __FUNCTION__,
+	DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete\n", __FUNCTION__,
 	     pipe_from_crtc(crtc),
 	     gettime_ust64() / 1000000, gettime_ust64() % 1000000,
 	     (long long)sna_crtc_last_swap(crtc->devPrivate)->msc,
@@ -417,7 +417,7 @@ present_flip_handler(struct drm_event_vblank *event, void *data)
 	} else
 		swap = *sna_crtc_last_swap(info->crtc);
 
-	DBG(("%s: pipe=%d, tv=%d.%06d msc %lld (target %lld), event %lld complete%s\n", __FUNCTION__,
+	DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld (target %lld), event=%lld complete%s\n", __FUNCTION__,
 	     info->crtc ? sna_crtc_to_pipe(info->crtc) : -1,
 	     swap.tv_sec, swap.tv_usec, (long long)swap.msc,
 	     (long long)info->target_msc,
@@ -553,7 +553,7 @@ sna_present_unflip(ScreenPtr screen, uint64_t event_id)
 
 notify:
 		swap = sna_crtc_last_swap(sna_primary_crtc(sna));
-		DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, event %lld complete\n", __FUNCTION__,
+		DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld, event=%lld complete\n", __FUNCTION__,
 		     -1,
 		     swap->tv_sec, swap->tv_usec, (long long)swap->msc,
 		     (long long)event_id));
diff --git a/test/present-test.c b/test/present-test.c
index 9e5e96b..bd38977 100644
--- a/test/present-test.c
+++ b/test/present-test.c
@@ -243,6 +243,141 @@ static int test_whole(Display *dpy)
 
 static int test_future(Display *dpy, void *Q)
 {
+	xcb_connection_t *c = XGetXCBConnection(dpy);
+	Pixmap pixmap;
+	struct dri3_fence fence;
+	Window root;
+	unsigned int width, height;
+	unsigned border, depth;
+	int x, y, ret = 0, n;
+	uint64_t target;
+	int complete;
+	int early = 0, late = 0;
+	int earliest = 0, latest = 0;
+
+	XGetGeometry(dpy, DefaultRootWindow(dpy),
+		     &root, &x, &y, &width, &height, &border, &depth);
+
+	if (dri3_create_fence(dpy, root, &fence))
+		return 0;
+
+	printf("Testing whole screen flips into the future: %dx%d\n", width, height);
+	_x_error_occurred = 0;
+
+	target = check_msc(dpy, root, Q, 0);
+	pixmap = XCreatePixmap(dpy, root, width, height, depth);
+	xcb_present_pixmap(c, root, pixmap,
+			   0xdeadbeef, /* serial */
+			   0, /* valid */
+			   0, /* update */
+			   0, /* x_off */
+			   0, /* y_off */
+			   None,
+			   None, /* wait fence */
+			   None,
+			   XCB_PRESENT_OPTION_NONE,
+			   target + 60, /* target msc */
+			   0, /* divisor */
+			   0, /* remainder */
+			   0, NULL);
+	xcb_flush(c);
+	complete = 0;
+	do {
+		xcb_present_complete_notify_event_t *ce;
+		xcb_generic_event_t *ev;
+
+		ev = xcb_wait_for_special_event(c, Q);
+		if (ev == NULL)
+			break;
+
+		ce = (xcb_present_complete_notify_event_t *)ev;
+		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
+			break;
+
+		complete = ce->serial == 0xdeadbeef;
+		free(ev);
+	} while (!complete);
+	XSync(dpy, True);
+
+	target = check_msc(dpy, root, Q, 0);
+	for (n = 0; n <= 10; n++)
+		xcb_present_pixmap(c, root, pixmap,
+				   target + 60 + n*15*60, /* serial */
+				   0, /* valid */
+				   0, /* update */
+				   0, /* x_off */
+				   0, /* y_off */
+				   None,
+				   None, /* wait fence */
+				   None,
+				   XCB_PRESENT_OPTION_NONE,
+				   target + 60 + n*15*60, /* target msc */
+				   0, /* divisor */
+				   0, /* remainder */
+				   0, NULL);
+	xcb_present_pixmap(c, root, pixmap,
+			   0xdeadbeef, /* serial */
+			   0, /* valid */
+			   0, /* update */
+			   0, /* x_off */
+			   0, /* y_off */
+			   None,
+			   None, /* wait fence */
+			   None,
+			   XCB_PRESENT_OPTION_NONE,
+			   target + 60 + n*15*60, /* target msc */
+			   0, /* divisor */
+			   0, /* remainder */
+			   0, NULL);
+	xcb_flush(c);
+
+	complete = 0;
+	do {
+		xcb_present_complete_notify_event_t *ce;
+		xcb_generic_event_t *ev;
+
+		ev = xcb_wait_for_special_event(c, Q);
+		if (ev == NULL)
+			break;
+
+		ce = (xcb_present_complete_notify_event_t *)ev;
+		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
+			break;
+
+		assert(ce->serial);
+
+		if (ce->serial == 0xdeadbeef) {
+			complete = 1;
+		} else {
+			int msc = (uint32_t)ce->msc - ce->serial;
+			if (msc < 0) {
+				fprintf(stderr, "\tframe %d displayed early by %lld frames\n", (int)(ce->serial - target - 60)/(15*60), (long long)msc);
+				ret += -msc;
+				if (-msc > earliest)
+					earliest = -msc;
+				early++;
+			} else if (msc > 1) { /* allow the frame to slip by a vblank */
+				ret += msc;
+				if (msc > latest)
+					latest = msc;
+				late++;
+			}
+		}
+		free(ev);
+	} while (!complete);
+
+	if (early)
+		printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
+	if (late)
+		printf("\t%d frames shown too late (worst %d)!\n", late, latest);
+
+	ret += !!_x_error_occurred;
+
+	return ret;
+}
+
+static int test_exhaustion(Display *dpy, void *Q)
+{
 #define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */
 	xcb_connection_t *c = XGetXCBConnection(dpy);
 	Pixmap pixmap;
@@ -261,7 +396,7 @@ static int test_future(Display *dpy, void *Q)
 	if (dri3_create_fence(dpy, root, &fence))
 		return 0;
 
-	printf("Testing whole screen flips into the future: %dx%d\n", width, height);
+	printf("Testing whole screen flips with long vblank queues: %dx%d\n", width, height);
 	_x_error_occurred = 0;
 
 	region = xcb_generate_id(c);
@@ -304,11 +439,11 @@ static int test_future(Display *dpy, void *Q)
 
 	final = check_msc(dpy, root, Q, 0);
 	if (final < target) {
-		printf("First flip too early, MSC was %llu, expected %llu\n",
+		printf("\tFirst flip too early, MSC was %llu, expected %llu\n",
 		       (long long)final, (long long)target);
 		ret++;
 	} else if (final > target + 1) {
-		printf("First flip too late, MSC was %llu, expected %llu\n",
+		printf("\tFirst flip too late, MSC was %llu, expected %llu\n",
 		       (long long)final, (long long)target);
 		ret++;
 	}
@@ -332,11 +467,11 @@ static int test_future(Display *dpy, void *Q)
 
 	final = check_msc(dpy, root, Q, 0);
 	if (final < target + N_VBLANKS) {
-		printf("Last flip too early, MSC was %llu, expected %llu\n",
+		printf("\tLast flip too early, MSC was %llu, expected %llu\n",
 		       (long long)final, (long long)(target + N_VBLANKS));
 		ret++;
 	} else if (final > target + N_VBLANKS + 1) {
-		printf("Last flip too late, MSC was %llu, expected %llu\n",
+		printf("\tLast flip too late, MSC was %llu, expected %llu\n",
 		       (long long)final, (long long)(target + N_VBLANKS));
 		ret++;
 	}
@@ -394,6 +529,7 @@ static int test_accuracy(Display *dpy, void *Q)
 	int x, y, ret = 0, n;
 	uint64_t target;
 	int early = 0, late = 0;
+	int earliest = 0, latest = 0;
 	int complete;
 
 	XGetGeometry(dpy, DefaultRootWindow(dpy),
@@ -471,13 +607,17 @@ static int test_accuracy(Display *dpy, void *Q)
 
 		assert(ce->serial);
 
-		msc = ce->msc - ce->serial;
+		msc = (uint32_t)ce->msc - ce->serial;
 		if (msc < 0) {
-			fprintf(stderr, "frame %d displayed early by %lld frames\n", (int)(ce->serial - target - 60), (long long)msc);
+			fprintf(stderr, "\tframe %d displayed early by %lld frames\n", (int)(ce->serial - target - 60), (long long)msc);
 			ret += -msc;
+			if (-msc > earliest)
+				earliest = -msc;
 			early++;
 		} else if (msc > 1) { /* allow the frame to slip by a vblank */
 			ret += msc;
+			if (msc > latest)
+				latest = msc;
 			late++;
 		}
 		complete = ce->serial == target + 60 + N_VBLANKS;
@@ -485,11 +625,9 @@ static int test_accuracy(Display *dpy, void *Q)
 	} while (!complete);
 
 	if (early)
-		printf("%d frames shown too early! ", early);
+		printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
 	if (late)
-		printf("%d fames shown too late!", late);
-	if (early|late)
-		printf("\n");
+		printf("\t%d frames shown too late (worst %d)!\n", late, latest);
 
 	ret += !!_x_error_occurred;
 
@@ -542,8 +680,6 @@ static int for_each_crtc(Display *dpy,
 	for (i = 0; i < res->ncrtc; i++)
 		original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
 
-	printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
-
 	for (i = 0; i < res->noutput; i++) {
 		XRROutputInfo *output;
 		XRRModeInfo *mode;
@@ -1016,6 +1152,9 @@ int main(void)
 	error += test_accuracy(dpy, queue);
 	last_msc = check_msc(dpy, root, queue, last_msc);
 
+	error += test_exhaustion(dpy, queue);
+	last_msc = check_msc(dpy, root, queue, last_msc);
+
 	error += test_crtc(dpy, queue, last_msc);
 	last_msc = check_msc(dpy, root, queue, last_msc);
 
commit 818b596a6a4dddea29f92f52d73a3577ef16c8b2
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Feb 12 12:12:29 2015 +0000

    sna/present: Store target_msc for DBG output in flip handler
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c
index e578803..d9cb8e5 100644
--- a/src/sna/sna_present.c
+++ b/src/sna/sna_present.c
@@ -219,11 +219,11 @@ sna_present_vblank_handler(struct drm_event_vblank *event)
 {
 	struct sna_present_event *info = to_present_event(event->user_data);
 
-	DBG(("%s: pipe=%d tv=%d.%06d msc=%d, event %lld complete: target_msc=%lld\n", __FUNCTION__,
+	DBG(("%s: pipe=%d tv=%d.%06d msc=%d (target=%lld), event %lld complete%s\n", __FUNCTION__,
 	     sna_crtc_to_pipe(info->crtc),
 	     event->tv_sec, event->tv_usec, event->sequence,
-	     (long long)info->event_id,
-	     (long long)info->target_msc));
+	     (long long)info->target_msc, (long long)info->event_id,
+	     info->target_msc && event->sequence == (uint32_t)info->target_msc ? "" : ": MISS"));
 	present_event_notify(info->event_id,
 			     ust64(event->tv_sec, event->tv_usec),
 			     sna_crtc_record_event(info->crtc, event));
@@ -234,32 +234,38 @@ static int
 sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 {
 	struct sna *sna = to_sna_from_screen(crtc->pScreen);
-	struct sna_present_event *event;
+	struct sna_present_event *info;
+	const struct ust_msc *swap;
 	union drm_wait_vblank vbl;
 
 	DBG(("%s(pipe=%d, event=%lld, msc=%lld)\n",
 	     __FUNCTION__, pipe_from_crtc(crtc),
 	     (long long)event_id, (long long)msc));
 
-	event = malloc(sizeof(struct sna_present_event));
-	if (event == NULL)
-		return BadAlloc;
+	swap = sna_crtc_last_swap(crtc->devPrivate);
+	assert((int64_t)(msc - swap->msc) >= 0);
+	if ((int64_t)(msc - swap->msc) <= 0) {
+		present_event_notify(event_id, swap_ust(swap), swap->msc);
+		return Success;
+	}
 
-	event->crtc = crtc->devPrivate;
-	event->sna = sna;
-	event->target_msc = msc;
-	event->event_id = event_id;
+	info = malloc(sizeof(struct sna_present_event));
+	if (info == NULL)
+		return BadAlloc;
 
-	assert((int64_t)(msc - sna_crtc_last_swap(event->crtc)->msc) >= 0);
+	info->crtc = crtc->devPrivate;
+	info->sna = sna;
+	info->target_msc = msc;
+	info->event_id = event_id;
 
 	VG_CLEAR(vbl);
 	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
 	vbl.request.sequence = msc;
-	vbl.request.signal = (uintptr_t)MARK_PRESENT(event);
-	if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(event->crtc))) {
+	vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
+	if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(info->crtc))) {
 		DBG(("%s: vblank enqueue failed\n", __FUNCTION__));
-		if (!sna_fake_vblank(event)) {
-			free(event);
+		if (!sna_fake_vblank(info)) {
+			free(info);
 			return BadAlloc;
 		}
 	}
@@ -387,11 +393,11 @@ page_flip__async(struct sna *sna,
 		return FALSE;
 	}
 
-	DBG(("%s: pipe=%d tv=%d.%06d msc=%d, event %lld complete\n", __FUNCTION__,
+	DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event %lld complete\n", __FUNCTION__,
 	     pipe_from_crtc(crtc),
 	     gettime_ust64() / 1000000, gettime_ust64() % 1000000,
-	     sna_crtc_last_swap(crtc->devPrivate)->msc,
-	     (long long)event_id));
+	     (long long)sna_crtc_last_swap(crtc->devPrivate)->msc,
+	     (long long)target_msc, (long long)event_id));
 	present_event_notify(event_id, gettime_ust64(), target_msc);
 	return TRUE;
 }
@@ -411,10 +417,12 @@ present_flip_handler(struct drm_event_vblank *event, void *data)
 	} else
 		swap = *sna_crtc_last_swap(info->crtc);
 
-	DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, event %lld complete\n", __FUNCTION__,
+	DBG(("%s: pipe=%d, tv=%d.%06d msc %lld (target %lld), event %lld complete%s\n", __FUNCTION__,
 	     info->crtc ? sna_crtc_to_pipe(info->crtc) : -1,
 	     swap.tv_sec, swap.tv_usec, (long long)swap.msc,
-	     (long long)info->event_id));
+	     (long long)info->target_msc,
+	     (long long)info->event_id,
+	     info->target_msc && info->target_msc == swap.msc ? "" : ": MISS"));
 	present_event_notify(info->event_id, swap_ust(&swap), swap.msc);
 
 	if (info->sna->present.unflip) {
@@ -430,9 +438,10 @@ static Bool
 page_flip(struct sna *sna,
 	  RRCrtcPtr crtc,
 	  uint64_t event_id,
+	  uint64_t target_msc,
 	  struct kgem_bo *bo)
 {
-	struct sna_present_event *event;
+	struct sna_present_event *info;
 
 	DBG(("%s(pipe=%d, event=%lld, handle=%d)\n",
 	     __FUNCTION__,
@@ -440,18 +449,18 @@ page_flip(struct sna *sna,
 	     (long long)event_id,
 	     bo->handle));
 
-	event = malloc(sizeof(struct sna_present_event));
-	if (event == NULL)
+	info = malloc(sizeof(struct sna_present_event));
+	if (info == NULL)
 		return FALSE;
 
-	event->crtc = crtc ? crtc->devPrivate : NULL;
-	event->sna = sna;
-	event->event_id = event_id;
-	event->target_msc = 0;
+	info->crtc = crtc ? crtc->devPrivate : NULL;
+	info->sna = sna;
+	info->event_id = event_id;
+	info->target_msc = target_msc;
 
-	if (!sna_page_flip(sna, bo, present_flip_handler, event)) {
+	if (!sna_page_flip(sna, bo, present_flip_handler, info)) {
 		DBG(("%s: pageflip failed\n", __FUNCTION__));
-		free(event);
+		free(info);
 		return FALSE;
 	}
 
@@ -525,7 +534,7 @@ sna_present_flip(RRCrtcPtr crtc,
 	}
 
 	if (sync_flip)
-		return page_flip(sna, crtc, event_id, bo);
+		return page_flip(sna, crtc, event_id, target_msc, bo);
 	else
 		return page_flip__async(sna, crtc, event_id, target_msc, bo);
 }
@@ -573,7 +582,7 @@ reset_mode:
 			return;
 	}
 
-	if (!page_flip(sna, NULL, event_id, bo))
+	if (!page_flip(sna, NULL, event_id, 0, bo))
 		goto reset_mode;
 }
 


More information about the xorg-commit mailing list