xf86-video-intel: 6 commits - src/sna/sna_dri2.c src/sna/sna_driver.c test/dri2-test.c

Chris Wilson ickle at kemper.freedesktop.org
Fri May 23 01:55:14 PDT 2014


 src/sna/sna_dri2.c   |  384 +++++++++++++++++++++++----------------------------
 src/sna/sna_driver.c |    4 
 test/dri2-test.c     |   64 +++++---
 3 files changed, 221 insertions(+), 231 deletions(-)

New commits:
commit 43fd06ee7d95db4114ce7b0261685380a48a8708
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 23 09:03:17 2014 +0100

    sna/dri2: Adjust current msc / target seq between CRTCs
    
    The target_msc supplied by the client is required to be monotonic. Since
    the client does not know which CRTC the window is on, they do not
    control from which pipe we derive the MSC, and so we need to adjust the
    hardware values such that the client only ever sees a monotonic value.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index d195856..20995d5 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -884,7 +884,9 @@ inline static uint32_t pipe_select(int pipe)
 
 static inline int sna_wait_vblank(struct sna *sna, union drm_wait_vblank *vbl, int pipe)
 {
-	DBG(("%s(pipe=%d)\n", __FUNCTION__, pipe));
+	DBG(("%s(pipe=%d, waiting until seq=%u%s)\n",
+	     __FUNCTION__, pipe, vbl->request.sequence,
+	     vbl->request.type & DRM_VBLANK_RELATIVE ? " [relative]" : ""));
 	assert(pipe != -1);
 
 	vbl->request.type |= pipe_select(pipe);
@@ -1355,9 +1357,10 @@ static void chain_swap(struct sna *sna, DrawablePtr draw, struct sna_dri2_frame_
 			vbl.request.sequence = 1;
 			vbl.request.signal = (unsigned long)chain;
 
-			chain->queued = true;
-			if (!sna_wait_vblank(sna, &vbl, chain->pipe))
+			if (!sna_wait_vblank(sna, &vbl, chain->pipe)) {
+				chain->queued = true;
 				return;
+			}
 
 			DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
 		}
@@ -1852,11 +1855,68 @@ sna_dri2_page_flip_handler(struct sna *sna,
 	sna_dri2_flip_event(sna, info);
 }
 
-static CARD64
-get_current_msc(struct sna *sna, xf86CrtcPtr crtc)
+struct window_crtc {
+	xf86CrtcPtr crtc;
+	int64_t msc_delta;
+};
+
+static struct window_crtc *window_get_crtc(WindowPtr win)
+{
+	return ((void **)__get_private(win, sna_window_key))[3];
+}
+
+static void window_set_crtc(WindowPtr win, struct window_crtc *wc)
+{
+	assert(win->drawable.type == DRAWABLE_WINDOW);
+	assert(window_get_crtc(win) == NULL);
+	((void **)__get_private(win, sna_window_key))[3] = wc;
+	assert(window_get_crtc(win) == wc);
+}
+
+static uint64_t
+draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
+{
+	struct window_crtc *wc = window_get_crtc((WindowPtr)draw);
+	if (wc == NULL) {
+		wc = malloc(sizeof(*wc));
+		if (wc != NULL) {
+			wc->crtc = crtc;
+			wc->msc_delta = 0;
+			window_set_crtc((WindowPtr)draw, wc);
+		}
+	} else {
+		if (wc->crtc != crtc) {
+			const struct ust_msc *last = sna_crtc_last_swap(wc->crtc);
+			const struct ust_msc *this = sna_crtc_last_swap(crtc);
+			DBG(("%s: Window transferring from pipe=%d [msc=%llu] to pipe=%d [msc=%llu], delta now %lld\n",
+			     __FUNCTION__,
+			     sna_crtc_to_pipe(wc->crtc), (long long)last->msc,
+			     sna_crtc_to_pipe(crtc), (long long)this->msc,
+			     (long long)(wc->msc_delta + this->msc - last->msc)));
+			wc->msc_delta += this->msc - last->msc;
+			wc->crtc = crtc;
+		}
+		msc -= wc->msc_delta;
+	}
+	return  msc;
+}
+
+static uint32_t
+draw_target_seq(DrawablePtr draw, uint64_t msc)
+{
+	struct window_crtc *wc = window_get_crtc((WindowPtr)draw);
+	if (wc == NULL)
+		return msc;
+	DBG(("%s: converting target_msc=%llu to seq %u\n",
+	     __FUNCTION__, (long long)msc, (unsigned)(msc + wc->msc_delta)));
+	return msc + wc->msc_delta;
+}
+
+static uint64_t
+get_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc)
 {
 	union drm_wait_vblank vbl;
-	CARD64 ret = -1;
+	uint64_t ret = -1;
 
 	VG_CLEAR(vbl);
 	vbl.request.type = DRM_VBLANK_RELATIVE;
@@ -1864,7 +1924,7 @@ get_current_msc(struct sna *sna, xf86CrtcPtr crtc)
 	if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
 		ret = sna_crtc_record_vblank(crtc, &vbl);
 
-	return ret;
+	return draw_current_msc(draw, crtc, ret);
 }
 
 #if !XORG_CAN_TRIPLE_BUFFER && XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
@@ -1912,6 +1972,7 @@ static int use_triple_buffer(struct sna *sna, ClientPtr client, bool async)
 static bool immediate_swap(struct sna *sna,
 			   uint64_t target_msc,
 			   uint64_t divisor,
+			   DrawablePtr draw,
 			   xf86CrtcPtr crtc,
 			   uint64_t *current_msc)
 {
@@ -1924,7 +1985,7 @@ static bool immediate_swap(struct sna *sna,
 		}
 
 		if (target_msc)
-			*current_msc = get_current_msc(sna, crtc);
+			*current_msc = get_current_msc(sna, draw, crtc);
 
 		DBG(("%s: current_msc=%ld, target_msc=%ld -- %s\n",
 		     __FUNCTION__, (long)*current_msc, (long)target_msc,
@@ -1934,7 +1995,7 @@ static bool immediate_swap(struct sna *sna,
 
 	DBG(("%s: explicit waits requests, divisor=%ld\n",
 	     __FUNCTION__, (long)divisor));
-	*current_msc = get_current_msc(sna, crtc);
+	*current_msc = get_current_msc(sna, draw, crtc);
 	return false;
 }
 
@@ -1947,9 +2008,9 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 	struct sna *sna = to_sna_from_drawable(draw);
 	struct sna_dri2_frame_event *info;
 	int pipe = sna_crtc_to_pipe(crtc);
-	CARD64 current_msc;
+	uint64_t current_msc;
 
-	if (immediate_swap(sna, *target_msc, divisor, crtc, &current_msc)) {
+	if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
 		int type;
 
 		info = sna->dri2.flip_pending;
@@ -2090,17 +2151,16 @@ out:
 			DRM_VBLANK_EVENT;
 
 		/* Account for 1 frame extra pageflip delay */
-		vbl.reply.sequence = *target_msc - 1;
-		DBG(("%s: flip adjusted sequence = %d\n",
-		     __FUNCTION__, vbl.request.sequence));
-
+		vbl.reply.sequence = draw_target_seq(draw, *target_msc - 1);
 		vbl.request.signal = (unsigned long)info;
+
 		if (sna_wait_vblank(sna, &vbl, pipe)) {
 			sna_dri2_frame_event_info_free(sna, draw, info);
 			return false;
 		}
 	}
 
+	DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc));
 	info->queued = true;
 	swap_limit(draw, 1);
 	return true;
@@ -2205,7 +2265,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 
 	info->type = SWAP;
 
-	if (immediate_swap(sna, *target_msc, divisor, info->crtc, &current_msc)) {
+	if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
 		bool sync = current_msc < *target_msc;
 		if (!sna_dri2_immediate_blit(sna, info, sync, true))
 			sna_dri2_frame_event_info_free(sna, draw, info);
@@ -2237,7 +2297,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		if (*target_msc <= current_msc)
 			*target_msc += divisor;
 	}
-	vbl.request.sequence = *target_msc - 1;
+	vbl.request.sequence = draw_target_seq(draw, *target_msc - 1);
 	if (*target_msc <= current_msc + 1) {
 		DBG(("%s: performing blit before queueing\n", __FUNCTION__));
 		info->bo = __sna_dri2_copy_region(sna, draw, NULL,
@@ -2255,6 +2315,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	if (sna_wait_vblank(sna, &vbl, info->pipe))
 		goto blit;
 
+	DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc));
 	info->queued = true;
 	swap_limit(draw, 1 + (info->type == SWAP_WAIT));
 	return TRUE;
@@ -2292,7 +2353,7 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
 fail:
 		/* Drawable not displayed, make up a *monotonic* value */
 		swap = sna_crtc_last_swap(crtc);
-		*msc = swap->msc;
+		*msc = draw_current_msc(draw, crtc, swap->msc);
 		*ust = ust64(swap->tv_sec, swap->tv_usec);
 		return TRUE;
 	}
@@ -2302,7 +2363,7 @@ fail:
 	vbl.request.sequence = 0;
 	if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0) {
 		*ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
-		*msc = sna_crtc_record_vblank(crtc, &vbl);
+		*msc = draw_current_msc(draw, crtc, sna_crtc_record_vblank(crtc, &vbl));
 		DBG(("%s: msc=%llu, ust=%llu\n", __FUNCTION__,
 		     (long long)*msc, (long long)*ust));
 	} else {
@@ -2353,7 +2414,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 	if (sna_wait_vblank(sna, &vbl, pipe))
 		goto out_complete;
 
-	current_msc = sna_crtc_record_vblank(crtc, &vbl);
+	current_msc = draw_current_msc(draw, crtc, sna_crtc_record_vblank(crtc, &vbl));
 
 	/* If target_msc already reached or passed, set it to
 	 * current_msc to ensure we return a reasonable value back
@@ -2394,9 +2455,8 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 		if (target_msc <= current_msc)
 			target_msc += divisor;
 	}
-	vbl.request.sequence = target_msc;
+	vbl.request.sequence = draw_target_seq(draw, target_msc);
 
-	DBG(("%s: waiting until MSC=%llu\n", __FUNCTION__, (long long)vbl.request.sequence));
 	if (sna_wait_vblank(sna, &vbl, pipe))
 		goto out_free_info;
 
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index f609254..fffb6ec 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -896,7 +896,7 @@ sna_register_all_privates(void)
 		return FALSE;
 
 	if (!dixRegisterPrivateKey(&sna_window_key, PRIVATE_WINDOW,
-				   3*sizeof(void *)))
+				   4*sizeof(void *)))
 		return FALSE;
 
 	if (!dixRegisterPrivateKey(&sna_client_key, PRIVATE_CLIENT,
@@ -912,7 +912,7 @@ sna_register_all_privates(void)
 	if (!dixRequestPrivate(&sna_glyph_key, sizeof(struct sna_glyph)))
 		return FALSE;
 
-	if (!dixRequestPrivate(&sna_window_key, 3*sizeof(void *)))
+	if (!dixRequestPrivate(&sna_window_key, 4*sizeof(void *)))
 		return FALSE;
 
 	if (!dixRequestPrivate(&sna_client_key, sizeof(struct sna_client)))
commit c8decdbccdefa87b635d871a8295608961f0d22e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 23 09:13:31 2014 +0100

    test/dri2: Check validity of MSC across CRTC
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/dri2-test.c b/test/dri2-test.c
index f712f12..d8ff3d9 100644
--- a/test/dri2-test.c
+++ b/test/dri2-test.c
@@ -83,15 +83,6 @@ static void dri2_copy_swap(Display *dpy, Drawable d,
 	XFixesDestroyRegion(dpy, region);
 }
 
-static void xsync(Display *dpy, Window win)
-{
-	XImage *image;
-
-	image = XGetImage(dpy, win, 0, 0, 1, 1, ~0, ZPixmap);
-	if (image)
-		XDestroyImage(image);
-}
-
 static double elapsed(const struct timespec *start,
 		      const struct timespec *end)
 {
@@ -99,6 +90,17 @@ static double elapsed(const struct timespec *start,
 		1e-9*(end->tv_nsec - start->tv_nsec);
 }
 
+static uint64_t check_msc(Display *dpy, Window win, uint64_t last_msc)
+{
+	uint64_t current_msc, current_ust, current_sbc;
+	DRI2GetMSC(dpy, win, &current_ust, &current_msc, &current_sbc);
+	if (current_msc < last_msc) {
+		printf("Invalid MSC: was %llu, now %llu\n",
+		       (long long)last_msc, (long long)current_msc);
+	}
+	return current_msc;
+}
+
 static void run(Display *dpy, int width, int height,
 		unsigned int *attachments, int nattachments,
 		const char *name)
@@ -108,6 +110,7 @@ static void run(Display *dpy, int width, int height,
 	int count;
 	DRI2Buffer *buffers;
 	struct timespec start, end;
+	uint64_t msc;
 
 	/* Be nasty and install a fullscreen window on top so that we
 	 * can guarantee we do not get clipped by children.
@@ -120,29 +123,29 @@ static void run(Display *dpy, int width, int height,
 			 DefaultVisual(dpy, DefaultScreen(dpy)),
 			 CWOverrideRedirect, &attr);
 	XMapWindow(dpy, win);
-	xsync(dpy, win);
 
 	DRI2CreateDrawable(dpy, win);
+	msc = check_msc(dpy, win, 0);
 
 	buffers = DRI2GetBuffers(dpy, win, &width, &height,
 				 attachments, nattachments, &count);
 	if (count != nattachments)
 		return;
 
-	xsync(dpy, win);
+	msc = check_msc(dpy, win, msc);
 	clock_gettime(CLOCK_MONOTONIC, &start);
 	for (count = 0; count < COUNT; count++)
 		DRI2SwapBuffers(dpy, win, 0, 0, 0);
-	xsync(dpy, win);
+	msc = check_msc(dpy, win, msc);
 	clock_gettime(CLOCK_MONOTONIC, &end);
 	printf("%d %s (%dx%d) swaps in %fs.\n",
 	       count, name, width, height, elapsed(&start, &end));
 
-	xsync(dpy, win);
+	msc = check_msc(dpy, win, msc);
 	clock_gettime(CLOCK_MONOTONIC, &start);
 	for (count = 0; count < COUNT; count++)
 		dri2_copy_swap(dpy, win, width, height, nattachments == 2);
-	xsync(dpy, win);
+	msc = check_msc(dpy, win, msc);
 	clock_gettime(CLOCK_MONOTONIC, &end);
 
 	printf("%d %s (%dx%d) blits in %fs.\n",
@@ -150,11 +153,11 @@ static void run(Display *dpy, int width, int height,
 
 	DRI2SwapInterval(dpy, win, 0);
 
-	xsync(dpy, win);
+	msc = check_msc(dpy, win, msc);
 	clock_gettime(CLOCK_MONOTONIC, &start);
 	for (count = 0; count < COUNT; count++)
 		DRI2SwapBuffers(dpy, win, 0, 0, 0);
-	xsync(dpy, win);
+	msc = check_msc(dpy, win, msc);
 	clock_gettime(CLOCK_MONOTONIC, &end);
 	printf("%d %s (%dx%d) vblank=0 swaps in %fs.\n",
 	       count, name, width, height, elapsed(&start, &end));
@@ -174,6 +177,8 @@ int main(void)
 		DRI2BufferFrontLeft,
 	};
 	XRRScreenResources *res;
+	Window root;
+	uint64_t last_msc;
 
 	dpy = XOpenDisplay(NULL);
 	if (dpy == NULL)
@@ -186,16 +191,19 @@ int main(void)
 	if (fd < 0)
 		return 1;
 
-	res = _XRRGetScreenResourcesCurrent(dpy, DefaultRootWindow(dpy));
+	root = DefaultRootWindow(dpy);
+	DRI2CreateDrawable(dpy, root);
+
+	res = _XRRGetScreenResourcesCurrent(dpy, root);
 	if (res == NULL)
 		return 1;
 
 	printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
-
+	last_msc = check_msc(dpy, root, 0);
 	for (i = 0; i < res->ncrtc; i++)
 		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
 				 0, 0, None, RR_Rotate_0, NULL, 0);
-	XSync(dpy, True);
+	last_msc = check_msc(dpy, root, last_msc);
 
 	for (i = 0; i < res->noutput; i++) {
 		XRROutputInfo *output;
@@ -209,12 +217,17 @@ int main(void)
 		if (res->nmode)
 			mode = lookup_mode(res, output->modes[0]);
 
-		for (j = 0; mode && j < output->ncrtc; j++) {
+		for (j = 0; mode && j < 2*output->ncrtc; j++) {
+			int c = j;
+			if (c >= output->ncrtc)
+				c = 2*output->ncrtc - j - 1;
+
 			printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld\n",
-			       i, j, (long)res->outputs[i], (long)output->crtcs[j]);
-			XRRSetCrtcConfig(dpy, res, output->crtcs[j], CurrentTime,
+			       i, c, (long)res->outputs[i], (long)output->crtcs[c]);
+			last_msc = check_msc(dpy, root, last_msc);
+			XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
 					 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
-			XSync(dpy, True);
+			last_msc = check_msc(dpy, root, last_msc);
 
 			run(dpy, mode->width, mode->height, attachments, 1, "fullscreen");
 			run(dpy, mode->width, mode->height, attachments, 2, "fullscreen (with front)");
@@ -222,9 +235,10 @@ int main(void)
 			run(dpy, mode->width/2, mode->height/2, attachments, 1, "windowed");
 			run(dpy, mode->width/2, mode->height/2, attachments, 2, "windowed (with front)");
 
-			XRRSetCrtcConfig(dpy, res, output->crtcs[j], CurrentTime,
+			last_msc = check_msc(dpy, root, last_msc);
+			XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
 					 0, 0, None, RR_Rotate_0, NULL, 0);
-			XSync(dpy, True);
+			last_msc = check_msc(dpy, root, last_msc);
 		}
 
 		XRRFreeOutputInfo(output);
commit a6613a8fe3908433ee33a167f57a0fae4e785a22
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu May 22 23:48:20 2014 +0100

    sna/dri2: Queue the flip immediately for the next frame
    
    If we compute that we want to flip on the next frame, queue it
    immediately rather than take a round trip through the kernel and risk
    missing the vblank.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 9c655f9..d195856 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -1947,7 +1947,6 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 	struct sna *sna = to_sna_from_drawable(draw);
 	struct sna_dri2_frame_event *info;
 	int pipe = sna_crtc_to_pipe(crtc);
-	union drm_wait_vblank vbl;
 	CARD64 current_msc;
 
 	if (immediate_swap(sna, *target_msc, divisor, crtc, &current_msc)) {
@@ -2057,12 +2056,6 @@ out:
 	sna_dri2_reference_buffer(front);
 	sna_dri2_reference_buffer(back);
 
-	VG_CLEAR(vbl);
-
-	vbl.request.type =
-		DRM_VBLANK_ABSOLUTE |
-		DRM_VBLANK_EVENT;
-
 	/*
 	 * If divisor is zero, or current_msc is smaller than target_msc
 	 * we just need to make sure target_msc passes before initiating
@@ -2081,15 +2074,31 @@ out:
 			*target_msc += divisor;
 	}
 
-	/* Account for 1 frame extra pageflip delay */
-	vbl.reply.sequence = *target_msc - 1;
-	DBG(("%s: flip adjusted sequence = %d\n",
-	     __FUNCTION__, vbl.request.sequence));
+	if (*target_msc <= current_msc + 1) {
+		if (!sna_dri2_page_flip(sna, info)) {
+			sna_dri2_frame_event_info_free(sna, draw, info);
+			return false;
+		}
+		*target_msc = current_msc + 1;
+	} else {
+		union drm_wait_vblank vbl;
 
-	vbl.request.signal = (unsigned long)info;
-	if (sna_wait_vblank(sna, &vbl, pipe)) {
-		sna_dri2_frame_event_info_free(sna, draw, info);
-		return false;
+		VG_CLEAR(vbl);
+
+		vbl.request.type =
+			DRM_VBLANK_ABSOLUTE |
+			DRM_VBLANK_EVENT;
+
+		/* Account for 1 frame extra pageflip delay */
+		vbl.reply.sequence = *target_msc - 1;
+		DBG(("%s: flip adjusted sequence = %d\n",
+		     __FUNCTION__, vbl.request.sequence));
+
+		vbl.request.signal = (unsigned long)info;
+		if (sna_wait_vblank(sna, &vbl, pipe)) {
+			sna_dri2_frame_event_info_free(sna, draw, info);
+			return false;
+		}
 	}
 
 	info->queued = true;
commit 24443c6c897278a8a196bf4a8df9fab4485f38b4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu May 22 22:47:35 2014 +0100

    sna/dri2: Tidy computation of target sequence
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index d82b1d0..9c655f9 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -2057,9 +2057,6 @@ out:
 	sna_dri2_reference_buffer(front);
 	sna_dri2_reference_buffer(back);
 
-	*target_msc &= 0xffffffff;
-	remainder &= 0xffffffff;
-
 	VG_CLEAR(vbl);
 
 	vbl.request.type =
@@ -2071,49 +2068,24 @@ out:
 	 * we just need to make sure target_msc passes before initiating
 	 * the swap.
 	 */
-	if (current_msc < *target_msc) {
-		DBG(("%s: waiting for swap: current=%d, target=%d, divisor=%d\n",
-		     __FUNCTION__,
-		     (int)current_msc,
-		     (int)*target_msc,
-		     (int)divisor));
-		vbl.request.sequence = *target_msc - 1;
-	} else {
-		DBG(("%s: missed target, queueing event for next: current=%d, target=%d, divisor=%d, remainder=%d\n",
+	if (divisor && current_msc >= *target_msc) {
+		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
 		     __FUNCTION__,
-		     (int)current_msc,
-		     (int)*target_msc,
-		     (int)divisor,
-		     (int)remainder));
-
-		*target_msc = current_msc;
-		if (divisor)
-			*target_msc += remainder - current_msc % divisor;
-
-		DBG(("%s: initial sequence = %lld\n", __FUNCTION__,
-		     (long long)*target_msc));
+		     (long long)current_msc,
+		     (long long)*target_msc,
+		     (long long)divisor,
+		     (long long)remainder));
 
-		/*
-		 * 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.
-		 */
-		*target_msc -= 1;
+		*target_msc = current_msc + remainder - current_msc % divisor;
 		if (*target_msc <= current_msc)
 			*target_msc += divisor;
-
-		vbl.reply.sequence = *target_msc;
-		DBG(("%s: flip adjusted sequence = %d\n",
-		     __FUNCTION__, vbl.request.sequence));
 	}
 
 	/* Account for 1 frame extra pageflip delay */
+	vbl.reply.sequence = *target_msc - 1;
+	DBG(("%s: flip adjusted sequence = %d\n",
+	     __FUNCTION__, vbl.request.sequence));
+
 	vbl.request.signal = (unsigned long)info;
 	if (sna_wait_vblank(sna, &vbl, pipe)) {
 		sna_dri2_frame_event_info_free(sna, draw, info);
@@ -2243,57 +2215,32 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	 * we just need to make sure target_msc passes before initiating
 	 * the swap.
 	 */
-	if (current_msc < *target_msc) {
-		DBG(("%s: waiting for swap: current=%d, target=%d, divisor=%d\n",
-		     __FUNCTION__,
-		     (int)current_msc,
-		     (int)*target_msc,
-		     (int)divisor));
-
-		info->type = SWAP;
-
-		vbl.request.sequence = *target_msc - 1;
-	} else {
-		/*
-		 * If we get here, target_msc has already passed or we don't have one,
-		 * and we need to queue an event that will satisfy the divisor/remainder
-		 * equation.
-		 */
-		DBG(("%s: missed target, queueing event for next: current=%d, target=%d,  divisor=%d\n",
+	info->type = SWAP;
+	if (divisor && current_msc >= *target_msc) {
+		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
 		     __FUNCTION__,
-		     (int)current_msc,
-		     (int)*target_msc,
-		     (int)divisor));
+		     (long long)current_msc,
+		     (long long)*target_msc,
+		     (long long)divisor,
+		     (long long)remainder));
 
-		*target_msc = current_msc;
-		if (divisor)
-			*target_msc += remainder - current_msc % divisor;
-		/*
-		 * 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.
-		 */
-		*target_msc -= 1;
-		if (*target_msc < current_msc)
+		*target_msc = current_msc + remainder - current_msc % divisor;
+		if (*target_msc <= current_msc)
 			*target_msc += divisor;
-		vbl.reply.sequence = *target_msc;
-		DBG(("%s: queueing target_msc = %d\n", __FUNCTION__,
-		     vbl.reply.sequence));
-
-		if (*target_msc == current_msc) {
-			DBG(("%s: performing blit before queueing\n", __FUNCTION__));
-			info->bo = __sna_dri2_copy_region(sna, draw, NULL,
-							  info->back, info->front,
-							  true);
-			info->type = SWAP_WAIT;
+	}
+	vbl.request.sequence = *target_msc - 1;
+	if (*target_msc <= current_msc + 1) {
+		DBG(("%s: performing blit before queueing\n", __FUNCTION__));
+		info->bo = __sna_dri2_copy_region(sna, draw, NULL,
+						  info->back, info->front,
+						  true);
+		info->type = SWAP_WAIT;
 
-			vbl.request.type =
-				DRM_VBLANK_RELATIVE |
-				DRM_VBLANK_EVENT;
-			vbl.request.sequence = 1;
-		}
+		vbl.request.type =
+			DRM_VBLANK_RELATIVE |
+			DRM_VBLANK_EVENT;
+		vbl.request.sequence = 1;
+		*target_msc = current_msc + 1;
 	}
 
 	if (sna_wait_vblank(sna, &vbl, info->pipe))
@@ -2374,7 +2321,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 	CARD64 current_msc;
 	union drm_wait_vblank vbl;
 	const struct ust_msc *swap;
-	int pipe = 0;
+	int pipe;
 
 	crtc = sna_dri2_get_crtc(draw);
 	DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n",
@@ -2427,14 +2374,18 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 	 * we just need to make sure target_msc passes before waking up the
 	 * client. Otherwise, compute the next msc to match divisor/remainder.
 	 */
-	if (divisor == 0 || current_msc < target_msc) {
-		vbl.request.sequence = target_msc;
-	} else {
+	if (divisor && current_msc >= target_msc) {
+		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
+		     __FUNCTION__,
+		     (long long)current_msc,
+		     (long long)target_msc,
+		     (long long)divisor,
+		     (long long)remainder));
 		target_msc = current_msc + remainder - current_msc % divisor;
 		if (target_msc <= current_msc)
 			target_msc += divisor;
-		vbl.request.sequence = target_msc;
 	}
+	vbl.request.sequence = target_msc;
 
 	DBG(("%s: waiting until MSC=%llu\n", __FUNCTION__, (long long)vbl.request.sequence));
 	if (sna_wait_vblank(sna, &vbl, pipe))
commit a767ad2e50a503e2b979c976a502ff358064b820
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu May 22 21:18:10 2014 +0100

    sna/dri2: Use the timestamps stored on the CRTC
    
    Now that we store the information for the swap completion on the CRTC,
    we don't need to pass it around inside the frame event.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 4544a17..d82b1d0 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -917,10 +917,6 @@ struct sna_dri2_frame_event {
 
 	struct sna_dri2_frame_event *chain;
 
-	uint64_t fe_frame;
-	unsigned int fe_tv_sec;
-	unsigned int fe_tv_usec;
-
 	struct {
 		struct kgem_bo *bo;
 		uint32_t name;
@@ -1305,6 +1301,25 @@ sna_dri2_exchange_buffers(DrawablePtr draw,
 	back->name = tmp;
 }
 
+static void frame_swap_complete(struct sna *sna,
+				struct sna_dri2_frame_event *frame,
+				int type)
+{
+	const struct ust_msc *swap;
+
+	if (frame->draw == NULL)
+		return;
+
+	swap = sna_crtc_last_swap(frame->crtc);
+	DBG(("%s: pipe=%d, frame=%lld, tv=%d.%06d\n",
+	     __FUNCTION__, frame->pipe,
+	     (long long)swap->msc, swap->tv_sec, swap->tv_usec));
+
+	DRI2SwapComplete(frame->client, frame->draw,
+			 swap->msc, swap->tv_sec, swap->tv_usec,
+			 type, frame->event_complete, frame->event_data);
+}
+
 static void fake_swap_complete(struct sna *sna, ClientPtr client,
 			       DrawablePtr draw, xf86CrtcPtr crtc,
 			       int type, DRI2SwapEventPtr func, void *data)
@@ -1321,10 +1336,7 @@ static void fake_swap_complete(struct sna *sna, ClientPtr client,
 			 type, func, data);
 }
 
-static void chain_swap(struct sna *sna,
-		       DrawablePtr draw,
-		       int frame, unsigned int tv_sec, unsigned int tv_usec,
-		       struct sna_dri2_frame_event *chain)
+static void chain_swap(struct sna *sna, DrawablePtr draw, struct sna_dri2_frame_event *chain)
 {
 	union drm_wait_vblank vbl;
 
@@ -1368,18 +1380,12 @@ static void chain_swap(struct sna *sna,
 	chain->queued = true;
 	if (sna_wait_vblank(sna, &vbl, chain->pipe)) {
 		DBG(("%s: vblank wait failed, unblocking client\n", __FUNCTION__));
-		DRI2SwapComplete(chain->client, draw,
-				 frame, tv_sec, tv_usec,
-				 DRI2_BLIT_COMPLETE,
-				 chain->event_complete, chain->event_data);
+		frame_swap_complete(sna, chain, DRI2_BLIT_COMPLETE);
 		sna_dri2_frame_event_info_free(sna, draw, chain);
 	} else {
 		if (chain->type == SWAP_THROTTLE && !swap_limit(draw, 2)) {
 			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
-			DRI2SwapComplete(chain->client, draw,
-					 frame, tv_sec, tv_usec,
-					 DRI2_BLIT_COMPLETE,
-					 chain->event_complete, chain->event_data);
+			frame_swap_complete(sna, chain, DRI2_BLIT_COMPLETE);
 		}
 	}
 }
@@ -1481,10 +1487,7 @@ void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 
 		DBG(("%s: swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
 		     event->sequence, event->tv_sec, event->tv_usec));
-		DRI2SwapComplete(info->client, draw, msc,
-				 event->tv_sec, event->tv_usec,
-				 DRI2_BLIT_COMPLETE,
-				 info->event_complete, info->event_data);
+		frame_swap_complete(sna, info, DRI2_BLIT_COMPLETE);
 		break;
 
 	case SWAP_THROTTLE:
@@ -1498,10 +1501,7 @@ void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 
 		DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
 		     event->sequence, event->tv_sec, event->tv_usec));
-		DRI2SwapComplete(info->client, draw, msc,
-				 event->tv_sec, event->tv_usec,
-				 DRI2_BLIT_COMPLETE,
-				 info->event_complete, info->event_data);
+		frame_swap_complete(sna, info, DRI2_BLIT_COMPLETE);
 #endif
 		break;
 
@@ -1519,9 +1519,7 @@ void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 	if (info->chain) {
 		assert(info->chain != info);
 		sna_dri2_remove_frame_event((WindowPtr)draw, info);
-		chain_swap(sna, draw,
-			   event->sequence, event->tv_sec, event->tv_usec,
-			   info->chain);
+		chain_swap(sna, draw, info->chain);
 		draw = NULL;
 	}
 
@@ -1571,11 +1569,7 @@ sna_dri2_immediate_blit(struct sna *sna,
 			}
 			if (event) {
 				DBG(("%s: fake triple bufferring, unblocking client\n", __FUNCTION__));
-				fake_swap_complete(sna, info->client,
-						   draw, info->crtc,
-						   DRI2_BLIT_COMPLETE,
-						   info->event_complete,
-						   info->event_data);
+				frame_swap_complete(sna, info, DRI2_BLIT_COMPLETE);
 			}
 		}
 	} else {
@@ -1691,9 +1685,7 @@ sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_frame_event *info)
 		sna_dri2_flip_get_back(sna, info);
 #if !XORG_CAN_TRIPLE_BUFFER
 		DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
-		fake_swap_complete(sna, info->client, info->draw, info->crtc,
-				   DRI2_FLIP_COMPLETE,
-				   info->event_complete, info->event_data);
+		frame_swap_complete(sna, info, DRI2_FLIP_COMPLETE);
 #endif
 	}
 
@@ -1745,9 +1737,7 @@ static void chain_flip(struct sna *sna)
 		}
 #endif
 		DBG(("%s: fake triple buffering (or vblank wait failed), unblocking client\n", __FUNCTION__));
-		fake_swap_complete(sna, chain->client, chain->draw,
-				   chain->crtc, DRI2_BLIT_COMPLETE,
-				   chain->event_complete, chain->event_data);
+		frame_swap_complete(sna, chain, DRI2_BLIT_COMPLETE);
 		sna_dri2_frame_event_info_free(sna, chain->draw, chain);
 	}
 }
@@ -1755,12 +1745,7 @@ static void chain_flip(struct sna *sna)
 static void sna_dri2_flip_event(struct sna *sna,
 				struct sna_dri2_frame_event *flip)
 {
-	DBG(("%s(frame=%lld, tv=%d.%06d, type=%d)\n",
-	     __FUNCTION__,
-	     (long long)flip->fe_frame,
-	     flip->fe_tv_sec,
-	     flip->fe_tv_usec,
-	     flip->type));
+	DBG(("%s(pipe=%d)\n", __FUNCTION__, flip->pipe));
 
 	assert(!sna->mode.shadow_flip);
 
@@ -1804,19 +1789,8 @@ static void sna_dri2_flip_event(struct sna *sna,
 	/* We assume our flips arrive in order, so we don't check the frame */
 	switch (flip->type) {
 	case FLIP:
-		DBG(("%s: flip complete (drawable gone? %d), msc=%lld\n",
-		     __FUNCTION__, flip->draw == NULL, (long long)flip->fe_frame));
-		if (flip->draw) {
-			DBG(("%s: swap complete, unblocking client (frame=%lld, tv=%d.%06d)\n", __FUNCTION__,
-			     (long long)flip->fe_frame, flip->fe_tv_sec, flip->fe_tv_usec));
-			DRI2SwapComplete(flip->client, flip->draw,
-					 flip->fe_frame,
-					 flip->fe_tv_sec,
-					 flip->fe_tv_usec,
-					 DRI2_FLIP_COMPLETE,
-					 flip->event_complete, flip->event_data);
-		}
-
+		DBG(("%s: swap complete, unblocking client\n", __FUNCTION__));
+		frame_swap_complete(sna, flip, DRI2_FLIP_COMPLETE);
 		sna_dri2_frame_event_info_free(sna, flip->draw, flip);
 
 		if (sna->dri2.flip_pending)
@@ -1824,16 +1798,8 @@ static void sna_dri2_flip_event(struct sna *sna,
 		break;
 
 	case FLIP_THROTTLE:
-		if (flip->draw) {
-			DBG(("%s: triple buffer swap complete, unblocking client (frame=%lld, tv=%d.%06d)\n", __FUNCTION__,
-			     (long long)flip->fe_frame, flip->fe_tv_sec, flip->fe_tv_usec));
-			DRI2SwapComplete(flip->client, flip->draw,
-					 flip->fe_frame,
-					 flip->fe_tv_sec,
-					 flip->fe_tv_usec,
-					 DRI2_FLIP_COMPLETE,
-					 flip->event_complete, flip->event_data);
-		}
+		DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__));
+		frame_swap_complete(sna, flip, DRI2_FLIP_COMPLETE);
 	case FLIP_COMPLETE:
 		if (sna->dri2.flip_pending) {
 			sna_dri2_frame_event_info_free(sna, flip->draw, flip);
@@ -1844,11 +1810,7 @@ static void sna_dri2_flip_event(struct sna *sna,
 			if (flip->chain) {
 				sna_dri2_remove_frame_event((WindowPtr)flip->draw,
 							   flip);
-				chain_swap(sna, flip->draw,
-					   flip->fe_frame,
-					   flip->fe_tv_sec,
-					   flip->fe_tv_usec,
-					   flip->chain);
+				chain_swap(sna, flip->draw, flip->chain);
 				flip->draw = NULL;
 			}
 
@@ -1880,11 +1842,8 @@ sna_dri2_page_flip_handler(struct sna *sna,
 	assert(info->count > 0);
 
 	/* Is this the event whose info shall be delivered to higher level? */
-	if (event->user_data & 1) {
-		info->fe_frame = sna_crtc_record_event(info->crtc, event);
-		info->fe_tv_sec = event->tv_sec;
-		info->fe_tv_usec = event->tv_usec;
-	}
+	if (event->user_data & 1)
+		sna_crtc_record_event(info->crtc, event);
 
 	if (--info->count)
 		return;
@@ -2066,8 +2025,7 @@ new_back:
 			sna_dri2_flip_get_back(sna, info);
 			if (type == FLIP_COMPLETE) {
 				DBG(("%s: fake triple bufferring, unblocking client\n", __FUNCTION__));
-				fake_swap_complete(sna, client, draw, info->crtc,
-						   DRI2_EXCHANGE_COMPLETE, func, data);
+				frame_swap_complete(sna, info, DRI2_EXCHANGE_COMPLETE);
 			}
 		}
 out:
commit 5d80af306677b6d0c52487707bbbcf8de065803b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu May 22 13:04:31 2014 +0100

    sna/dri2: Tweak flip continuation
    
    Minor tidying to the returned target_msc and a useful assertion.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index eae6cc3..4544a17 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -1855,7 +1855,7 @@ static void sna_dri2_flip_event(struct sna *sna,
 			sna_dri2_frame_event_info_free(sna, flip->draw, flip);
 		} else if (!sna_dri2_flip_continue(sna, flip)) {
 			DBG(("%s: no longer able to flip\n", __FUNCTION__));
-			if (flip->draw == NULL || !sna_dri2_immediate_blit(sna, flip, false, flip->mode == 1))
+			if (flip->draw == NULL || !sna_dri2_immediate_blit(sna, flip, false, flip->mode < 0))
 				sna_dri2_frame_event_info_free(sna, flip->draw, flip);
 		}
 		break;
@@ -2009,15 +2009,14 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 			if (current_msc >= *target_msc) {
 				DBG(("%s: executing xchg of pending flip\n",
 				     __FUNCTION__));
+				assert(info->mode == 0 || info->mode == FLIP_COMPLETE);
 				sna_dri2_exchange_buffers(draw, front, back);
 				info->mode = type = FLIP_COMPLETE;
-				current_msc = *target_msc;
 				goto new_back;
 			} else {
 				DBG(("%s: chaining flip\n", __FUNCTION__));
 				type = FLIP_THROTTLE;
 				info->mode = -type;
-				current_msc++;
 				goto out;
 			}
 		}
@@ -2062,7 +2061,6 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 			}
 		}
 
-		current_msc++;
 		if (info->type != FLIP) {
 new_back:
 			sna_dri2_flip_get_back(sna, info);
@@ -2073,8 +2071,8 @@ new_back:
 			}
 		}
 out:
-		DBG(("%s: target_msc=%lu\n", __FUNCTION__, (unsigned long)current_msc));
-		*target_msc = current_msc;
+		DBG(("%s: target_msc=%llu\n", __FUNCTION__, current_msc + 1));
+		*target_msc = current_msc + 1;
 		return true;
 	}
 


More information about the xorg-commit mailing list