xf86-video-intel: src/sna/sna_display.c src/sna/sna_dri2.c src/sna/sna.h src/sna/sna_present.c src/sna/sna_video_sprite.c test/present-speed.c

Chris Wilson ickle at kemper.freedesktop.org
Sat Apr 18 04:56:37 PDT 2015


 src/sna/sna.h              |   46 +++++++-
 src/sna/sna_display.c      |  239 +++++++++++++++++++++------------------------
 src/sna/sna_dri2.c         |   26 ++--
 src/sna/sna_present.c      |   77 ++++++++++----
 src/sna/sna_video_sprite.c |   18 +--
 test/present-speed.c       |    1 
 6 files changed, 232 insertions(+), 175 deletions(-)

New commits:
commit 7eaf593640d4479f850227252fd793bcb55be8d3
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Apr 17 23:45:20 2015 +0100

    sna/present: Reuse last cached swap msc/ust during a flip chain
    
    Querying the known swap values is much slower than not!
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index 5153399..e51ee14 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -591,13 +591,51 @@ static inline void sna_present_vblank_handler(struct drm_event_vblank *event) {
 #endif
 
 extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation);
-extern int sna_crtc_to_pipe(xf86CrtcPtr crtc);
-extern int sna_crtc_to_pipe__safe(xf86CrtcPtr crtc);
 extern uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc);
-extern uint32_t sna_crtc_id(xf86CrtcPtr crtc);
-extern bool sna_crtc_is_on(xf86CrtcPtr crtc);
 extern bool sna_crtc_is_transformed(xf86CrtcPtr crtc);
 
+#define CRTC_VBLANK 0x3
+#define CRTC_ON 0x80000000
+
+static inline unsigned long *sna_crtc_flags(xf86CrtcPtr crtc)
+{
+	unsigned long *flags = crtc->driver_private;
+	assert(flags);
+	return flags;
+}
+
+static inline unsigned sna_crtc_pipe(xf86CrtcPtr crtc)
+{
+	return *sna_crtc_flags(crtc) >> 8 & 0xff;
+}
+
+static inline unsigned sna_crtc_id(xf86CrtcPtr crtc)
+{
+	return *sna_crtc_flags(crtc) >> 16 & 0xff;
+}
+
+static inline bool sna_crtc_is_on(xf86CrtcPtr crtc)
+{
+	return *sna_crtc_flags(crtc) & CRTC_ON;
+}
+
+static inline void sna_crtc_set_vblank(xf86CrtcPtr crtc)
+{
+	assert((*sna_crtc_flags(crtc) & CRTC_VBLANK) < 2);
+	++*sna_crtc_flags(crtc);
+}
+
+static inline void sna_crtc_clear_vblank(xf86CrtcPtr crtc)
+{
+	assert(*sna_crtc_flags(crtc) & CRTC_VBLANK);
+	--*sna_crtc_flags(crtc);
+}
+
+static inline bool sna_crtc_has_vblank(xf86CrtcPtr crtc)
+{
+	return *sna_crtc_flags(crtc) & CRTC_VBLANK;
+}
+
 CARD32 sna_format_for_depth(int depth);
 CARD32 sna_render_format_for_depth(int depth);
 
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 6b2c3ef..0183246 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -144,6 +144,7 @@ struct sna_cursor {
 };
 
 struct sna_crtc {
+	unsigned long flags;
 	xf86CrtcPtr base;
 	struct drm_mode_modeinfo kmode;
 	PixmapPtr slave_pixmap;
@@ -158,8 +159,6 @@ struct sna_crtc {
 	bool cursor_transform;
 	bool hwcursor;
 	bool flip_pending;
-	uint8_t id;
-	uint8_t pipe;
 
 	RegionRec client_damage; /* XXX overlap with shadow damage? */
 
@@ -281,6 +280,16 @@ static inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc)
 	return crtc->driver_private;
 }
 
+static inline unsigned __sna_crtc_pipe(struct sna_crtc *crtc)
+{
+	return crtc->flags >> 8 & 0xff;
+}
+
+static inline unsigned __sna_crtc_id(struct sna_crtc *crtc)
+{
+	return crtc->flags >> 16 & 0xff;
+}
+
 static inline bool event_pending(int fd)
 {
 	struct pollfd pfd;
@@ -302,39 +311,12 @@ static inline uint32_t fb_id(struct kgem_bo *bo)
 	return bo->delta;
 }
 
-uint32_t sna_crtc_id(xf86CrtcPtr crtc)
-{
-	if (to_sna_crtc(crtc) == NULL)
-		return 0;
-	return to_sna_crtc(crtc)->id;
-}
-
-int sna_crtc_to_pipe(xf86CrtcPtr crtc)
-{
-	assert(to_sna_crtc(crtc));
-	return to_sna_crtc(crtc)->pipe;
-}
-
-int sna_crtc_to_pipe__safe(xf86CrtcPtr crtc)
-{
-	if (to_sna_crtc(crtc))
-		return sna_crtc_to_pipe(crtc);
-	else
-		return sna_crtc_to_pipe(sna_primary_crtc(to_sna(crtc->scrn)));
-}
-
 uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc)
 {
 	assert(to_sna_crtc(crtc));
 	return to_sna_crtc(crtc)->sprite.id;
 }
 
-bool sna_crtc_is_on(xf86CrtcPtr crtc)
-{
-	assert(to_sna_crtc(crtc));
-	return to_sna_crtc(crtc)->bo != NULL;
-}
-
 bool sna_crtc_is_transformed(xf86CrtcPtr crtc)
 {
 	assert(to_sna_crtc(crtc));
@@ -348,11 +330,11 @@ static inline bool msc64(struct sna_crtc *sna_crtc, uint32_t seq, uint64_t *msc)
 		if (sna_crtc->last_seq - seq > 0x40000000) {
 			sna_crtc->wrap_seq++;
 			DBG(("%s: pipe=%d wrapped; was %u, now %u, wraps=%u\n",
-			     __FUNCTION__, sna_crtc->pipe,
+			     __FUNCTION__, __sna_crtc_pipe(sna_crtc),
 			     sna_crtc->last_seq, seq, sna_crtc->wrap_seq));
 		} else {
 			DBG(("%s: pipe=%d msc went backwards; was %u, now %u; ignoring for last_swap\n",
-			     __FUNCTION__, sna_crtc->pipe, sna_crtc->last_seq, seq));
+			     __FUNCTION__, __sna_crtc_pipe(sna_crtc), sna_crtc->last_seq, seq));
 
 			record = false;
 		}
@@ -371,14 +353,14 @@ uint64_t sna_crtc_record_swap(xf86CrtcPtr crtc,
 
 	if (msc64(sna_crtc, seq, &msc)) {
 		DBG(("%s: recording last swap on pipe=%d, frame %d [%08llx], time %d.%06d\n",
-		     __FUNCTION__, sna_crtc->pipe, seq, (long long)msc,
+		     __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
 		     tv_sec, tv_usec));
 		sna_crtc->swap.tv_sec = tv_sec;
 		sna_crtc->swap.tv_usec = tv_usec;
 		sna_crtc->swap.msc = msc;
 	} else {
 		DBG(("%s: swap event on pipe=%d, frame %d [%08llx], time %d.%06d\n",
-		     __FUNCTION__, sna_crtc->pipe, seq, (long long)msc,
+		     __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
 		     tv_sec, tv_usec));
 	}
 
@@ -939,7 +921,7 @@ sna_crtc_force_outputs_on(xf86CrtcPtr crtc)
 	int i;
 
 	assert(to_sna_crtc(crtc));
-	DBG(("%s(pipe=%d)\n", __FUNCTION__, to_sna_crtc(crtc)->pipe));
+	DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
 
 	/* DPMS handling by the kernel is inconsistent, so after setting a
 	 * mode on an output presume that we intend for it to be on, or that
@@ -969,7 +951,7 @@ sna_crtc_force_outputs_off(xf86CrtcPtr crtc)
 	int i;
 
 	assert(to_sna_crtc(crtc));
-	DBG(("%s(pipe=%d)\n", __FUNCTION__, to_sna_crtc(crtc)->pipe));
+	DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
 
 	/* DPMS handling by the kernel is inconsistent, so after setting a
 	 * mode on an output presume that we intend for it to be on, or that
@@ -1068,8 +1050,8 @@ bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation)
 	assert(to_sna_crtc(crtc));
 	DBG(("%s: CRTC:%d [pipe=%d], sprite=%u set-rotation=%x\n",
 	     __FUNCTION__,
-	     to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->sprite.id,
-	     rotation));
+	     sna_crtc_id(crtc), sna_crtc_pipe(crtc),
+	     to_sna_crtc(crtc)->sprite.id, rotation));
 
 	return rotation_set(to_sna(crtc->scrn),
 			    &to_sna_crtc(crtc)->sprite,
@@ -1087,10 +1069,12 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 	int output_count = 0;
 	int i;
 
-	DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->bo->handle));
+	DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__,
+	     __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
+	     sna_crtc->bo->handle));
 	if (!sna_crtc->kmode.clock) {
 		ERR(("%s(CRTC:%d [pipe=%d]): attempted to set an invalid mode\n",
-		     __FUNCTION__, sna_crtc->id, sna_crtc->pipe));
+		     __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc)));
 		return false;
 	}
 
@@ -1099,12 +1083,12 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 
 	if (!rotation_set(sna, &sna_crtc->primary, sna_crtc->rotation)) {
 		ERR(("%s: set-primary-rotation failed (rotation-id=%d, rotation=%d) on CRTC:%d [pipe=%d], errno=%d\n",
-		     __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, sna_crtc->id, sna_crtc->pipe, errno));
+		     __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno));
 		sna_crtc->primary.rotation.supported &= ~sna_crtc->rotation;
 		return false;
 	}
 	DBG(("%s: CRTC:%d [pipe=%d] primary rotation set to %x\n",
-	     __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->rotation));
+	     __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), sna_crtc->rotation));
 
 	for (i = 0; i < sna->mode.num_real_output; i++) {
 		xf86OutputPtr output = config->output[i];
@@ -1129,11 +1113,11 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 
 		DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n",
 		     __FUNCTION__, output->name, i, to_connector_id(output),
-		     sna_crtc->id, sna_crtc->pipe,
+		     __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
 		     (uint32_t)output->possible_crtcs,
 		     (uint32_t)output->possible_clones));
 
-		assert(output->possible_crtcs & (1 << sna_crtc->pipe) ||
+		assert(output->possible_crtcs & (1 << __sna_crtc_pipe(sna_crtc)) ||
 		       is_zaphod(crtc->scrn));
 
 		output_ids[output_count] = to_connector_id(output);
@@ -1151,7 +1135,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 	}
 
 	VG_CLEAR(arg);
-	arg.crtc_id = sna_crtc->id;
+	arg.crtc_id = __sna_crtc_id(sna_crtc);
 	arg.fb_id = fb_id(sna_crtc->bo);
 	if (sna_crtc->transform || sna_crtc->slave_pixmap) {
 		arg.x = 0;
@@ -1168,7 +1152,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 	arg.mode_valid = 1;
 
 	DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d%s%s update to %d outputs [%d...]\n",
-	     __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
+	     __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
 	     arg.mode.hdisplay,
 	     arg.mode.vdisplay,
 	     arg.x, arg.y,
@@ -1535,7 +1519,7 @@ static void sna_crtc_slave_damage(DamagePtr damage, RegionPtr region, void *clos
 	     __FUNCTION__,
 	     region->extents.x1, region->extents.y1, region->extents.x2, region->extents.y2,
 	     region_num_rects(region),
-	     crtc->pipe, crtc->base->x, crtc->base->y));
+	     __sna_crtc_pipe(crtc), crtc->base->x, crtc->base->y));
 
 	assert(crtc->slave_damage == damage);
 	assert(sna->mode.shadow_damage);
@@ -1553,7 +1537,7 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
 		return true;
 	}
 
-	DBG(("%s: enabling for crtc %d\n", __FUNCTION__, crtc->id));
+	DBG(("%s: enabling for crtc %d\n", __FUNCTION__, __sna_crtc_id(crtc)));
 
 	if (!sna->mode.shadow_active) {
 		if (!sna_mode_enable_shadow(sna))
@@ -1566,7 +1550,7 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
 		assert(crtc->slave_damage == NULL);
 
 		DBG(("%s: enabling PRIME slave tracking on CRTC %d [pipe=%d], pixmap=%ld\n",
-		     __FUNCTION__, crtc->id, crtc->pipe, crtc->slave_pixmap->drawable.serialNumber));
+		     __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->slave_pixmap->drawable.serialNumber));
 		crtc->slave_damage = DamageCreate(sna_crtc_slave_damage, NULL,
 						  DamageReportRawRegion, TRUE,
 						  to_screen_from_sna(sna),
@@ -1616,7 +1600,7 @@ static void sna_crtc_disable_shadow(struct sna *sna, struct sna_crtc *crtc)
 	if (!crtc->shadow)
 		return;
 
-	DBG(("%s: disabling for crtc %d\n", __FUNCTION__, crtc->id));
+	DBG(("%s: disabling for crtc %d\n", __FUNCTION__, __sna_crtc_id(crtc)));
 	assert(sna->mode.shadow_active > 0);
 
 	if (crtc->slave_damage) {
@@ -1646,11 +1630,13 @@ __sna_crtc_disable(struct sna *sna, struct sna_crtc *sna_crtc)
 	if (sna_crtc->bo) {
 		DBG(("%s: releasing handle=%d from scanout, active=%d\n",
 		     __FUNCTION__,sna_crtc->bo->handle, sna_crtc->bo->active_scanout-1));
+		assert(sna_crtc->flags & CRTC_ON);
 		assert(sna_crtc->bo->active_scanout);
 		assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
 		sna_crtc->bo->active_scanout--;
 		kgem_bo_destroy(&sna->kgem, sna_crtc->bo);
 		sna_crtc->bo = NULL;
+		sna_crtc->flags &= ~CRTC_ON;
 
 		if (sna->mode.hidden) {
 			sna->mode.hidden--;
@@ -1692,12 +1678,12 @@ sna_crtc_disable(xf86CrtcPtr crtc, bool force)
 		return;
 
 	DBG(("%s: disabling crtc [%d, pipe=%d], force?=%d\n", __FUNCTION__,
-	     sna_crtc->id, sna_crtc->pipe, force));
+	     __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), force));
 
 	sna_crtc_force_outputs_off(crtc);
 
 	memset(&arg, 0, sizeof(arg));
-	arg.crtc_id = sna_crtc->id;
+	arg.crtc_id = __sna_crtc_id(sna_crtc);
 	(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg);
 
 	__sna_crtc_disable(sna, sna_crtc);
@@ -1717,19 +1703,19 @@ static void update_flush_interval(struct sna *sna)
 
 		if (!crtc->enabled) {
 			DBG(("%s: CRTC:%d (pipe %d) disabled\n",
-			     __FUNCTION__,i, to_sna_crtc(crtc)->pipe));
+			     __FUNCTION__,i, sna_crtc_pipe(crtc)));
 			assert(to_sna_crtc(crtc)->bo == NULL);
 			continue;
 		}
 
 		if (to_sna_crtc(crtc)->bo == NULL) {
 			DBG(("%s: CRTC:%d (pipe %d) turned off\n",
-			     __FUNCTION__,i, to_sna_crtc(crtc)->pipe));
+			     __FUNCTION__,i, sna_crtc_pipe(crtc)));
 			continue;
 		}
 
 		DBG(("%s: CRTC:%d (pipe %d) vrefresh=%f\n",
-		     __FUNCTION__, i, to_sna_crtc(crtc)->pipe,
+		     __FUNCTION__, i, sna_crtc_pipe(crtc),
 		     xf86ModeVRefresh(&crtc->mode)));
 		max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(&crtc->mode));
 	}
@@ -1805,7 +1791,7 @@ void sna_copy_fbcon(struct sna *sna)
 		assert(crtc != NULL);
 
 		VG_CLEAR(mode);
-		mode.crtc_id = crtc->id;
+		mode.crtc_id = __sna_crtc_id(crtc);
 		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
 			continue;
 		if (!mode.fb_id)
@@ -2445,7 +2431,7 @@ sna_crtc_damage(xf86CrtcPtr crtc)
 	}
 
 	DBG(("%s: marking crtc %d as completely damaged (%d, %d), (%d, %d)\n",
-	     __FUNCTION__, to_sna_crtc(crtc)->id,
+	     __FUNCTION__, sna_crtc_id(crtc),
 	     region.extents.x1, region.extents.y1,
 	     region.extents.x2, region.extents.y2));
 	to_sna_crtc(crtc)->client_damage = region;
@@ -2516,7 +2502,7 @@ __sna_crtc_set_mode(xf86CrtcPtr crtc)
 	bool saved_cursor_transform;
 
 	DBG(("%s: CRTC=%d, pipe=%d, hidden?=%d\n", __FUNCTION__,
-	     sna_crtc->id, sna_crtc->pipe, sna->mode.hidden));
+	     __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), sna->mode.hidden));
 	if (sna->mode.hidden)
 		return TRUE;
 
@@ -2555,6 +2541,7 @@ retry: /* Attach per-crtc pixmap or direct */
 		goto error;
 	}
 
+	sna_crtc->flags |= CRTC_ON;
 	bo->active_scanout++;
 	DBG(("%s: marking handle=%d as active=%d (removing %d from scanout, active=%d)\n",
 	     __FUNCTION__, bo->handle, bo->active_scanout,
@@ -2616,14 +2603,14 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 	xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO,
 		   "switch to mode %dx%d@%.1f on %s using pipe %d, position (%d, %d), rotation %s, reflection %s\n",
 		   mode->HDisplay, mode->VDisplay, xf86ModeVRefresh(mode),
-		   outputs_for_crtc(crtc, outputs, sizeof(outputs)), sna_crtc->pipe,
+		   outputs_for_crtc(crtc, outputs, sizeof(outputs)), __sna_crtc_pipe(sna_crtc),
 		   x, y, rotation_to_str(rotation), reflection_to_str(rotation));
 
 	assert(mode->HDisplay <= sna->mode.max_crtc_width &&
 	       mode->VDisplay <= sna->mode.max_crtc_height);
 
 #if HAS_GAMMA
-	drmModeCrtcSetGamma(sna->kgem.fd, sna_crtc->id,
+	drmModeCrtcSetGamma(sna->kgem.fd, __sna_crtc_id(sna_crtc),
 			    crtc->gamma_size,
 			    crtc->gamma_red,
 			    crtc->gamma_green,
@@ -2643,7 +2630,7 @@ static void
 sna_crtc_dpms(xf86CrtcPtr crtc, int mode)
 {
 	DBG(("%s(pipe %d, dpms mode -> %d):= active=%d\n",
-	     __FUNCTION__, to_sna_crtc(crtc)->pipe, mode, mode == DPMSModeOn));
+	     __FUNCTION__, sna_crtc_pipe(crtc), mode, mode == DPMSModeOn));
 
 	if (mode == DPMSModeOn && crtc->enabled) {
 		if (__sna_crtc_set_mode(crtc))
@@ -2689,7 +2676,7 @@ sna_crtc_gamma_set(xf86CrtcPtr crtc,
 {
 	assert(to_sna_crtc(crtc));
 	drmModeCrtcSetGamma(to_sna(crtc->scrn)->kgem.fd,
-			    to_sna_crtc(crtc)->id,
+			    sna_crtc_id(crtc),
 			    size, red, green, blue);
 }
 
@@ -2718,7 +2705,7 @@ sna_crtc_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr pixmap)
 		return TRUE;
 
 	DBG(("%s: CRTC:%d, pipe=%d setting scanout pixmap=%ld\n",
-	     __FUNCTION__, sna_crtc->id,  sna_crtc->pipe,
+	     __FUNCTION__, __sna_crtc_id(sna_crtc),  __sna_crtc_pipe(sna_crtc),
 	     pixmap ? pixmap->drawable.serialNumber : 0));
 
 	/* Disable first so that we can unregister the damage tracking */
@@ -2912,11 +2899,11 @@ sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
 		if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANE, &p))
 			continue;
 
-		if ((p.possible_crtcs & (1 << crtc->pipe)) == 0)
+		if ((p.possible_crtcs & (1 << __sna_crtc_pipe(crtc))) == 0)
 			continue;
 
 		DBG(("%s: plane %d is attached to our pipe=%d\n",
-		     __FUNCTION__, planes[i], crtc->pipe));
+		     __FUNCTION__, planes[i], __sna_crtc_pipe(crtc)));
 
 		details.id = p.plane_id;
 		details.rotation.prop = 0;
@@ -2961,7 +2948,7 @@ sna_crtc_init__cursor(struct sna *sna, struct sna_crtc *crtc)
 
 	VG_CLEAR(arg);
 	arg.flags = DRM_MODE_CURSOR_BO;
-	arg.crtc_id = crtc->id;
+	arg.crtc_id = __sna_crtc_id(crtc);
 	arg.width = arg.height = 0;
 	arg.handle = 0;
 
@@ -2970,7 +2957,7 @@ sna_crtc_init__cursor(struct sna *sna, struct sna_crtc *crtc)
 }
 
 static bool
-sna_crtc_add(ScrnInfoPtr scrn, int id)
+sna_crtc_add(ScrnInfoPtr scrn, unsigned id)
 {
 	struct sna *sna = to_sna(scrn);
 	xf86CrtcPtr crtc;
@@ -2983,21 +2970,23 @@ sna_crtc_add(ScrnInfoPtr scrn, int id)
 	if (sna_crtc == NULL)
 		return false;
 
-	sna_crtc->id = id;
+	assert(id < 256);
+	sna_crtc->flags = id << 16;
 
 	VG_CLEAR(get_pipe);
 	get_pipe.pipe = 0;
-	get_pipe.crtc_id = sna_crtc->id;
+	get_pipe.crtc_id = id;
 	if (drmIoctl(sna->kgem.fd,
 		     DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID,
 		     &get_pipe)) {
 		free(sna_crtc);
 		return false;
 	}
-	sna_crtc->pipe = get_pipe.pipe;
+	assert((unsigned)get_pipe.pipe < 256);
+	sna_crtc->flags |= get_pipe.pipe << 8;
 
 	if (is_zaphod(scrn) &&
-	    scrn->confScreen->device->screen != sna_crtc->pipe) {
+	    scrn->confScreen->device->screen != get_pipe.pipe) {
 		free(sna_crtc);
 		return true;
 	}
@@ -3007,7 +2996,7 @@ sna_crtc_add(ScrnInfoPtr scrn, int id)
 	sna_crtc_find_planes(sna, sna_crtc);
 
 	DBG(("%s: CRTC:%d [pipe=%d], primary id=%x: supported-rotations=%x, current-rotation=%x, sprite id=%x: supported-rotations=%x, current-rotation=%x\n",
-	     __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
+	     __FUNCTION__, id, get_pipe.pipe,
 	     sna_crtc->primary.id, sna_crtc->primary.rotation.supported, sna_crtc->primary.rotation.current,
 	     sna_crtc->sprite.id, sna_crtc->sprite.rotation.supported, sna_crtc->sprite.rotation.current));
 
@@ -3024,7 +3013,7 @@ sna_crtc_add(ScrnInfoPtr scrn, int id)
 	crtc->driver_private = sna_crtc;
 	sna_crtc->base = crtc;
 	DBG(("%s: attached crtc[%d] pipe=%d\n",
-	     __FUNCTION__, id, sna_crtc->pipe));
+	     __FUNCTION__, id, __sna_crtc_pipe(sna_crtc)));
 
 	return true;
 }
@@ -3486,12 +3475,12 @@ sna_output_get_modes(xf86OutputPtr output)
 
 		VG_CLEAR(mode);
 		assert(to_sna_crtc(output->crtc));
-		mode.crtc_id = to_sna_crtc(output->crtc)->id;
+		mode.crtc_id = sna_crtc_id(output->crtc);
 
 		if (drmIoctl(to_sna(output->scrn)->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode) == 0) {
 			DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__,
-			     to_sna_crtc(output->crtc)->id,
-			     to_sna_crtc(output->crtc)->pipe,
+			     sna_crtc_id(output->crtc),
+			     sna_crtc_pipe(output->crtc),
 			     mode.mode_valid && mode.mode.clock));
 
 			if (mode.mode_valid && mode.mode.clock) {
@@ -4600,7 +4589,7 @@ static bool disable_unused_crtc(struct sna *sna)
 
 		if (o == sna->mode.num_real_output) {
 			DBG(("%s: CRTC:%d was enabled with no outputs\n",
-			     __FUNCTION__, to_sna_crtc(crtc)->id));
+			     __FUNCTION__, sna_crtc_id(crtc)));
 			crtc->enabled = false;
 			update = true;
 		}
@@ -5288,7 +5277,7 @@ sna_show_cursors(ScrnInfoPtr scrn)
 
 		if (!crtc->cursor_in_range) {
 			DBG(("%s: skipping cursor outside CRTC (pipe=%d)\n",
-			     __FUNCTION__, sna_crtc->pipe));
+			     __FUNCTION__, sna_crtc_pipe(crtc)));
 			continue;
 		}
 
@@ -5296,16 +5285,16 @@ sna_show_cursors(ScrnInfoPtr scrn)
 		if (cursor == NULL ||
 		    (sna_crtc->cursor == cursor && sna_crtc->last_cursor_size == cursor->size)) {
 			DBG(("%s: skipping cursor already show on CRTC (pipe=%d)\n",
-			     __FUNCTION__, sna_crtc->pipe));
+			     __FUNCTION__, sna_crtc_pipe(crtc)));
 			continue;
 		}
 
 		DBG(("%s: CRTC pipe=%d, handle->%d\n", __FUNCTION__,
-		     sna_crtc->pipe, cursor->handle));
+		     sna_crtc_pipe(crtc), cursor->handle));
 
 		VG_CLEAR(arg);
 		arg.flags = DRM_MODE_CURSOR_BO;
-		arg.crtc_id = sna_crtc->id;
+		arg.crtc_id = __sna_crtc_id(sna_crtc);
 		arg.width = arg.height = cursor->size;
 		arg.handle = cursor->handle;
 
@@ -5363,7 +5352,7 @@ sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc)
 
 	sigio = sigio_block();
 	if (crtc->cursor) {
-		DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, crtc->id, crtc->cursor->handle));
+		DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, __sna_crtc_id(crtc), crtc->cursor->handle));
 		assert(crtc->cursor->ref > 0);
 		crtc->cursor->ref--;
 		crtc->cursor = NULL;
@@ -5371,7 +5360,7 @@ sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc)
 
 		VG_CLEAR(arg);
 		arg.flags = DRM_MODE_CURSOR_BO;
-		arg.crtc_id = crtc->id;
+		arg.crtc_id = __sna_crtc_id(crtc);
 		arg.width = arg.height = 0;
 		arg.handle = 0;
 
@@ -5464,7 +5453,7 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
 
 		VG_CLEAR(arg);
 		arg.flags = 0;
-		arg.crtc_id = sna_crtc->id;
+		arg.crtc_id = __sna_crtc_id(sna_crtc);
 		arg.handle = 0;
 
 		if (sna_crtc->bo == NULL)
@@ -5520,7 +5509,7 @@ disable:
 		}
 
 		__DBG(("%s: CRTC:%d (%d, %d), handle=%d, flags=%x (old cursor handle=%d), move? %d, update handle? %d\n",
-		       __FUNCTION__, sna_crtc->id, arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0,
+		       __FUNCTION__, __sna_crtc_id(sna_crtc), arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0,
 		       arg.flags & DRM_MODE_CURSOR_MOVE, arg.flags & DRM_MODE_CURSOR_BO));
 
 		if (arg.flags &&
@@ -5596,7 +5585,7 @@ transformable_cursor(struct sna *sna, CursorPtr cursor)
 
 		if (!to_sna_crtc(crtc)->hwcursor) {
 			DBG(("%s: hwcursor disabled on CRTC:%d [pipe=%d]\n",
-			     __FUNCTION__, to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe));
+			     __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc)));
 			return false;
 		}
 
@@ -5824,7 +5813,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
 	int output_count = 0;
 	int i;
 
-	DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, crtc->id, crtc->pipe, bo->handle));
+	DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), bo->handle));
 
 	assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids));
 	assert(crtc->bo);
@@ -5838,11 +5827,11 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
 
 		DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n",
 		     __FUNCTION__, output->name, i, to_connector_id(output),
-		     crtc->id, crtc->pipe,
+		     __sna_crtc_id(crtc), __sna_crtc_pipe(crtc),
 		     (uint32_t)output->possible_crtcs,
 		     (uint32_t)output->possible_clones));
 
-		assert(output->possible_crtcs & (1 << crtc->pipe) ||
+		assert(output->possible_crtcs & (1 << __sna_crtc_pipe(crtc)) ||
 		       is_zaphod(sna->scrn));
 
 		output_ids[output_count] = to_connector_id(output);
@@ -5852,7 +5841,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
 	assert(output_count);
 
 	VG_CLEAR(arg);
-	arg.crtc_id = crtc->id;
+	arg.crtc_id = __sna_crtc_id(crtc);
 	arg.fb_id = fb_id(bo);
 	assert(arg.fb_id);
 	arg.x = x;
@@ -5863,7 +5852,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
 	arg.mode_valid = 1;
 
 	DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d across %d outputs [%d...]\n",
-	     __FUNCTION__, crtc->id, crtc->pipe,
+	     __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc),
 	     arg.mode.hdisplay,
 	     arg.mode.vdisplay,
 	     arg.x, arg.y,
@@ -5941,7 +5930,7 @@ sna_page_flip(struct sna *sna,
 		uint32_t crtc_offset;
 
 		DBG(("%s: crtc %d id=%d, pipe=%d active? %d\n",
-		     __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo != NULL));
+		     __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->bo != NULL));
 		if (crtc->bo == NULL)
 			continue;
 		assert(!crtc->transform);
@@ -5953,7 +5942,7 @@ sna_page_flip(struct sna *sna,
 		if (data == NULL && crtc->bo == bo)
 			goto next_crtc;
 
-		arg.crtc_id = crtc->id;
+		arg.crtc_id = __sna_crtc_id(crtc);
 		arg.fb_id = get_fb(sna, bo, width, height);
 		if (arg.fb_id == 0) {
 			assert(count == 0);
@@ -6011,7 +6000,7 @@ update_scanout:
 
 retry_flip:
 		DBG(("%s: crtc %d id=%d, pipe=%d  --> fb %d\n",
-		     __FUNCTION__, i, crtc->id, crtc->pipe, arg.fb_id));
+		     __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), arg.fb_id));
 		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
 			ERR(("%s: pageflip failed with err=%d\n", __FUNCTION__, errno));
 
@@ -6019,7 +6008,7 @@ retry_flip:
 				struct drm_mode_crtc mode;
 
 				memset(&mode, 0, sizeof(mode));
-				mode.crtc_id = crtc->id;
+				mode.crtc_id = __sna_crtc_id(crtc);
 				drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode);
 
 				DBG(("%s: crtc=%d, valid?=%d, fb attached?=%d, expected=%d\n",
@@ -6043,7 +6032,7 @@ retry_flip:
 			if (sna->flags & (data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP)) {
 				xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
 					   "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n",
-					   crtc->id, crtc->pipe, data ? "synchronous": "asynchronous");
+					   __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), data ? "synchronous": "asynchronous");
 				sna->flags &= ~(data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP);
 				goto fixup_flip;
 			}
@@ -6064,7 +6053,7 @@ retry_flip:
 			sna->mode.flip_active++;
 
 			DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
-			     __FUNCTION__, crtc->id, crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial));
+			     __FUNCTION__, __sna_crtc_id(crtc), crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial));
 		} else
 			goto update_scanout;
 next_crtc:
@@ -6145,7 +6134,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
 
 		assert(sna_crtc);
 
-		lut.crtc_id = sna_crtc->id;
+		lut.crtc_id = __sna_crtc_id(sna_crtc);
 		lut.gamma_size = 256;
 		lut.red = (uintptr_t)(gamma);
 		lut.green = (uintptr_t)(gamma + 256);
@@ -6159,7 +6148,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
 		}
 
 		DBG(("%s: CRTC:%d, pipe=%d: gamma set?=%d\n",
-		     __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
+		     __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
 		     gamma_set));
 		if (!gamma_set) {
 			int i;
@@ -6251,12 +6240,12 @@ static bool sna_probe_initial_configuration(struct sna *sna)
 
 		/* Retrieve the current mode */
 		VG_CLEAR(mode);
-		mode.crtc_id = sna_crtc->id;
+		mode.crtc_id = __sna_crtc_id(sna_crtc);
 		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
 			continue;
 
 		DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__,
-		     sna_crtc->id, sna_crtc->pipe,
+		     __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
 		     mode.mode_valid && mode.mode.clock));
 
 		if (!mode.mode_valid || mode.mode.clock == 0)
@@ -6298,7 +6287,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
 			xf86CrtcPtr crtc = config->crtc[j];
 
 			assert(to_sna_crtc(crtc));
-			if (to_sna_crtc(crtc)->id != crtc_id)
+			if (sna_crtc_id(crtc) != crtc_id)
 				continue;
 
 			if (crtc->desiredMode.status == MODE_OK) {
@@ -6316,7 +6305,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
 					   "Output %s using initial mode %s on pipe %d\n",
 					   output->name,
 					   crtc->desiredMode.name,
-					   to_sna_crtc(crtc)->pipe);
+					   sna_crtc_pipe(crtc));
 
 				output->crtc = crtc;
 				output->status = XF86OutputStatusConnected;
@@ -7154,7 +7143,7 @@ sna_wait_for_scanline(struct sna *sna,
 		y2 /= 2;
 	}
 
-	pipe = sna_crtc_to_pipe(crtc);
+	pipe = sna_crtc_pipe(crtc);
 	DBG(("%s: pipe=%d, y1=%d, y2=%d, full_height?=%d\n",
 	     __FUNCTION__, pipe, y1, y2, full_height));
 
@@ -7206,7 +7195,7 @@ void sna_mode_check(struct sna *sna)
 		expected[1] = sna_crtc->flip_bo ? fb_id(sna_crtc->flip_bo) : -1;
 
 		VG_CLEAR(mode);
-		mode.crtc_id = sna_crtc->id;
+		mode.crtc_id = __sna_crtc_id(sna_crtc);
 		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
 			continue;
 
@@ -7218,7 +7207,7 @@ void sna_mode_check(struct sna *sna)
 		if (mode.fb_id != expected[0] && mode.fb_id != expected[1]) {
 			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
 				   "%s: invalid state found on pipe %d, disabling CRTC:%d\n",
-				   __FUNCTION__, sna_crtc->pipe, sna_crtc->id);
+				   __FUNCTION__, __sna_crtc_pipe(sna_crtc), __sna_crtc_id(sna_crtc));
 			sna_crtc_disable(crtc, true);
 		}
 	}
@@ -7604,7 +7593,7 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo)
 	struct sna_pixmap *priv = sna_pixmap((PixmapPtr)draw);
 
 	DBG(("%s: crtc %d [pipe=%d], damage (%d, %d), (%d, %d) x %d\n",
-	     __FUNCTION__, to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe,
+	     __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc),
 	     region->extents.x1, region->extents.y1,
 	     region->extents.x2, region->extents.y2,
 	     region_num_rects(region)));
@@ -7673,11 +7662,11 @@ void sna_shadow_set_crtc(struct sna *sna,
 	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
 	struct sna_pixmap *priv;
 
+	assert(sna_crtc);
 	DBG(("%s: setting shadow override for CRTC:%d to handle=%d\n",
-	     __FUNCTION__, sna_crtc->id, bo->handle));
+	     __FUNCTION__, __sna_crtc_id(sna_crtc), bo->handle));
 
 	assert(sna->flags & SNA_TEAR_FREE);
-	assert(sna_crtc);
 	assert(!sna_crtc->transform);
 
 	if (sna_crtc->client_bo != bo) {
@@ -7737,7 +7726,7 @@ void sna_shadow_unset_crtc(struct sna *sna,
 	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
 
 	DBG(("%s: clearin shadow override for CRTC:%d\n",
-	     __FUNCTION__, sna_crtc->id));
+	     __FUNCTION__, __sna_crtc_id(sna_crtc)));
 
 	if (sna_crtc->client_bo == NULL)
 		return;
@@ -7771,7 +7760,7 @@ static bool move_crtc_to_gpu(struct sna *sna)
 			continue;
 
 		DBG(("%s: CRTC %d [pipe=%d] requires frontbuffer\n",
-		     __FUNCTION__, crtc->id, crtc->pipe));
+		     __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc)));
 		return sna_pixmap_move_to_gpu(sna->front,
 					      MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT);
 	}
@@ -7849,7 +7838,7 @@ void sna_mode_redisplay(struct sna *sna)
 				struct kgem_bo *bo = NULL;
 
 				DBG(("%s: fallback intersects pipe=%d [(%d, %d), (%d, %d)]\n",
-				     __FUNCTION__, sna_crtc->pipe,
+				     __FUNCTION__, __sna_crtc_pipe(sna_crtc),
 				     damage.extents.x1, damage.extents.y1,
 				     damage.extents.x2, damage.extents.y2));
 
@@ -7884,7 +7873,7 @@ void sna_mode_redisplay(struct sna *sna)
 				if (bo != sna_crtc->bo) {
 					struct drm_mode_crtc_page_flip arg;
 
-					arg.crtc_id = sna_crtc->id;
+					arg.crtc_id = __sna_crtc_id(sna_crtc);
 					arg.fb_id = get_fb(sna, bo,
 							   crtc->mode.HDisplay,
 							   crtc->mode.VDisplay);
@@ -7908,7 +7897,7 @@ void sna_mode_redisplay(struct sna *sna)
 							sna_crtc->cache_bo = NULL;
 						} else {
 							DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
-							     __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno));
+							     __FUNCTION__, arg.fb_id, i, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno));
 							xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
 								   "Page flipping failed, disabling TearFree\n");
 							sna->flags &= ~SNA_TEAR_FREE;
@@ -7934,7 +7923,7 @@ void sna_mode_redisplay(struct sna *sna)
 						sna_crtc->cache_bo = kgem_bo_reference(sna_crtc->bo);
 
 						DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
-						     __FUNCTION__, sna_crtc->id, sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial));
+						     __FUNCTION__, __sna_crtc_id(sna_crtc), sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial));
 					}
 				}
 			}
@@ -8021,7 +8010,7 @@ void sna_mode_redisplay(struct sna *sna)
 				sna_crtc_redisplay(crtc, &damage, bo);
 				kgem_bo_submit(&sna->kgem, bo);
 
-				arg.crtc_id = sna_crtc->id;
+				arg.crtc_id = __sna_crtc_id(sna_crtc);
 				arg.fb_id = get_fb(sna, bo,
 						   crtc->mode.HDisplay,
 						   crtc->mode.VDisplay);
@@ -8050,7 +8039,7 @@ void sna_mode_redisplay(struct sna *sna)
 						DrawableRec tmp;
 
 						DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
-						     __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno));
+						     __FUNCTION__, arg.fb_id, i, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno));
 						xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
 							   "Page flipping failed, disabling TearFree\n");
 						sna->flags &= ~SNA_TEAR_FREE;
@@ -8069,7 +8058,7 @@ disable1:
 									    &box, 1, COPY_LAST)) {
 							xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
 								   "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n",
-								   __FUNCTION__, sna_crtc->id, sna_crtc->pipe);
+								   __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc));
 							sna_crtc_disable(crtc, false);
 						}
 
@@ -8090,7 +8079,7 @@ disable1:
 
 				sna_crtc->cache_bo = kgem_bo_reference(sna_crtc->bo);
 				DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
-				     __FUNCTION__, sna_crtc->id, sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial));
+				     __FUNCTION__, __sna_crtc_id(sna_crtc), sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial));
 			} else {
 				sna_crtc_redisplay(crtc, &damage, sna_crtc->bo);
 				kgem_scanout_flush(&sna->kgem, sna_crtc->bo);
@@ -8126,19 +8115,19 @@ disable1:
 
 			assert(crtc != NULL);
 			DBG(("%s: crtc %d [%d, pipe=%d] active? %d, transformed? %d\n",
-			     __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo ? crtc->bo->handle : 0, crtc->transform));
+			     __FUNCTION__, i, __sna_crtc_id(crtc), crtc->bo ? crtc->bo->handle : 0, crtc->transform));
 			if (crtc->bo == NULL || crtc->transform)
 				continue;
 
 			assert(config->crtc[i]->enabled);
 			assert(crtc->flip_bo == NULL);
 
-			arg.crtc_id = crtc->id;
+			arg.crtc_id = __sna_crtc_id(crtc);
 			arg.user_data = (uintptr_t)crtc;
 
 			if (crtc->client_bo) {
 				DBG(("%s: apply shadow override bo for CRTC:%d on pipe=%d, handle=%d\n",
-				     __FUNCTION__, crtc->id, crtc->pipe, crtc->client_bo->handle));
+				     __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->client_bo->handle));
 				arg.fb_id = get_fb(sna, crtc->client_bo,
 						   crtc->base->mode.HDisplay,
 						   crtc->base->mode.VDisplay);
@@ -8215,7 +8204,7 @@ fixup_flip:
 
 					xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
 						   "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n",
-						   __FUNCTION__, crtc->id, crtc->pipe);
+						   __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc));
 					sna_crtc_disable(crtc->base, false);
 				}
 				continue;
@@ -8223,7 +8212,7 @@ fixup_flip:
 
 			if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
 				ERR(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
-				     __FUNCTION__, arg.fb_id, i, crtc->id, crtc->pipe, errno));
+				     __FUNCTION__, arg.fb_id, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), errno));
 				goto fixup_flip;
 			}
 			sna->mode.flip_active++;
@@ -8237,7 +8226,7 @@ fixup_flip:
 			crtc->flip_pending = true;
 
 			DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
-			     __FUNCTION__, crtc->id, crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial));
+			     __FUNCTION__, __sna_crtc_id(crtc), crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial));
 
 			{
 				struct drm_i915_gem_busy busy = { flip_bo->handle };
@@ -8320,7 +8309,7 @@ again:
 
 				if (msc64(crtc, vbl->sequence, &msc)) {
 					DBG(("%s: recording last swap on pipe=%d, frame %d [%08llx], time %d.%06d\n",
-					     __FUNCTION__, crtc->pipe, vbl->sequence, (long long)msc, vbl->tv_sec, vbl->tv_usec));
+					     __FUNCTION__, __sna_crtc_pipe(crtc), vbl->sequence, (long long)msc, vbl->tv_sec, vbl->tv_usec));
 					crtc->swap.tv_sec = vbl->tv_sec;
 					crtc->swap.tv_usec = vbl->tv_usec;
 					crtc->swap.msc = msc;
diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 43d4701..9ee7e99 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -1312,8 +1312,8 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
 			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(priv->crtc), (long long)last->msc,
-			     sna_crtc_to_pipe(crtc), (long long)this->msc,
+			     sna_crtc_pipe(priv->crtc), (long long)last->msc,
+			     sna_crtc_pipe(crtc), (long long)this->msc,
 			     (long long)(priv->msc_delta + this->msc - last->msc)));
 			priv->msc_delta += this->msc - last->msc;
 			priv->crtc = crtc;
@@ -1491,7 +1491,7 @@ sna_dri2_add_event(struct sna *sna,
 	info->sna = sna;
 	info->draw = draw;
 	info->crtc = crtc;
-	info->pipe = sna_crtc_to_pipe(crtc);
+	info->pipe = sna_crtc_pipe(crtc);
 
 	if (!add_event_to_client(info, sna, client)) {
 		free(info);
@@ -1685,7 +1685,7 @@ can_flip(struct sna * sna,
 	}
 
 	if (!sna_crtc_is_on(crtc)) {
-		DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_to_pipe(crtc)));
+		DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_pipe(crtc)));
 		return false;
 	}
 
@@ -2137,7 +2137,7 @@ static void fake_swap_complete(struct sna *sna, ClientPtr client,
 
 	swap = sna_crtc_last_swap(crtc);
 	DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
-	     __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_to_pipe(crtc) : -1,
+	     __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_pipe(crtc) : -1,
 	     (long long)swap->msc,
 	     (long long)draw_current_msc(draw, crtc, swap->msc),
 	     swap->tv_sec, swap->tv_usec));
@@ -2587,7 +2587,7 @@ get_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc)
 	VG_CLEAR(vbl);
 	vbl.request.type = _DRM_VBLANK_RELATIVE;
 	vbl.request.sequence = 0;
-	if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
+	if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(crtc)) == 0)
 		ret = sna_crtc_record_vblank(crtc, &vbl);
 	else
 		ret = sna_crtc_last_swap(crtc)->msc;
@@ -2704,7 +2704,7 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 	if (immediate) {
 		info = sna->dri2.flip_pending;
 		DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d, continuation? %d\n",
-		     __FUNCTION__, sna_crtc_to_pipe(crtc),
+		     __FUNCTION__, sna_crtc_pipe(crtc),
 		     info != NULL, info ? info->flip_continue : 0,
 		     info && info->draw == draw));
 
@@ -2844,7 +2844,7 @@ sna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 	DBG(("%s: synchronous?=%d, send-event?=%d\n", __FUNCTION__, sync, event));
 	if (!sync || event) {
 		DBG(("%s: performing immediate xchg on pipe %d\n",
-		     __FUNCTION__, sna_crtc_to_pipe(crtc)));
+		     __FUNCTION__, sna_crtc_pipe(crtc)));
 		sna_dri2_xchg(draw, front, back);
 	}
 	if (sync) {
@@ -2906,7 +2906,7 @@ sna_dri2_schedule_xchg_crtc(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc
 	DBG(("%s: synchronous?=%d, send-event?=%d\n", __FUNCTION__, sync, event));
 	if (!sync || event) {
 		DBG(("%s: performing immediate xchg only on pipe %d\n",
-		     __FUNCTION__, sna_crtc_to_pipe(crtc)));
+		     __FUNCTION__, sna_crtc_pipe(crtc)));
 		sna_dri2_xchg_crtc(sna, draw, crtc, front, back);
 	}
 	if (sync) {
@@ -3173,7 +3173,7 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
 	const struct ust_msc *swap;
 
 	DBG(("%s(draw=%ld, pipe=%d)\n", __FUNCTION__, draw->id,
-	     crtc ? sna_crtc_to_pipe(crtc) : -1));
+	     crtc ? sna_crtc_pipe(crtc) : -1));
 
 	if (crtc != NULL) {
 		union drm_wait_vblank vbl;
@@ -3181,7 +3181,7 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
 		VG_CLEAR(vbl);
 		vbl.request.type = _DRM_VBLANK_RELATIVE;
 		vbl.request.sequence = 0;
-		if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
+		if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(crtc)) == 0)
 			sna_crtc_record_vblank(crtc, &vbl);
 	} else
 		/* Drawable not displayed, make up a *monotonic* value */
@@ -3215,7 +3215,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 
 	crtc = sna_dri2_get_crtc(draw);
 	DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n",
-	     __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1,
+	     __FUNCTION__, crtc ? sna_crtc_pipe(crtc) : -1,
 	     (long long)target_msc,
 	     (long long)divisor,
 	     (long long)remainder));
@@ -3224,7 +3224,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 	if (crtc == NULL)
 		goto out_complete;
 
-	pipe = sna_crtc_to_pipe(crtc);
+	pipe = sna_crtc_pipe(crtc);
 
 	VG_CLEAR(vbl);
 
diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c
index a344dac..2b3468d 100644
--- a/src/sna/sna_present.c
+++ b/src/sna/sna_present.c
@@ -56,9 +56,24 @@ to_present_event(uintptr_t  data)
 
 #define MARK_PRESENT(x) ((void *)((uintptr_t)(x) | 2))
 
-static int pipe_from_crtc(RRCrtcPtr crtc)
+static inline xf86CrtcPtr unmask_crtc(xf86CrtcPtr crtc)
 {
-	return crtc ? sna_crtc_to_pipe__safe(crtc->devPrivate) : -1;
+	return (xf86CrtcPtr)((uintptr_t)crtc & ~1);
+}
+
+static inline xf86CrtcPtr mark_crtc(xf86CrtcPtr crtc)
+{
+	return (xf86CrtcPtr)((uintptr_t)crtc | 1);
+}
+
+static inline bool has_vblank(xf86CrtcPtr crtc)
+{
+	return (uintptr_t)crtc & 1;
+}
+
+static inline int pipe_from_crtc(RRCrtcPtr crtc)
+{
+	return crtc ? sna_crtc_pipe(crtc->devPrivate) : -1;
 }
 
 static uint32_t pipe_select(int pipe)
@@ -98,7 +113,7 @@ static void vblank_complete(struct sna_present_event *info,
 	DBG(("%s: %d events complete\n", __FUNCTION__, info->n_event_id));
 	for (n = 0; n < info->n_event_id; n++) {
 		DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete%s\n", __FUNCTION__,
-		     sna_crtc_to_pipe(info->crtc),
+		     sna_crtc_pipe(unmask_crtc(info->crtc)),
 		     (int)(ust / 1000000), (int)(ust % 1000000),
 		     (long long)msc, (long long)info->target_msc,
 		     (long long)info->event_id[n],
@@ -142,7 +157,7 @@ static CARD32 sna_fake_vblank_handler(OsTimerPtr timer, CARD32 now, void *data)
 	VG_CLEAR(vbl);
 	vbl.request.type = DRM_VBLANK_RELATIVE;
 	vbl.request.sequence = 0;
-	if (sna_wait_vblank(info->sna, &vbl, sna_crtc_to_pipe(info->crtc)) == 0) {
+	if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
 		ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
 		msc = sna_crtc_record_vblank(info->crtc, &vbl);
 		DBG(("%s: event=%lld, target msc=%lld, now %lld\n",
@@ -155,7 +170,7 @@ static CARD32 sna_fake_vblank_handler(OsTimerPtr timer, CARD32 now, void *data)
 			vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
 			vbl.request.sequence = info->target_msc;
 			vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
-			if (sna_wait_vblank(info->sna, &vbl, sna_crtc_to_pipe(info->crtc)) == 0) {
+			if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
 				DBG(("%s: scheduled new vblank event for %lld\n", __FUNCTION__, (long long)info->target_msc));
 				free(timer);
 				return 0;
@@ -173,7 +188,7 @@ static CARD32 sna_fake_vblank_handler(OsTimerPtr timer, CARD32 now, void *data)
 			DBG(("%s: blocking wait!\n", __FUNCTION__));
 			vbl.request.type = DRM_VBLANK_ABSOLUTE;
 			vbl.request.sequence = info->target_msc;
-			(void)sna_wait_vblank(info->sna, &vbl, sna_crtc_to_pipe(info->crtc));
+			(void)sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc));
 		}
 	} else {
 		const struct ust_msc *swap = sna_crtc_last_swap(info->crtc);
@@ -241,24 +256,31 @@ static int
 sna_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc)
 {
 	struct sna *sna = to_sna_from_screen(crtc->pScreen);
-	int pipe = pipe_from_crtc(crtc);
 	union drm_wait_vblank vbl;
 
-	DBG(("%s(pipe=%d)\n", __FUNCTION__, pipe));
+	DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc->devPrivate)));
+	if (sna_crtc_has_vblank(crtc->devPrivate)) {
+		DBG(("%s: vblank active, reusing last swap msc/ust\n",
+		     __FUNCTION__));
+		goto last;
+	}
 
 	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_pipe(crtc->devPrivate)) == 0) {
 		*ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
 		*msc = sna_crtc_record_vblank(crtc->devPrivate, &vbl);
 	} else {
-		const struct ust_msc *swap = sna_crtc_last_swap(crtc->devPrivate);
+		const struct ust_msc *swap;
+last:
+		swap = sna_crtc_last_swap(crtc->devPrivate);
 		*ust = swap_ust(swap);
 		*msc = swap->msc;
 	}
 
-	DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld\n", __FUNCTION__, pipe,
+	DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld\n", __FUNCTION__,
+	     sna_crtc_pipe(crtc->devPrivate),
 	     (int)(*ust / 1000000), (int)(*ust % 1000000),
 	     (long long)*msc));
 
@@ -269,10 +291,13 @@ void
 sna_present_vblank_handler(struct drm_event_vblank *event)
 {
 	struct sna_present_event *info = to_present_event(event->user_data);
+	xf86CrtcPtr crtc = info->crtc;
 
 	vblank_complete(info,
 			ust64(event->tv_sec, event->tv_usec),
-			sna_crtc_record_event(info->crtc, event));
+			sna_crtc_record_event(unmask_crtc(crtc), event));
+	if (has_vblank(crtc))
+		sna_crtc_clear_vblank(unmask_crtc(crtc));
 }
 
 static int
@@ -284,14 +309,14 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 	union drm_wait_vblank vbl;
 
 	DBG(("%s(pipe=%d, event=%lld, msc=%lld)\n",
-	     __FUNCTION__, pipe_from_crtc(crtc),
+	     __FUNCTION__, sna_crtc_pipe(crtc->devPrivate),
 	     (long long)event_id, (long long)msc));
 
 	swap = sna_crtc_last_swap(crtc->devPrivate);
 	assert((int64_t)(msc - swap->msc) >= 0);
 	if ((int64_t)(msc - swap->msc) <= 0) {
 		DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete\n", __FUNCTION__,
-		     pipe_from_crtc(crtc),
+		     sna_crtc_pipe(crtc->devPrivate),
 		     swap->tv_sec, swap->tv_usec,
 		     (long long)swap->msc, (long long)msc,
 		     (long long)event_id));
@@ -300,13 +325,14 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 	}
 
 	list_for_each_entry(tmp, &sna->present.vblank_queue, link) {
-		if (tmp->target_msc == msc && tmp->crtc == crtc->devPrivate) {
+		if (tmp->target_msc == msc &&
+		    unmask_crtc(tmp->crtc) == crtc->devPrivate) {
 			uint64_t *events = tmp->event_id;
 
 			if (is_power_of_two(tmp->n_event_id)) {
 				events = malloc(2*sizeof(uint64_t)*tmp->n_event_id);
 				if (events == NULL)
-					goto fail;
+					return BadAlloc;
 
 				memcpy(events,
 				       tmp->event_id,
@@ -321,11 +347,13 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 			events[tmp->n_event_id++] = event_id;
 			return Success;
 		}
-		if ((int64_t)(tmp->target_msc - msc) > 0)
+		if ((int64_t)(tmp->target_msc - msc) > 0) {
+			DBG(("%s: previous target_msc=%lld invalid for coalescing\n",
+			     __FUNCTION__, (long long)tmp->target_msc));
 			break;
+		}
 	}
 
-fail:
 	info = malloc(sizeof(struct sna_present_event) + sizeof(uint64_t));
 	if (info == NULL)
 		return BadAlloc;
@@ -342,13 +370,18 @@ fail:
 	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
 	vbl.request.sequence = msc;
 	vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
-	if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(info->crtc))) {
+	if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(info->crtc))) {
 		DBG(("%s: vblank enqueue failed\n", __FUNCTION__));
 		if (!sna_fake_vblank(info)) {
 			list_del(&info->link);
 			free(info);
 			return BadAlloc;
 		}
+	} else {
+		if (msc - swap->msc == 1) {
+			sna_crtc_set_vblank(info->crtc);
+			info->crtc = mark_crtc(info->crtc);
+		}
 	}
 
 	return Success;
@@ -510,12 +543,14 @@ present_flip_handler(struct drm_event_vblank *event, void *data)
 		swap = *sna_crtc_last_swap(info->crtc);
 
 	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,
+	     info->crtc ? sna_crtc_pipe(info->crtc) : -1,
 	     swap.tv_sec, swap.tv_usec, (long long)swap.msc,
 	     (long long)info->target_msc,
 	     (long long)info->event_id[0],
 	     info->target_msc && info->target_msc == swap.msc ? "" : ": MISS"));
 	present_event_notify(info->event_id[0], swap_ust(&swap), swap.msc);
+	if (info->crtc)
+		sna_crtc_clear_vblank(info->crtc);
 
 	if (info->sna->present.unflip) {
 		DBG(("%s: executing queued unflip (event=%lld)\n", __FUNCTION__, (long long)info->sna->present.unflip));
@@ -558,6 +593,8 @@ flip(struct sna *sna,
 		return FALSE;
 	}
 
+	if (info->crtc)
+		sna_crtc_set_vblank(info->crtc);
 	return TRUE;
 }
 
diff --git a/src/sna/sna_video_sprite.c b/src/sna/sna_video_sprite.c
index 9ce9879..7c8a73f 100644
--- a/src/sna/sna_video_sprite.c
+++ b/src/sna/sna_video_sprite.c
@@ -81,14 +81,11 @@ static int sna_video_sprite_stop(ddStopVideo_ARGS)
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(video->sna->scrn);
 	int i;
 
-	for (i = 0; i < config->num_crtc; i++) {
+	for (i = 0; i < video->sna->mode.num_real_crtc; i++) {
 		xf86CrtcPtr crtc = config->crtc[i];
 		int pipe;
 
-		if (sna_crtc_id(crtc) == 0)
-			break;
-
-		pipe = sna_crtc_to_pipe(crtc);
+		pipe = sna_crtc_pipe(crtc);
 		if (video->bo[pipe] == NULL)
 			continue;
 
@@ -221,7 +218,7 @@ sna_video_sprite_show(struct sna *sna,
 		      BoxPtr dstBox)
 {
 	struct local_mode_set_plane s;
-	int pipe = sna_crtc_to_pipe(crtc);
+	int pipe = sna_crtc_pipe(crtc);
 
 	/* XXX handle video spanning multiple CRTC */
 
@@ -402,7 +399,7 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS)
 		goto err;
 	}
 
-	for (i = 0; i < config->num_crtc; i++) {
+	for (i = 0; i < video->sna->mode.num_real_crtc; i++) {
 		xf86CrtcPtr crtc = config->crtc[i];
 		struct sna_video_frame frame;
 		int pipe;
@@ -411,10 +408,7 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS)
 		RegionRec reg;
 		Rotation rotation;
 
-		if (sna_crtc_id(crtc) == 0)
-			break;
-
-		pipe = sna_crtc_to_pipe(crtc);
+		pipe = sna_crtc_pipe(crtc);
 
 		sna_video_frame_init(video, format->id, width, height, &frame);
 
@@ -611,7 +605,7 @@ static bool sna_video_has_sprites(struct sna *sna)
 
 	for (i = 0; i < sna->mode.num_real_crtc; i++) {
 		if (!sna_crtc_to_sprite(config->crtc[i])) {
-			DBG(("%s: no sprite found on pipe %d\n", __FUNCTION__, sna_crtc_to_pipe(config->crtc[i])));
+			DBG(("%s: no sprite found on pipe %d\n", __FUNCTION__, sna_crtc_pipe(config->crtc[i])));
 			return false;
 		}
 	}
diff --git a/test/present-speed.c b/test/present-speed.c
index ba06264..4d33904 100644
--- a/test/present-speed.c
+++ b/test/present-speed.c
@@ -249,7 +249,6 @@ static void run(Display *dpy, Window win, const char *name, unsigned options)
 					free(ev);
 				} while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
 			}
-			assert(p);
 
 			b->busy = (options & NOCOPY) == 0;
 			if (b->fence.xid) {


More information about the xorg-commit mailing list