xf86-video-intel: 4 commits - src/sna/sna_display.c src/sna/sna_dri2.c src/sna/sna.h

Chris Wilson ickle at kemper.freedesktop.org
Thu May 22 00:41:52 PDT 2014


 src/sna/sna.h         |   48 +++----------
 src/sna/sna_display.c |   49 +++++++++++++
 src/sna/sna_dri2.c    |  183 +++++++++++++++++++++++---------------------------
 3 files changed, 147 insertions(+), 133 deletions(-)

New commits:
commit 80dfbaa3c39e1c56aaa9f8951e3bbcc30a9b748d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu May 22 00:24:07 2014 +0100

    sna/dri2: Move fixed array allocations to per-crtc
    
    Replace the fixed size MAX_PIPES array by moving the vblank handling to
    per-crtc.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index c3eb248..f88690c 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -72,8 +72,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <signal.h>
 #include <setjmp.h>
 
-#define MAX_PIPES 4
-
 #include "compiler.h"
 
 #if HAS_DEBUG_FULL
@@ -289,17 +287,6 @@ struct sna {
 		unsigned serial;
 
 		uint32_t *encoders;
-
-		struct {
-			uint64_t msc;
-			unsigned int tv_sec;
-			unsigned int tv_usec;
-		} last_swap[MAX_PIPES];
-
-		struct {
-			uint32_t last;
-			uint32_t wraps;
-		} msc[MAX_PIPES];
 	} mode;
 
 	struct {
@@ -469,43 +456,30 @@ extern xf86CrtcPtr sna_covering_crtc(struct sna *sna,
 extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
 				  xf86CrtcPtr crtc, const BoxRec *clip);
 
-static inline uint64_t msc64(struct sna *sna, int pipe, uint32_t seq)
-{
-	assert((unsigned)pipe < MAX_PIPES);
-	if ((int32_t)(seq - sna->mode.msc[pipe].last) < -0x40000000) {
-		sna->mode.msc[pipe].wraps++;
-		DBG(("%s: pipe=%d wrapped was %u, now %u, wraps=%u\n",
-		     __FUNCTION__, pipe, sna->mode.msc[pipe].last, seq,
-		     sna->mode.msc[pipe].wraps));
-	}
-	sna->mode.msc[pipe].last = seq;
-	return (uint64_t)sna->mode.msc[pipe].wraps << 32 | seq;
-}
+xf86CrtcPtr sna_mode_first_crtc(struct sna *sna);
 
-static inline uint64_t sna_mode_record_swap(struct sna *sna, int pipe,
-					    int tv_sec, int tv_usec, unsigned seq)
-{
-	DBG(("%s: recording last swap on pipe=%d, frame %d, time %d.%06d\n",
-	     __FUNCTION__, pipe, seq, tv_sec, tv_usec));
-	assert((unsigned)pipe < MAX_PIPES);
-	sna->mode.last_swap[pipe].tv_sec = tv_sec;
-	sna->mode.last_swap[pipe].tv_usec = tv_usec;
-	return sna->mode.last_swap[pipe].msc = msc64(sna, pipe, seq);
-}
+const struct ust_msc {
+	uint64_t msc;
+	int tv_sec;
+	int tv_usec;
+} *sna_crtc_last_swap(xf86CrtcPtr crtc);
+
+uint64_t sna_crtc_record_swap(xf86CrtcPtr crtc,
+			      int tv_sec, int tv_usec, unsigned seq);
 
-static inline uint64_t sna_mode_record_vblank(struct sna *sna, int pipe,
+static inline uint64_t sna_crtc_record_vblank(xf86CrtcPtr crtc,
 					      const union drm_wait_vblank *vbl)
 {
-	return sna_mode_record_swap(sna, pipe,
+	return sna_crtc_record_swap(crtc,
 				    vbl->reply.tval_sec,
 				    vbl->reply.tval_usec,
 				    vbl->reply.sequence);
 }
 
-static inline uint64_t sna_mode_record_event(struct sna *sna, int pipe,
+static inline uint64_t sna_crtc_record_event(xf86CrtcPtr crtc,
 					     struct drm_event_vblank *event)
 {
-	return sna_mode_record_swap(sna, pipe,
+	return sna_crtc_record_swap(crtc,
 				    event->tv_sec,
 				    event->tv_usec,
 				    event->sequence);
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 63631ef..a81ce21 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -119,6 +119,9 @@ struct sna_crtc {
 	uint32_t rotation;
 	struct rotation primary_rotation;
 	struct rotation sprite_rotation;
+
+	uint32_t last_seq, wrap_seq;
+	struct ust_msc swap;
 };
 
 struct sna_property {
@@ -228,6 +231,52 @@ int sna_crtc_is_on(xf86CrtcPtr crtc)
 	return to_sna_crtc(crtc)->bo != NULL;
 }
 
+static inline uint64_t msc64(struct sna_crtc *sna_crtc, uint32_t seq)
+{
+	if ((int32_t)(seq - sna_crtc->last_seq) < -0x40000000) {
+		sna_crtc->wrap_seq++;
+		DBG(("%s: pipe=%d wrapped was %u, now %u, wraps=%u\n",
+		     __FUNCTION__, sna_crtc->pipe,
+		     sna_crtc->last_seq, seq, sna_crtc->wrap_seq));
+	}
+	sna_crtc->last_seq = seq;
+	return (uint64_t)sna_crtc->wrap_seq << 32 | seq;
+}
+
+uint64_t sna_crtc_record_swap(xf86CrtcPtr crtc,
+			      int tv_sec, int tv_usec, unsigned seq)
+{
+	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
+	assert(sna_crtc);
+	DBG(("%s: recording last swap on pipe=%d, frame %d, time %d.%06d\n",
+	     __FUNCTION__, sna_crtc->pipe, seq, tv_sec, tv_usec));
+	sna_crtc->swap.tv_sec = tv_sec;
+	sna_crtc->swap.tv_usec = tv_usec;
+	return sna_crtc->swap.msc = msc64(sna_crtc, seq);
+}
+
+const struct ust_msc *sna_crtc_last_swap(xf86CrtcPtr crtc)
+{
+	static struct ust_msc zero;
+
+	if (crtc == NULL) {
+		return &zero;
+	} else {
+		struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
+		assert(sna_crtc);
+		return &sna_crtc->swap;
+	}
+}
+
+xf86CrtcPtr sna_mode_first_crtc(struct sna *sna)
+{
+	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
+	if (sna->mode.num_real_crtc)
+		return config->crtc[0];
+	else
+		return NULL;
+}
+
 #ifndef NDEBUG
 static void gem_close(int fd, uint32_t handle);
 static void assert_scanout(struct kgem *kgem, struct kgem_bo *bo,
diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 1595721..43381d2 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -1305,18 +1305,19 @@ sna_dri2_exchange_buffers(DrawablePtr draw,
 	back->name = tmp;
 }
 
-static void fake_swap_complete(struct sna *sna,
-			       ClientPtr client, DrawablePtr draw, int type,
-			       DRI2SwapEventPtr func, void *data)
+static void fake_swap_complete(struct sna *sna, ClientPtr client,
+			       DrawablePtr draw, xf86CrtcPtr crtc,
+			       int type, DRI2SwapEventPtr func, void *data)
 {
-	DBG(("%s: frame=%lld, tv=%d.%06d\n", __FUNCTION__,
-	     (long long)sna->mode.last_swap[0].msc,
-	     sna->mode.last_swap[0].tv_sec,
-	     sna->mode.last_swap[0].tv_usec));
+	const struct ust_msc *swap;
+
+	swap = sna_crtc_last_swap(crtc);
+	DBG(("%s: pipe=%d, frame=%lld, tv=%d.%06d\n",
+	     __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1,
+	     (long long)swap->msc, swap->tv_sec, swap->tv_usec));
+
 	DRI2SwapComplete(client, draw,
-			 sna->mode.last_swap[0].msc,
-			 sna->mode.last_swap[0].tv_sec,
-			 sna->mode.last_swap[0].tv_usec,
+			 swap->msc, swap->tv_sec, swap->tv_usec,
 			 type, func, data);
 }
 
@@ -1433,9 +1434,8 @@ void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 	uint64_t msc;
 
 	DBG(("%s(type=%d, sequence=%d)\n", __FUNCTION__, info->type, event->sequence));
-	assert((unsigned)info->pipe < MAX_PIPES);
 	assert(info->queued);
-	msc = sna_mode_record_event(sna, info->pipe, event);
+	msc = sna_crtc_record_event(info->crtc, event);
 
 	draw = info->draw;
 	if (draw == NULL) {
@@ -1571,7 +1571,8 @@ 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,
+				fake_swap_complete(sna, info->client,
+						   draw, info->crtc,
 						   DRI2_BLIT_COMPLETE,
 						   info->event_complete,
 						   info->event_data);
@@ -1690,7 +1691,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,
+		fake_swap_complete(sna, info->client, info->draw, info->crtc,
 				   DRI2_FLIP_COMPLETE,
 				   info->event_complete, info->event_data);
 #endif
@@ -1745,7 +1746,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,
-				   DRI2_BLIT_COMPLETE,
+				   chain->crtc, DRI2_BLIT_COMPLETE,
 				   chain->event_complete, chain->event_data);
 		sna_dri2_frame_event_info_free(sna, chain->draw, chain);
 	}
@@ -1880,7 +1881,7 @@ sna_dri2_page_flip_handler(struct sna *sna,
 
 	/* Is this the event whose info shall be delivered to higher level? */
 	if (event->user_data & 1) {
-		info->fe_frame = sna_mode_record_event(sna, info->pipe, event);
+		info->fe_frame = sna_crtc_record_event(info->crtc, event);
 		info->fe_tv_sec = event->tv_sec;
 		info->fe_tv_usec = event->tv_usec;
 	}
@@ -1893,16 +1894,16 @@ sna_dri2_page_flip_handler(struct sna *sna,
 }
 
 static CARD64
-get_current_msc(struct sna *sna, int pipe)
+get_current_msc(struct sna *sna, xf86CrtcPtr crtc)
 {
 	union drm_wait_vblank vbl;
 	CARD64 ret = -1;
 
 	VG_CLEAR(vbl);
-	vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe);
+	vbl.request.type = DRM_VBLANK_RELATIVE;
 	vbl.request.sequence = 0;
-	if (sna_wait_vblank(sna, &vbl, pipe) == 0)
-		ret = sna_mode_record_vblank(sna, pipe, &vbl);
+	if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
+		ret = sna_crtc_record_vblank(crtc, &vbl);
 
 	return ret;
 }
@@ -1952,7 +1953,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,
-			   int pipe,
+			   xf86CrtcPtr crtc,
 			   uint64_t *current_msc)
 {
 	if (divisor == 0) {
@@ -1964,7 +1965,7 @@ static bool immediate_swap(struct sna *sna,
 		}
 
 		if (target_msc)
-			*current_msc = get_current_msc(sna, pipe);
+			*current_msc = get_current_msc(sna, crtc);
 
 		DBG(("%s: current_msc=%ld, target_msc=%ld -- %s\n",
 		     __FUNCTION__, (long)*current_msc, (long)target_msc,
@@ -1974,7 +1975,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, pipe);
+	*current_msc = get_current_msc(sna, crtc);
 	return false;
 }
 
@@ -1990,7 +1991,7 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 	union drm_wait_vblank vbl;
 	CARD64 current_msc;
 
-	if (immediate_swap(sna, *target_msc, divisor, pipe, &current_msc)) {
+	if (immediate_swap(sna, *target_msc, divisor, crtc, &current_msc)) {
 		int type;
 
 		info = sna->dri2.flip_pending;
@@ -2067,7 +2068,8 @@ 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, DRI2_EXCHANGE_COMPLETE, func, data);
+				fake_swap_complete(sna, client, draw, info->crtc,
+						   DRI2_EXCHANGE_COMPLETE, func, data);
 			}
 		}
 out:
@@ -2194,7 +2196,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 {
 	struct sna *sna = to_sna_from_drawable(draw);
 	union drm_wait_vblank vbl;
-	xf86CrtcPtr crtc;
+	xf86CrtcPtr crtc = NULL;
 	struct sna_dri2_frame_event *info = NULL;
 	CARD64 current_msc;
 
@@ -2231,7 +2233,6 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	assert(sna_pixmap_from_drawable(draw)->flush);
 
 	/* Drawable not displayed... just complete the swap */
-	crtc = NULL;
 	if ((sna->flags & SNA_NO_WAIT) == 0)
 		crtc = sna_dri2_get_crtc(draw);
 	if (crtc == NULL) {
@@ -2267,7 +2268,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 
 	info->type = SWAP;
 
-	if (immediate_swap(sna, *target_msc, divisor, info->pipe, &current_msc)) {
+	if (immediate_swap(sna, *target_msc, divisor, info->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);
@@ -2353,20 +2354,13 @@ blit:
 		sna_dri2_frame_event_info_free(sna, draw, info);
 skip:
 	DBG(("%s: unable to show frame, unblocking client\n", __FUNCTION__));
-	fake_swap_complete(sna, client, draw, DRI2_BLIT_COMPLETE, func, data);
+	if (crtc == NULL)
+		crtc = sna_mode_first_crtc(sna);
+	fake_swap_complete(sna, client, draw, crtc, DRI2_BLIT_COMPLETE, func, data);
 	*target_msc = 0; /* offscreen, so zero out target vblank count */
 	return TRUE;
 }
 
-static int sna_dri2_get_pipe(DrawablePtr draw)
-{
-	int pipe = -1;
-	xf86CrtcPtr crtc = sna_dri2_get_crtc(draw);
-	if (crtc)
-		pipe = sna_crtc_to_pipe(crtc);
-	return pipe;
-}
-
 /*
  * Get current frame count and frame count timestamp, based on drawable's
  * crtc.
@@ -2376,28 +2370,27 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
 {
 	struct sna *sna = to_sna_from_drawable(draw);
 	union drm_wait_vblank vbl;
-	int pipe;
+	xf86CrtcPtr crtc = sna_dri2_get_crtc(draw);
 
-	pipe = sna_dri2_get_pipe(draw);
-	DBG(("%s(pipe=%d)\n", __FUNCTION__, pipe));
-	if (pipe == -1) {
+	DBG(("%s(pipe=%d)\n", __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1));
+	if (crtc == NULL) {
+		const struct ust_msc *swap;
+
+		crtc = sna_mode_first_crtc(sna);
 fail:
 		/* Drawable not displayed, make up a *monotonic* value */
-		assert(pipe < MAX_PIPES);
-		if (pipe < 0)
-			pipe = 0;
-		*msc = sna->mode.last_swap[pipe].msc;
-		*ust = ust64(sna->mode.last_swap[pipe].tv_sec,
-			     sna->mode.last_swap[pipe].tv_usec);
+		swap = sna_crtc_last_swap(crtc);
+		*msc = swap->msc;
+		*ust = ust64(swap->tv_sec, swap->tv_usec);
 		return TRUE;
 	}
 
 	VG_CLEAR(vbl);
 	vbl.request.type = DRM_VBLANK_RELATIVE;
 	vbl.request.sequence = 0;
-	if (sna_wait_vblank(sna, &vbl, pipe) == 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_mode_record_vblank(sna, pipe, &vbl);
+		*msc = sna_crtc_record_vblank(crtc, &vbl);
 		DBG(("%s: msc=%llu, ust=%llu\n", __FUNCTION__,
 		     (long long)*msc, (long long)*ust));
 	} else {
@@ -2424,6 +2417,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 	xf86CrtcPtr crtc;
 	CARD64 current_msc;
 	union drm_wait_vblank vbl;
+	const struct ust_msc *swap;
 	int pipe = 0;
 
 	crtc = sna_dri2_get_crtc(draw);
@@ -2447,7 +2441,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_mode_record_vblank(sna, pipe, &vbl);
+	current_msc = 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
@@ -2497,10 +2491,11 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 out_free_info:
 	sna_dri2_frame_event_info_free(sna, draw, info);
 out_complete:
+	if (crtc == NULL)
+		crtc = sna_mode_first_crtc(sna);
+	swap = sna_crtc_last_swap(crtc);
 	DRI2WaitMSCComplete(client, draw,
-			    sna->mode.last_swap[pipe].msc,
-			    sna->mode.last_swap[pipe].tv_sec,
-			    sna->mode.last_swap[pipe].tv_usec);
+			    swap->msc, swap->tv_sec, swap->tv_usec);
 	return TRUE;
 }
 #else
commit 9b21237a1caa369133e6ba972e2ec39feac21bcc
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed May 21 23:40:36 2014 +0100

    sna/dri2: Maintain sequence calculation in 64bits
    
    Avoid casting down to 32bits at the begining of the calculation to only
    then compare against the full 64bit values later.
    
    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 242f718..1595721 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -2128,11 +2128,12 @@ out:
 		     (int)divisor,
 		     (int)remainder));
 
-		vbl.request.sequence = current_msc;
+		*target_msc = current_msc;
 		if (divisor)
-			vbl.request.sequence += remainder - current_msc % divisor;
+			*target_msc += remainder - current_msc % divisor;
 
-		DBG(("%s: initial sequence = %d\n", __FUNCTION__, vbl.request.sequence));
+		DBG(("%s: initial sequence = %lld\n", __FUNCTION__,
+		     (long long)*target_msc));
 
 		/*
 		 * If the calculated deadline vbl.request.sequence is
@@ -2145,14 +2146,13 @@ out:
 		 * This comparison takes the 1 frame swap delay
 		 * in pageflipping mode into account.
 		 */
-		vbl.request.sequence -= 1;
-		if (vbl.request.sequence <= current_msc)
-			vbl.request.sequence += divisor;
-
-		DBG(("%s: flip adjusted sequence = %d\n", __FUNCTION__, vbl.request.sequence));
+		*target_msc -= 1;
+		if (*target_msc <= current_msc)
+			*target_msc += divisor;
 
-		/* Adjust returned value for 1 frame pageflip offset */
-		*target_msc = vbl.reply.sequence;
+		vbl.reply.sequence = *target_msc;
+		DBG(("%s: flip adjusted sequence = %d\n",
+		     __FUNCTION__, vbl.request.sequence));
 	}
 
 	/* Account for 1 frame extra pageflip delay */
@@ -2308,9 +2308,9 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		     (int)*target_msc,
 		     (int)divisor));
 
-		vbl.request.sequence = current_msc;
+		*target_msc = current_msc;
 		if (divisor)
-			vbl.request.sequence += remainder - current_msc % 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
@@ -2318,12 +2318,14 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		 * seq % divisor == remainder, so we need to wait for the next time
 		 * this will happen.
 		 */
-		vbl.request.sequence -= 1;
-		if (vbl.request.sequence < current_msc)
-			vbl.request.sequence += divisor;
-		*target_msc = vbl.reply.sequence;
-		DBG(("%s: queueing target_msc = %d\n", __FUNCTION__, vbl.reply.sequence));
-		if (vbl.request.sequence == current_msc) {
+		*target_msc -= 1;
+		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,
commit c548f231c1d59f578dfb113c549b5b6e015e7c5a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed May 21 23:35:19 2014 +0100

    sna/dri2: Fix WaitMSC to maintain the vblank counters
    
    Fix WaitMSC to also use 64 bit counters and maintain the last vblank
    notifications.
    
    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 725e2c4..242f718 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -2419,26 +2419,24 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 {
 	struct sna *sna = to_sna_from_drawable(draw);
 	struct sna_dri2_frame_event *info = NULL;
-	int pipe = sna_dri2_get_pipe(draw);
+	xf86CrtcPtr crtc;
 	CARD64 current_msc;
 	union drm_wait_vblank vbl;
+	int pipe = 0;
 
+	crtc = sna_dri2_get_crtc(draw);
 	DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n",
-	     __FUNCTION__, pipe,
+	     __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1,
 	     (long long)target_msc,
 	     (long long)divisor,
 	     (long long)remainder));
 
-	/* Truncate to match kernel interfaces; means occasional overflow
-	 * misses, but that's generally not a big deal */
-	target_msc &= 0xffffffff;
-	divisor &= 0xffffffff;
-	remainder &= 0xffffffff;
-
 	/* Drawable not visible, return immediately */
-	if (pipe == -1)
+	if (crtc == NULL)
 		goto out_complete;
 
+	pipe = sna_crtc_to_pipe(crtc);
+
 	VG_CLEAR(vbl);
 
 	/* Get current count */
@@ -2447,7 +2445,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 = vbl.reply.sequence;
+	current_msc = sna_mode_record_vblank(sna, pipe, &vbl);
 
 	/* If target_msc already reached or passed, set it to
 	 * current_msc to ensure we return a reasonable value back
@@ -2455,10 +2453,8 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 	 * sending us MSC targets from the past by forcibly updating
 	 * their count on this call.
 	 */
-	if (divisor == 0 && current_msc >= target_msc) {
-		target_msc = current_msc;
+	if (divisor == 0 && current_msc >= target_msc)
 		goto out_complete;
-	}
 
 	info = calloc(1, sizeof(struct sna_dri2_frame_event));
 	if (!info)
@@ -2468,6 +2464,8 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 	info->draw = draw;
 	info->client = client;
 	info->type = WAITMSC;
+	info->crtc = crtc;
+	info->pipe = pipe;
 	sna_dri2_add_frame_event(draw, info);
 
 	vbl.request.signal = (unsigned long)info;
@@ -2475,26 +2473,15 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 	/*
 	 * 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.
+	 * client. Otherwise, compute the next msc to match divisor/remainder.
 	 */
 	if (divisor == 0 || current_msc < target_msc) {
 		vbl.request.sequence = target_msc;
 	} else {
-		/*
-		 * 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/remainder
-		 * equation.
-		 */
-		vbl.request.sequence = current_msc - current_msc % divisor + remainder;
-
-		/*
-		 * If calculated remainder is larger than requested remainder,
-		 * 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 ((current_msc % divisor) >= remainder)
-			vbl.request.sequence += divisor;
+		target_msc = current_msc + remainder - current_msc % divisor;
+		if (target_msc <= current_msc)
+			target_msc += divisor;
+		vbl.request.sequence = target_msc;
 	}
 
 	DBG(("%s: waiting until MSC=%llu\n", __FUNCTION__, (long long)vbl.request.sequence));
@@ -2508,7 +2495,10 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 out_free_info:
 	sna_dri2_frame_event_info_free(sna, draw, info);
 out_complete:
-	DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
+	DRI2WaitMSCComplete(client, draw,
+			    sna->mode.last_swap[pipe].msc,
+			    sna->mode.last_swap[pipe].tv_sec,
+			    sna->mode.last_swap[pipe].tv_usec);
 	return TRUE;
 }
 #else
commit 1f237bb6db9724358eca0467362c03dc6a41dc4a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed May 21 23:02:52 2014 +0100

    sna/dri2: Apply a margin of error to the sequence wrap detection
    
    If we have a queue of events, we may set the msc from a recent vblank
    query only to then process an older vblank event and declare the counter
    wrapped.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index 59e4472..c3eb248 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -472,8 +472,12 @@ extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
 static inline uint64_t msc64(struct sna *sna, int pipe, uint32_t seq)
 {
 	assert((unsigned)pipe < MAX_PIPES);
-	if (seq < sna->mode.msc[pipe].last)
+	if ((int32_t)(seq - sna->mode.msc[pipe].last) < -0x40000000) {
 		sna->mode.msc[pipe].wraps++;
+		DBG(("%s: pipe=%d wrapped was %u, now %u, wraps=%u\n",
+		     __FUNCTION__, pipe, sna->mode.msc[pipe].last, seq,
+		     sna->mode.msc[pipe].wraps));
+	}
 	sna->mode.msc[pipe].last = seq;
 	return (uint64_t)sna->mode.msc[pipe].wraps << 32 | seq;
 }


More information about the xorg-commit mailing list