xf86-video-intel: 19 commits - src/intel_dri.c src/intel_options.c src/sna/kgem.c src/sna/kgem.h src/sna/sna_display.c src/sna/sna_dri.c src/sna/sna_driver.c src/sna/sna.h src/sna/sna_video.c src/sna/sna_video_textured.c

Chris Wilson ickle at kemper.freedesktop.org
Mon May 28 10:33:34 PDT 2012


 src/intel_dri.c              |   18 +---
 src/intel_options.c          |    8 -
 src/sna/kgem.c               |   88 ++++++++++++++++---
 src/sna/kgem.h               |    1 
 src/sna/sna.h                |    4 
 src/sna/sna_display.c        |  193 +++++++++++++++++++++++++------------------
 src/sna/sna_dri.c            |  169 +++++++++++++++++++------------------
 src/sna/sna_driver.c         |   28 ++++++
 src/sna/sna_video.c          |   60 ++++++++++---
 src/sna/sna_video_textured.c |    7 -
 10 files changed, 365 insertions(+), 211 deletions(-)

New commits:
commit 55e6f5f220401318529e81f7c96fe0af3b893a0c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 16:21:09 2012 +0100

    sna: Use the local function for turning the cursor off prior to release
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 5d84578..3ec2d23 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -915,7 +915,7 @@ sna_crtc_destroy(xf86CrtcPtr crtc)
 	struct sna *sna = to_sna(crtc->scrn);
 	struct sna_crtc *sna_crtc = crtc->driver_private;
 
-	drmModeSetCursor(sna->kgem.fd, crtc_id(sna_crtc), 0, 64, 64);
+	sna_crtc_hide_cursor(crtc);
 	gem_close(sna->kgem.fd, sna_crtc->cursor);
 
 	list_del(&sna_crtc->link);
commit 77dd429222922aa1ba7f283553e11e60e4d5c496
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 14:40:23 2012 +0100

    sna/dri: Make WAIT_VBLANK valgrind clean
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 2ce4e40..59de4e2 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -686,6 +686,11 @@ sna_dri_copy_region(DrawablePtr draw,
 	copy(sna, draw, region, dst, src, false);
 }
 
+static inline int sna_wait_vblank(struct sna *sna, drmVBlank *vbl)
+{
+	return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
+}
+
 #if DRI2INFOREC_VERSION >= 4
 
 static int
@@ -1080,6 +1085,7 @@ static void sna_dri_vblank_handle(int fd,
 			if (kgem_bo_is_busy(info->bo)) {
 				drmVBlank vbl;
 
+				VG_CLEAR(vbl);
 				vbl.request.type =
 					DRM_VBLANK_RELATIVE |
 					DRM_VBLANK_EVENT;
@@ -1087,7 +1093,7 @@ static void sna_dri_vblank_handle(int fd,
 					vbl.request.type |= DRM_VBLANK_SECONDARY;
 				vbl.request.sequence = 1;
 				vbl.request.signal = (unsigned long)info;
-				if (!drmWaitVBlank(sna->kgem.fd, &vbl))
+				if (!sna_wait_vblank(sna, &vbl))
 					return;
 			}
 		}
@@ -1332,6 +1338,8 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	     (long long)divisor,
 	     (long long)remainder));
 
+	VG_CLEAR(vbl);
+
 	/* XXX In theory we can just exchange pixmaps.... */
 	pipe = sna_dri_get_pipe(draw);
 	if (pipe == -1)
@@ -1435,7 +1443,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		if (pipe > 0)
 			vbl.request.type |= DRM_VBLANK_SECONDARY;
 		vbl.request.sequence = 0;
-		if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
+		if (sna_wait_vblank(sna, &vbl)) {
 			sna_dri_frame_event_info_free(info);
 			return FALSE;
 		}
@@ -1491,7 +1499,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		/* Account for 1 frame extra pageflip delay */
 		vbl.request.sequence -= 1;
 		vbl.request.signal = (unsigned long)info;
-		if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
+		if (sna_wait_vblank(sna, &vbl)) {
 			sna_dri_frame_event_info_free(info);
 			return FALSE;
 		}
@@ -1559,6 +1567,8 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		goto blit_fallback;
 	}
 
+	VG_CLEAR(vbl);
+
 	/* Truncate to match kernel interfaces; means occasional overflow
 	 * misses, but that's generally not a big deal */
 	*target_msc &= 0xffffffff;
@@ -1607,7 +1617,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 				vbl.request.type |= DRM_VBLANK_SECONDARY;
 			vbl.request.sequence = 0;
 			vbl.request.signal = (unsigned long)info;
-			if (drmWaitVBlank(sna->kgem.fd, &vbl) == 0)
+			if (sna_wait_vblank(sna, &vbl) == 0)
 				return TRUE;
 		}
 
@@ -1621,7 +1631,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	if (pipe > 0)
 		vbl.request.type |= DRM_VBLANK_SECONDARY;
 	vbl.request.sequence = 0;
-	if (drmWaitVBlank(sna->kgem.fd, &vbl))
+	if (sna_wait_vblank(sna, &vbl))
 		goto blit_fallback;
 
 	current_msc = vbl.reply.sequence;
@@ -1648,7 +1658,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 			 vbl.request.type |= DRM_VBLANK_SECONDARY;
 		 vbl.request.sequence = *target_msc;
 		 vbl.request.signal = (unsigned long)info;
-		 if (drmWaitVBlank(sna->kgem.fd, &vbl))
+		 if (sna_wait_vblank(sna, &vbl))
 			 goto blit_fallback;
 
 		 return TRUE;
@@ -1683,7 +1693,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	vbl.request.sequence -= 1;
 
 	vbl.request.signal = (unsigned long)info;
-	if (drmWaitVBlank(sna->kgem.fd, &vbl))
+	if (sna_wait_vblank(sna, &vbl))
 		goto blit_fallback;
 
 	*target_msc = vbl.reply.sequence;
@@ -1849,20 +1859,14 @@ sna_dri_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
 		return TRUE;
 	}
 
+	VG_CLEAR(vbl);
+
 	vbl.request.type = DRM_VBLANK_RELATIVE;
 	if (pipe > 0)
 		vbl.request.type |= DRM_VBLANK_SECONDARY;
 	vbl.request.sequence = 0;
 
-	if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
-		static int limit = 5;
-		if (limit) {
-			xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
-				   "%s:%d get vblank counter failed: %s\n",
-				   __FUNCTION__, __LINE__,
-				   strerror(errno));
-			limit--;
-		}
+	if (sna_wait_vblank(sna, &vbl)) {
 		DBG(("%s: failed on pipe %d\n", __FUNCTION__, pipe));
 		return FALSE;
 	}
@@ -1906,22 +1910,15 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 	if (pipe == -1)
 		goto out_complete;
 
+	VG_CLEAR(vbl);
+
 	/* Get current count */
 	vbl.request.type = DRM_VBLANK_RELATIVE;
 	if (pipe > 0)
 		vbl.request.type |= DRM_VBLANK_SECONDARY;
 	vbl.request.sequence = 0;
-	if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
-		static int limit = 5;
-		if (limit) {
-			xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
-				   "%s:%d get vblank counter failed: %s\n",
-				   __FUNCTION__, __LINE__,
-				   strerror(errno));
-			limit--;
-		}
+	if (sna_wait_vblank(sna, &vbl))
 		goto out_complete;
-	}
 
 	current_msc = vbl.reply.sequence;
 
@@ -1961,17 +1958,8 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 			vbl.request.type |= DRM_VBLANK_SECONDARY;
 		vbl.request.sequence = target_msc;
 		vbl.request.signal = (unsigned long)info;
-		if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
-			static int limit = 5;
-			if (limit) {
-				xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
-					   "%s:%d get vblank counter failed: %s\n",
-					   __FUNCTION__, __LINE__,
-					   strerror(errno));
-				limit--;
-			}
+		if (sna_wait_vblank(sna, &vbl))
 			goto out_free_info;
-		}
 
 		info->frame = vbl.reply.sequence;
 		DRI2BlockClient(client, draw);
@@ -1998,17 +1986,8 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 		vbl.request.sequence += divisor;
 
 	vbl.request.signal = (unsigned long)info;
-	if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
-		static int limit = 5;
-		if (limit) {
-			xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
-				   "%s:%d get vblank counter failed: %s\n",
-				   __FUNCTION__, __LINE__,
-				   strerror(errno));
-			limit--;
-		}
+	if (sna_wait_vblank(sna, &vbl))
 		goto out_free_info;
-	}
 
 	info->frame = vbl.reply.sequence;
 	DRI2BlockClient(client, draw);
commit 8ebe84818ab70e662a9bb3f232b4664ff40ac375
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 14:27:46 2012 +0100

    sna: Make sna_copy_fbcon() valgrind clean
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index e0b9ee5..5d84578 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -554,7 +554,7 @@ sna_crtc_dpms(xf86CrtcPtr crtc, int mode)
 }
 
 static struct kgem_bo *sna_create_bo_for_fbcon(struct sna *sna,
-					       drmModeFBPtr fbcon)
+					       const struct drm_mode_fb_cmd *fbcon)
 {
 	struct drm_gem_flink flink;
 	struct kgem_bo *bo;
@@ -584,7 +584,7 @@ static struct kgem_bo *sna_create_bo_for_fbcon(struct sna *sna,
 void sna_copy_fbcon(struct sna *sna)
 {
 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(sna->scrn);
-	drmModeFBPtr fbcon;
+	struct drm_mode_fb_cmd fbcon;
 	PixmapPtr scratch;
 	struct sna_pixmap *priv;
 	struct kgem_bo *bo;
@@ -600,22 +600,27 @@ void sna_copy_fbcon(struct sna *sna)
 	DBG(("%s\n", __FUNCTION__));
 
 	/* Scan the connectors for a framebuffer and assume that is the fbcon */
-	fbcon = NULL;
-	for (i = 0; fbcon == NULL && i < xf86_config->num_crtc; i++) {
+	VG_CLEAR(fbcon);
+	fbcon.fb_id = 0;
+	for (i = 0; i < xf86_config->num_crtc; i++) {
 		struct sna_crtc *crtc = xf86_config->crtc[i]->driver_private;
-		drmModeCrtcPtr mode_crtc;
+		struct drm_mode_crtc mode;
 
-		mode_crtc = drmModeGetCrtc(sna->kgem.fd,
-					   sna->mode.mode_res->crtcs[crtc->num]);
-		if (mode_crtc == NULL)
+		VG_CLEAR(mode);
+		mode.crtc_id = crtc->id;
+		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
+			continue;
+		if (!mode.fb_id)
 			continue;
 
-		if (mode_crtc->buffer_id)
-			fbcon = drmModeGetFB(sna->kgem.fd,
-					     mode_crtc->buffer_id);
-		drmModeFreeCrtc(mode_crtc);
+		fbcon.fb_id = mode.fb_id;
+		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETFB, &fbcon)) {
+			fbcon.fb_id = 0;
+			continue;
+		}
+		break;
 	}
-	if (fbcon == NULL) {
+	if (fbcon.fb_id == 0) {
 		DBG(("%s: no fbcon found\n", __FUNCTION__));
 		return;
 	}
@@ -625,17 +630,17 @@ void sna_copy_fbcon(struct sna *sna)
 	 * across a depth change upon starting X.
 	 */
 	scratch = GetScratchPixmapHeader(sna->scrn->pScreen,
-					fbcon->width, fbcon->height,
-					fbcon->depth, fbcon->bpp,
+					fbcon.width, fbcon.height,
+					fbcon.depth, fbcon.bpp,
 					0, NULL);
 	if (scratch == NullPixmap)
-		goto cleanup_fbcon;
+		return;
 
 	box.x1 = box.y1 = 0;
-	box.x2 = min(fbcon->width, sna->front->drawable.width);
-	box.y2 = min(fbcon->height, sna->front->drawable.height);
+	box.x2 = min(fbcon.width, sna->front->drawable.width);
+	box.y2 = min(fbcon.height, sna->front->drawable.height);
 
-	bo = sna_create_bo_for_fbcon(sna, fbcon);
+	bo = sna_create_bo_for_fbcon(sna, &fbcon);
 	if (bo == NULL)
 		goto cleanup_scratch;
 
@@ -645,14 +650,14 @@ void sna_copy_fbcon(struct sna *sna)
 	assert(priv && priv->gpu_bo);
 
 	sx = dx = 0;
-	if (box.x2 < (uint16_t)fbcon->width)
-		sx = (fbcon->width - box.x2) / 2.;
+	if (box.x2 < (uint16_t)fbcon.width)
+		sx = (fbcon.width - box.x2) / 2.;
 	if (box.x2 < sna->front->drawable.width)
 		dx = (sna->front->drawable.width - box.x2) / 2.;
 
 	sy = dy = 0;
-	if (box.y2 < (uint16_t)fbcon->height)
-		sy = (fbcon->height - box.y2) / 2.;
+	if (box.y2 < (uint16_t)fbcon.height)
+		sy = (fbcon.height - box.y2) / 2.;
 	if (box.y2 < sna->front->drawable.height)
 		dy = (sna->front->drawable.height - box.y2) / 2.;
 
@@ -669,8 +674,6 @@ void sna_copy_fbcon(struct sna *sna)
 
 cleanup_scratch:
 	FreeScratchPixmapHeader(scratch);
-cleanup_fbcon:
-	drmModeFreeFB(fbcon);
 }
 
 static void update_flush_interval(struct sna *sna)
commit f37dae734ebac5c0ed2d6f50fc92bc107f4e4a33
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 14:20:54 2012 +0100

    sna: Just use the CRTC id from the array
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 8ca8efb..e0b9ee5 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -971,7 +971,6 @@ static void
 sna_crtc_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
 {
 	struct sna *sna = to_sna(scrn);
-	drmModeCrtcPtr mode_crtc;
 	xf86CrtcPtr crtc;
 	struct sna_crtc *sna_crtc;
 	struct drm_i915_get_pipe_from_crtc_id get_pipe;
@@ -983,10 +982,7 @@ sna_crtc_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
 		return;
 
 	sna_crtc->num = num;
-
-	mode_crtc = drmModeGetCrtc(sna->kgem.fd, mode->mode_res->crtcs[num]);
-	sna_crtc->id = mode_crtc->crtc_id;
-	drmModeFreeCrtc(mode_crtc);
+	sna_crtc->id = mode->mode_res->crtcs[num];
 
 	VG_CLEAR(get_pipe);
 	get_pipe.pipe = 0;
commit b1f24a0eae4bb0081ff7469a2aee63a1f32140f7
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 14:16:03 2012 +0100

    sna: Make sna_crtc_apply() valgrind clean
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 9aade61..8ca8efb 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -54,7 +54,7 @@
 
 struct sna_crtc {
 	struct sna *sna;
-	drmModeModeInfo kmode;
+	struct drm_mode_modeinfo kmode;
 	PixmapPtr shadow;
 	uint32_t shadow_fb_id;
 	uint32_t cursor;
@@ -371,7 +371,7 @@ mode_from_kmode(ScrnInfoPtr scrn,
 }
 
 static void
-mode_to_kmode(drmModeModeInfoPtr kmode, DisplayModePtr mode)
+mode_to_kmode(struct drm_mode_modeinfo *kmode, DisplayModePtr mode)
 {
 	memset(kmode, 0, sizeof(*kmode));
 
@@ -415,6 +415,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 	struct sna_crtc *sna_crtc = crtc->driver_private;
 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
 	struct sna_mode *mode = &sna->mode;
+	struct drm_mode_crtc arg;
 	uint32_t output_ids[16];
 	int output_count = 0;
 	int fb_id, x, y;
@@ -468,9 +469,16 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 	     fb_id, sna_crtc->shadow_fb_id ? " [shadow]" : "",
 	     output_count));
 
-	ret = drmModeSetCrtc(sna->kgem.fd, crtc_id(sna_crtc),
-			     fb_id, x, y, output_ids, output_count,
-			     &sna_crtc->kmode);
+	VG_CLEAR(arg);
+	arg.x = x;
+	arg.y = y;
+	arg.crtc_id = sna_crtc->id;
+	arg.fb_id = fb_id;
+	arg.set_connectors_ptr = (uintptr_t)output_ids;
+	arg.count_connectors = output_count;
+	arg.mode = sna_crtc->kmode;
+	arg.mode_valid = 1;
+	ret = drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg);
 	if (ret) {
 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
 			   "failed to set mode: %s\n", strerror(-ret));
commit 0ebfcdbb80245f98c0c7ef9f090a2be6900fb457
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 14:10:04 2012 +0100

    sna: Make AddFB valgrind clean
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 2d6cba4..9aade61 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -157,6 +157,7 @@ static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
 		       int width, int height)
 {
 	ScrnInfoPtr scrn = sna->scrn;
+	struct drm_mode_fb_cmd arg;
 	int ret;
 
 	assert(bo->proxy == NULL);
@@ -170,21 +171,25 @@ static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
 	     __FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel));
 
 	assert(bo->tiling != I915_TILING_Y);
-	ret = drmModeAddFB(sna->kgem.fd,
-			   width, height,
-			   scrn->depth, scrn->bitsPerPixel,
-			   bo->pitch, bo->handle,
-			   &bo->delta);
-	if (ret < 0) {
-		ErrorF("%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d\n",
-		       __FUNCTION__,
-		       width, height,
-		       scrn->depth, scrn->bitsPerPixel, bo->pitch);
+
+	VG_CLEAR(arg);
+	arg.width = width;
+	arg.height = height;
+	arg.pitch = bo->pitch;
+	arg.bpp = scrn->bitsPerPixel;
+	arg.depth = scrn->depth;
+	arg.handle = bo->handle;
+
+	if ((ret = drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_ADDFB, &arg))) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n",
+			   __FUNCTION__, width, height,
+			   scrn->depth, scrn->bitsPerPixel, bo->pitch, ret);
 		return 0;
 	}
 
 	bo->scanout = true;
-	return bo->delta;
+	return bo->delta = arg.fb_id;
 }
 
 static uint32_t gem_create(int fd, int size)
commit 32ca3c7b65516b0bd48b0d0979b086ee1580167a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 14:02:11 2012 +0100

    sna: Make sna_crtc_is_bound() valgrind clean
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index ec0e03d..2d6cba4 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -393,6 +393,7 @@ bool sna_crtc_is_bound(struct sna *sna, xf86CrtcPtr crtc)
 {
 	struct drm_mode_crtc mode;
 
+	VG_CLEAR(mode);
 	mode.crtc_id = crtc_id(crtc->driver_private);
 	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
 		return false;
commit 7973f6751c9bf565dee4c89aa3e1badbcc45018f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 14:00:55 2012 +0100

    sna: Add a little bit more verbosity to cursor routines for valgrind
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index a218d83..ec0e03d 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -748,54 +748,78 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 }
 
 static void
-sna_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
+sna_crtc_hide_cursor(xf86CrtcPtr crtc)
 {
+	struct sna *sna = to_sna(crtc->scrn);
+	struct sna_crtc *sna_crtc = crtc->driver_private;
+	struct drm_mode_cursor arg;
+
+	DBG(("%s: CRTC:%d\n", __FUNCTION__, crtc_id(sna_crtc)));
+
+	VG_CLEAR(arg);
+	arg.flags = DRM_MODE_CURSOR_BO;
+	arg.crtc_id = sna_crtc->id;
+	arg.width = arg.height = 64;
+	arg.handle = 0;
 
+	drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
 }
 
 static void
-sna_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
+sna_crtc_show_cursor(xf86CrtcPtr crtc)
 {
 	struct sna *sna = to_sna(crtc->scrn);
 	struct sna_crtc *sna_crtc = crtc->driver_private;
+	struct drm_mode_cursor arg;
+
+	DBG(("%s: CRTC:%d\n", __FUNCTION__, crtc_id(sna_crtc)));
 
-	drmModeMoveCursor(sna->kgem.fd, crtc_id(sna_crtc), x, y);
+	VG_CLEAR(arg);
+	arg.flags = DRM_MODE_CURSOR_BO;
+	arg.crtc_id = sna_crtc->id;
+	arg.width = arg.height = 64;
+	arg.handle = sna_crtc->cursor;
+
+	drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
 }
 
 static void
-sna_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
+sna_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
 {
-	struct sna *sna = to_sna(crtc->scrn);
-	struct sna_crtc *sna_crtc = crtc->driver_private;
-	struct drm_i915_gem_pwrite pwrite;
-
-	VG_CLEAR(pwrite);
-	pwrite.handle = sna_crtc->cursor;
-	pwrite.offset = 0;
-	pwrite.size = 64*64*4;
-	pwrite.data_ptr = (uintptr_t)image;
-	(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite);
 }
 
 static void
-sna_crtc_hide_cursor(xf86CrtcPtr crtc)
+sna_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
 {
 	struct sna *sna = to_sna(crtc->scrn);
 	struct sna_crtc *sna_crtc = crtc->driver_private;
+	struct drm_mode_cursor arg;
 
-	DBG(("%s: CRTC:%d\n", __FUNCTION__, crtc_id(sna_crtc)));
-	drmModeSetCursor(sna->kgem.fd, crtc_id(sna_crtc), 0, 64, 64);
+	DBG(("%s: CRTC:%d (%d, %d)\n", __FUNCTION__, crtc_id(sna_crtc), x, y));
+
+	VG_CLEAR(arg);
+	arg.flags = DRM_MODE_CURSOR_MOVE;
+	arg.crtc_id = sna_crtc->id;
+	arg.x = x;
+	arg.y = y;
+	arg.handle = sna_crtc->cursor;
+
+	drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
 }
 
 static void
-sna_crtc_show_cursor(xf86CrtcPtr crtc)
+sna_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
 {
 	struct sna *sna = to_sna(crtc->scrn);
 	struct sna_crtc *sna_crtc = crtc->driver_private;
+	struct drm_i915_gem_pwrite pwrite;
 
-	DBG(("%s: CRTC:%d\n", __FUNCTION__, crtc_id(sna_crtc)));
-	drmModeSetCursor(sna->kgem.fd, crtc_id(sna_crtc),
-			 sna_crtc->cursor, 64, 64);
+	VG_CLEAR(pwrite);
+	pwrite.handle = sna_crtc->cursor;
+	pwrite.offset = 0;
+	pwrite.size = 64*64*4;
+	pwrite.data_ptr = (uintptr_t)image;
+	(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite);
 }
 
 static void *
commit 19c463e52df919fc75de7e420fd3565f0e9a0576
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 12:54:35 2012 +0100

    sna: Only wait if there is a suitable active buffer
    
    There is not point repeating the search after retiring if we know that
    there is no outstanding suitable active buffer.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 0ef160c..af5b4b9 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -2837,7 +2837,9 @@ search_inactive:
 		return bo;
 	}
 
-	if (flags & CREATE_INACTIVE && __kgem_throttle_retire(kgem, flags)) {
+	if (flags & CREATE_INACTIVE &&
+	    !list_is_empty(&kgem->active[bucket][tiling]) &&
+	    __kgem_throttle_retire(kgem, flags)) {
 		flags &= ~CREATE_INACTIVE;
 		goto search_inactive;
 	}
commit 5b99c7cd340f782d3057d4257865c5feb96b71f0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 10:55:49 2012 +0100

    uxa/dri: Enable vblank scheduling even with pageflipping disabled
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/intel_dri.c b/src/intel_dri.c
index 34d00b6..3261e54 100644
--- a/src/intel_dri.c
+++ b/src/intel_dri.c
@@ -1685,15 +1685,13 @@ Bool I830DRI2ScreenInit(ScreenPtr screen)
 
 	info.CopyRegion = I830DRI2CopyRegion;
 #if DRI2INFOREC_VERSION >= 4
-	if (intel->use_pageflipping) {
-	    info.version = 4;
-	    info.ScheduleSwap = I830DRI2ScheduleSwap;
-	    info.GetMSC = I830DRI2GetMSC;
-	    info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC;
-	    info.numDrivers = 1;
-	    info.driverNames = driverNames;
-	    driverNames[0] = info.driverName;
-	}
+	info.version = 4;
+	info.ScheduleSwap = I830DRI2ScheduleSwap;
+	info.GetMSC = I830DRI2GetMSC;
+	info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC;
+	info.numDrivers = 1;
+	info.driverNames = driverNames;
+	driverNames[0] = info.driverName;
 #endif
 
 	return DRI2ScreenInit(screen, &info);
commit 810357ad65d551ec5d35dbf228f1b62fe235801f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 10:12:38 2012 +0100

    uxa/dri: Fix ordering of setting vs using swap members
    
    Trivial readibility fix, as the actual ordering is serialised through
    there being only a single thread.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/intel_dri.c b/src/intel_dri.c
index 36e96ff..34d00b6 100644
--- a/src/intel_dri.c
+++ b/src/intel_dri.c
@@ -933,12 +933,12 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel,
 	int tmp_name;
 
 	if (!intel->use_triple_buffer) {
+		info->type = DRI2_SWAP;
 		if (!intel_do_pageflip(intel,
 				       intel_get_pixmap_bo(priv->pixmap),
 				       info, info->pipe))
 			return FALSE;
 
-		info->type = DRI2_SWAP;
 		I830DRI2ExchangeBuffers(intel, info->front, info->back);
 		return TRUE;
 	}
commit 2b56a188ef2c48f82572eca2201a3a0ecf6b4f45
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 10:01:09 2012 +0100

    Mark another couple of options as being UXA only.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/intel_options.c b/src/intel_options.c
index 80572be..56929be 100644
--- a/src/intel_options.c
+++ b/src/intel_options.c
@@ -7,9 +7,7 @@ const OptionInfoRec intel_options[] = {
 	{OPTION_VIDEO_KEY,	"VideoKey",	OPTV_INTEGER,	{0},	0},
 	{OPTION_TILING_2D,	"Tiling",	OPTV_BOOLEAN,	{0},	1},
 	{OPTION_TILING_FB,	"LinearFramebuffer",	OPTV_BOOLEAN,	{0},	0},
-	{OPTION_SHADOW,	"Shadow",	OPTV_BOOLEAN,	{0},	0},
 	{OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN,	{0},	1},
-	{OPTION_TRIPLE_BUFFER, "TripleBuffer", OPTV_BOOLEAN,	{0},	1},
 #ifdef INTEL_XVMC
 	{OPTION_XVMC,	"XvMC",		OPTV_BOOLEAN,	{0},	1},
 #endif
@@ -26,8 +24,10 @@ const OptionInfoRec intel_options[] = {
 	{OPTION_DELAYED_FLUSH,	"DelayedFlush",	OPTV_BOOLEAN,	{0},	1},
 #endif
 #ifdef USE_UXA
-	{OPTION_FALLBACKDEBUG, "FallbackDebug", OPTV_BOOLEAN, {0},	0},
-	{OPTION_BUFFER_CACHE,       "BufferCache",  OPTV_BOOLEAN,   {0},    1},
+	{OPTION_FALLBACKDEBUG,	"FallbackDebug",OPTV_BOOLEAN,	{0},	0},
+	{OPTION_BUFFER_CACHE,	"BufferCache",	OPTV_BOOLEAN,   {0},    1},
+	{OPTION_SHADOW,		"Shadow",	OPTV_BOOLEAN,	{0},	0},
+	{OPTION_TRIPLE_BUFFER,	"TripleBuffer", OPTV_BOOLEAN,	{0},	1},
 #endif
 	{-1,			NULL,		OPTV_NONE,	{0},	0}
 };
commit b025f1a604dbbbd456a23f330ceed5f97ecdffcf
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 09:48:49 2012 +0100

    sna/dri: Tweak vblank_mode=n swapbuffers to account for throttle delay
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 0f582b5..2ce4e40 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -1665,26 +1665,22 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		     (int)*target_msc,
 		     (int)divisor));
 
-	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
-	vbl.request.type |= DRM_VBLANK_NEXTONMISS;
+	vbl.request.type =
+		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | DRM_VBLANK_NEXTONMISS;
 	if (pipe > 0)
 		vbl.request.type |= DRM_VBLANK_SECONDARY;
 
 	vbl.request.sequence = current_msc - current_msc % divisor + 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, as well as a potential DRM_VBLANK_NEXTONMISS delay
-	 * if we are blitting/exchanging instead of flipping.
 	 */
-	if (vbl.request.sequence <= current_msc)
+	if (vbl.request.sequence < current_msc)
 		vbl.request.sequence += divisor;
+	vbl.request.sequence -= 1;
 
 	vbl.request.signal = (unsigned long)info;
 	if (drmWaitVBlank(sna->kgem.fd, &vbl))
commit 45148a714f1461fff898aeb393ad225f081b9bd5
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 09:39:51 2012 +0100

    sna/dri: Enable handling for Option "SwapBuffersWait"
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index 92614d0..b4f2ba4 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -208,6 +208,8 @@ struct sna {
 	unsigned flags;
 #define SNA_NO_THROTTLE		0x1
 #define SNA_NO_DELAYED_FLUSH	0x2
+#define SNA_NO_WAIT		0x4
+#define SNA_NO_FLIP		0x8
 
 	unsigned watch_flush;
 	unsigned flush;
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index ee509c0..0f582b5 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -448,7 +448,8 @@ sna_dri_copy_to_front(struct sna *sna, DrawablePtr draw, RegionPtr region,
 			return NULL;
 		}
 
-		if (pixmap == sna->front && sync) {
+		if (pixmap == sna->front && sync &&
+		    (sna->flags & SNA_NO_WAIT) == 0) {
 			BoxRec crtc_box;
 
 			crtc = sna_covering_crtc(sna->scrn, &region->extents,
@@ -952,6 +953,11 @@ can_flip(struct sna * sna,
 		return FALSE;
 	}
 
+	if (sna->flags & SNA_NO_FLIP) {
+		DBG(("%s: no, pageflips disabled\n", __FUNCTION__));
+		return FALSE;
+	}
+
 	if (front->format != back->format) {
 		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
 		     __FUNCTION__, front->format, back->format));
@@ -1591,21 +1597,22 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 						 get_private(front)->bo,
 						 get_private(back)->bo,
 						 true);
-
-		info->type = DRI2_SWAP_THROTTLE;
-		vbl.request.type =
-			DRM_VBLANK_RELATIVE |
-			DRM_VBLANK_NEXTONMISS |
-			DRM_VBLANK_EVENT;
-		if (pipe > 0)
-			vbl.request.type |= DRM_VBLANK_SECONDARY;
-		vbl.request.sequence = 0;
-		vbl.request.signal = (unsigned long)info;
-		if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
-			sna_dri_frame_event_info_free(info);
-			DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
+		if ((sna->flags & SNA_NO_WAIT) == 0) {
+			info->type = DRI2_SWAP_THROTTLE;
+			vbl.request.type =
+				DRM_VBLANK_RELATIVE |
+				DRM_VBLANK_NEXTONMISS |
+				DRM_VBLANK_EVENT;
+			if (pipe > 0)
+				vbl.request.type |= DRM_VBLANK_SECONDARY;
+			vbl.request.sequence = 0;
+			vbl.request.signal = (unsigned long)info;
+			if (drmWaitVBlank(sna->kgem.fd, &vbl) == 0)
+				return TRUE;
 		}
 
+		sna_dri_frame_event_info_free(info);
+		DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
 		return TRUE;
 	}
 
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index 39e67c4..af8bfe9 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -62,6 +62,11 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <sys/poll.h>
 #include "i915_drm.h"
 
+#ifdef HAVE_VALGRIND
+#include <valgrind.h>
+#include <memcheck.h>
+#endif
+
 #if HAVE_DOT_GIT
 #include "git_version.h"
 #endif
@@ -372,6 +377,23 @@ static void sna_selftest(void)
 	sna_damage_selftest();
 }
 
+static bool has_pageflipping(struct sna *sna)
+{
+	drm_i915_getparam_t gp;
+	int v;
+
+	if (sna->flags & SNA_NO_WAIT)
+		return false;
+
+	VG_CLEAR(gp);
+	gp.param = I915_PARAM_HAS_PAGEFLIPPING;
+	gp.value = &v;
+	drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GETPARAM, &gp);
+
+	VG(VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v)));
+	return v > 0;
+}
+
 /**
  * This is called before ScreenInit to do any require probing of screen
  * configuration.
@@ -500,6 +522,10 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
 		sna->flags |= SNA_NO_THROTTLE;
 	if (!xf86ReturnOptValBool(sna->Options, OPTION_DELAYED_FLUSH, TRUE))
 		sna->flags |= SNA_NO_DELAYED_FLUSH;
+	if (!xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE))
+		sna->flags |= SNA_NO_WAIT;
+	if (!has_pageflipping(sna))
+		sna->flags |= SNA_NO_FLIP;
 
 	xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Framebuffer %s\n",
 		   sna->tiling & SNA_TILING_FB ? "tiled" : "linear");
commit c709f2447dfc6dc36c50ff741d5d9bbdc7c03b58
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 08:17:21 2012 +0100

    sna/dri: Requeue vblank throttling until the vsync'ed copy completes
    
    If the GPU is busy, then we may not actually schedule our copy for
    several vblanks, resulting in us falsely reporting that the work
    completed too early and allowing the client to continue scheduling more
    work and racing ahead of the queued copies.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 9d2fd99..0ef160c 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -1382,17 +1382,18 @@ static bool kgem_retire__requests(struct kgem *kgem)
 			}
 		}
 
-		rq->bo->refcnt--;
-		assert(rq->bo->refcnt == 0);
 		assert(rq->bo->rq == NULL);
 		assert(list_is_empty(&rq->bo->request));
-		if (kgem_bo_set_purgeable(kgem, rq->bo)) {
-			kgem_bo_move_to_inactive(kgem, rq->bo);
-			retired = true;
-		} else {
-			DBG(("%s: closing %d\n",
-			     __FUNCTION__, rq->bo->handle));
-			kgem_bo_free(kgem, rq->bo);
+
+		if (--rq->bo->refcnt == 0) {
+			if (kgem_bo_set_purgeable(kgem, rq->bo)) {
+				kgem_bo_move_to_inactive(kgem, rq->bo);
+				retired = true;
+			} else {
+				DBG(("%s: closing %d\n",
+				     __FUNCTION__, rq->bo->handle));
+				kgem_bo_free(kgem, rq->bo);
+			}
 		}
 
 		if (kgem->sync == rq)
@@ -4221,3 +4222,17 @@ kgem_replace_bo(struct kgem *kgem,
 
 	return dst;
 }
+
+struct kgem_bo *kgem_get_last_request(struct kgem *kgem)
+{
+	struct kgem_request *rq;
+
+	if (list_is_empty(&kgem->requests))
+		return NULL;
+
+	rq = list_last_entry(&kgem->requests,
+			     struct kgem_request,
+			     list);
+
+	return kgem_bo_reference(rq->bo);
+}
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index fdabfae..bb6bcf2 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -245,6 +245,7 @@ void kgem_bo_set_binding(struct kgem_bo *bo, uint32_t format, uint16_t offset);
 
 void kgem_bo_retire(struct kgem *kgem, struct kgem_bo *bo);
 bool kgem_retire(struct kgem *kgem);
+struct kgem_bo *kgem_get_last_request(struct kgem *kgem);
 
 void _kgem_submit(struct kgem *kgem);
 static inline void kgem_submit(struct kgem *kgem)
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 632c57d..ee509c0 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -90,6 +90,7 @@ struct sna_dri_frame_event {
 	void *event_data;
 	DRI2BufferPtr front;
 	DRI2BufferPtr back;
+	struct kgem_bo *bo;
 
 	unsigned int fe_frame;
 	unsigned int fe_tv_sec;
@@ -395,13 +396,14 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
 	priv->gpu_bo = ref(bo);
 }
 
-static void
+static struct kgem_bo *
 sna_dri_copy_to_front(struct sna *sna, DrawablePtr draw, RegionPtr region,
 		      struct kgem_bo *dst_bo, struct kgem_bo *src_bo,
 		      bool sync)
 {
 	PixmapPtr pixmap = get_drawable_pixmap(draw);
 	pixman_region16_t clip;
+	struct kgem_bo *bo = NULL;
 	bool flush = false;
 	xf86CrtcPtr crtc;
 	BoxRec box, *boxes;
@@ -421,7 +423,7 @@ sna_dri_copy_to_front(struct sna *sna, DrawablePtr draw, RegionPtr region,
 
 		if (!pixman_region_not_empty(region)) {
 			DBG(("%s: all clipped\n", __FUNCTION__));
-			return;
+			return NULL;
 		}
 	}
 
@@ -443,7 +445,7 @@ sna_dri_copy_to_front(struct sna *sna, DrawablePtr draw, RegionPtr region,
 		pixman_region_intersect(region, &win->clipList, region);
 		if (!pixman_region_not_empty(region)) {
 			DBG(("%s: all clipped\n", __FUNCTION__));
-			return;
+			return NULL;
 		}
 
 		if (pixmap == sna->front && sync) {
@@ -495,6 +497,7 @@ sna_dri_copy_to_front(struct sna *sna, DrawablePtr draw, RegionPtr region,
 	if (flush) { /* STAT! */
 		assert(sna_crtc_is_bound(sna, crtc));
 		kgem_submit(&sna->kgem);
+		bo = kgem_get_last_request(&sna->kgem);
 	}
 
 	pixman_region_translate(region, dx, dy);
@@ -503,6 +506,8 @@ sna_dri_copy_to_front(struct sna *sna, DrawablePtr draw, RegionPtr region,
 
 	if (region == &clip)
 		pixman_region_fini(&clip);
+
+	return bo;
 }
 
 static void
@@ -650,7 +655,7 @@ sna_dri_copy_region(DrawablePtr draw,
 
 	if (dst_buffer->attachment == DRI2BufferFrontLeft) {
 		dst = sna_pixmap_get_bo(pixmap);
-		copy = sna_dri_copy_to_front;
+		copy = (void *)sna_dri_copy_to_front;
 	} else
 		dst = get_private(dst_buffer)->bo;
 
@@ -884,6 +889,9 @@ sna_dri_frame_event_info_free(struct sna_dri_frame_event *info)
 		sna_dri_frame_event_release_bo(&info->sna->kgem,
 					       info->cache.bo);
 
+	if (info->bo)
+		kgem_bo_destroy(&info->sna->kgem, info->bo);
+
 	free(info);
 }
 
@@ -1052,13 +1060,32 @@ static void sna_dri_vblank_handle(int fd,
 		}
 		/* else fall through to blit */
 	case DRI2_SWAP:
-		sna_dri_copy_to_front(sna, draw, NULL,
-				      get_private(info->front)->bo,
-				      get_private(info->back)->bo,
-				      true);
+		info->bo = sna_dri_copy_to_front(sna, draw, NULL,
+						 get_private(info->front)->bo,
+						 get_private(info->back)->bo,
+						 true);
+		info->type = DRI2_SWAP_THROTTLE;
 	case DRI2_SWAP_THROTTLE:
 		DBG(("%s: %d complete, frame=%d tv=%d.%06d\n",
 		     __FUNCTION__, info->type, frame, tv_sec, tv_usec));
+
+		if (info->bo && kgem_bo_is_busy(info->bo)) {
+			kgem_retire(&sna->kgem);
+			if (kgem_bo_is_busy(info->bo)) {
+				drmVBlank vbl;
+
+				vbl.request.type =
+					DRM_VBLANK_RELATIVE |
+					DRM_VBLANK_EVENT;
+				if (info->pipe > 0)
+					vbl.request.type |= DRM_VBLANK_SECONDARY;
+				vbl.request.sequence = 1;
+				vbl.request.signal = (unsigned long)info;
+				if (!drmWaitVBlank(sna->kgem.fd, &vbl))
+					return;
+			}
+		}
+
 		DRI2SwapComplete(info->client,
 				 draw, frame,
 				 tv_sec, tv_usec,
@@ -1560,26 +1587,26 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		DBG(("%s: emitting immediate vsync'ed blit, throttling client\n",
 		     __FUNCTION__));
 
-		 info->type = DRI2_SWAP_THROTTLE;
+		info->bo = sna_dri_copy_to_front(sna, draw, NULL,
+						 get_private(front)->bo,
+						 get_private(back)->bo,
+						 true);
 
-		 vbl.request.type =
-			 DRM_VBLANK_RELATIVE |
-			 DRM_VBLANK_EVENT |
-			 DRM_VBLANK_NEXTONMISS;
-		 if (pipe > 0)
-			 vbl.request.type |= DRM_VBLANK_SECONDARY;
-		 vbl.request.sequence = 0;
-		 vbl.request.signal = (unsigned long)info;
-		 if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
-			 sna_dri_frame_event_info_free(info);
-			 DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
-		 }
-
-		 sna_dri_copy_to_front(sna, draw, NULL,
-				       get_private(front)->bo,
-				       get_private(back)->bo,
-				       true);
-		 return TRUE;
+		info->type = DRI2_SWAP_THROTTLE;
+		vbl.request.type =
+			DRM_VBLANK_RELATIVE |
+			DRM_VBLANK_NEXTONMISS |
+			DRM_VBLANK_EVENT;
+		if (pipe > 0)
+			vbl.request.type |= DRM_VBLANK_SECONDARY;
+		vbl.request.sequence = 0;
+		vbl.request.signal = (unsigned long)info;
+		if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
+			sna_dri_frame_event_info_free(info);
+			DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
+		}
+
+		return TRUE;
 	}
 
 	/* Get current count */
commit 7e73fa02ed361a9c0c08f61d00421671bf10ce9f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 28 08:16:43 2012 +0100

    sna: Add some debugging to show count of outstanding requests during retire
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 00ef82d..9d2fd99 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -1306,6 +1306,14 @@ static bool kgem_retire__flushing(struct kgem *kgem)
 				kgem_bo_free(kgem, bo);
 		}
 	}
+#if DEBUG_KGEM
+	{
+		int count = 0;
+		list_for_each_entry(bo, &kgem->flushing, request)
+			count++;
+		ErrorF("%s: %d bo on flushing list\n", __FUNCTION__, count);
+	}
+#endif
 
 	return retired;
 }
@@ -1394,6 +1402,24 @@ static bool kgem_retire__requests(struct kgem *kgem)
 		free(rq);
 	}
 
+#if DEBUG_KGEM
+	{
+		int count = 0;
+
+		list_for_each_entry(bo, &kgem->requests, request)
+			count++;
+
+		bo = NULL;
+		if (!list_is_empty(&kgem->requests))
+			bo = list_first_entry(&kgem->requests,
+					      struct kgem_request,
+					      list)->bo;
+
+		ErrorF("%s: %d outstanding requests, oldest=%d\n",
+		       __FUNCTION__, count, bo ? bo->handle : 0);
+	}
+#endif
+
 	return retired;
 }
 
commit 62b557065edc0555f2bf83b0eed9169329a2f2ba
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun May 27 16:52:51 2012 +0100

    sna: Use magic upload buffers for video textures
    
    So that we may benefit from the caching of buffers and the automatic
    selection  of the preferred upload method.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_video.c b/src/sna/sna_video.c
index 1f6e210..ce1e284 100644
--- a/src/sna/sna_video.c
+++ b/src/sna/sna_video.c
@@ -196,6 +196,7 @@ sna_video_frame_init(struct sna *sna,
 {
 	int align;
 
+	frame->bo = NULL;
 	frame->id = id;
 	frame->width = width;
 	frame->height = height;
@@ -444,12 +445,9 @@ sna_video_copy_data(struct sna *sna,
 {
 	uint8_t *dst;
 
-	if (frame->bo == NULL)
-		return FALSE;
-
 	DBG(("%s: handle=%d, size=%dx%d, rotation=%d\n",
-	     __FUNCTION__, frame->bo->handle, frame->width, frame->height,
-	     video->rotation));
+	     __FUNCTION__, frame->bo ? frame->bo->handle : 0,
+	     frame->width, frame->height, video->rotation));
 	DBG(("%s: top=%d, left=%d\n", __FUNCTION__, frame->top, frame->left));
 
 	/* In the common case, we can simply the upload in a single pwrite */
@@ -462,10 +460,22 @@ sna_video_copy_data(struct sna *sna,
 			if (pitch[0] == frame->pitch[0] &&
 			    pitch[1] == frame->pitch[1] &&
 			    frame->top == 0 && frame->left == 0) {
-				kgem_bo_write(&sna->kgem, frame->bo,
-					      buf,
-					      pitch[1]*frame->height +
-					      pitch[0]*frame->height);
+				if (frame->bo) {
+					kgem_bo_write(&sna->kgem, frame->bo,
+						      buf,
+						      pitch[1]*frame->height +
+						      pitch[0]*frame->height);
+				} else {
+					frame->bo = kgem_create_buffer(&sna->kgem, frame->size,
+								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
+								       (void **)&dst);
+					if (frame->bo == NULL)
+						return FALSE;
+
+					memcpy(dst, buf,
+					       pitch[1]*frame->height +
+					       pitch[0]*frame->height);
+				}
 				if (frame->id != FOURCC_I420) {
 					uint32_t tmp;
 					tmp = frame->VBufOffset;
@@ -476,18 +486,38 @@ sna_video_copy_data(struct sna *sna,
 			}
 		} else {
 			if (frame->width*2 == frame->pitch[0]) {
-				kgem_bo_write(&sna->kgem, frame->bo,
-					      buf + (frame->top * frame->width*2) + (frame->left << 1),
-					      frame->nlines*frame->width*2);
+				if (frame->bo) {
+					kgem_bo_write(&sna->kgem, frame->bo,
+						      buf + (frame->top * frame->width*2) + (frame->left << 1),
+						      frame->nlines*frame->width*2);
+				} else {
+					frame->bo = kgem_create_buffer(&sna->kgem, frame->size,
+								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
+								       (void **)&dst);
+					if (frame->bo == NULL)
+						return FALSE;
+
+					memcpy(dst,
+					       buf + (frame->top * frame->width*2) + (frame->left << 1),
+					       frame->nlines*frame->width*2);
+				}
 				return TRUE;
 			}
 		}
 	}
 
 	/* copy data, must use GTT so that we keep the overlay uncached */
-	dst = kgem_bo_map__gtt(&sna->kgem, frame->bo);
-	if (dst == NULL)
-		return FALSE;
+	if (frame->bo) {
+		dst = kgem_bo_map__gtt(&sna->kgem, frame->bo);
+		if (dst == NULL)
+			return FALSE;
+	} else {
+		frame->bo = kgem_create_buffer(&sna->kgem, frame->size,
+					       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
+					       (void **)&dst);
+		if (frame->bo == NULL)
+			return FALSE;
+	}
 
 	if (is_planar_fourcc(frame->id))
 		sna_copy_planar_data(video, frame, buf, dst);
diff --git a/src/sna/sna_video_textured.c b/src/sna/sna_video_textured.c
index e1806d5..bc117a4 100644
--- a/src/sna/sna_video_textured.c
+++ b/src/sna/sna_video_textured.c
@@ -273,13 +273,6 @@ sna_video_textured_put_image(ScrnInfoPtr scrn,
 
 		assert(kgem_bo_size(frame.bo) >= frame.size);
 	} else {
-		frame.bo = kgem_create_linear(&sna->kgem, frame.size,
-					      CREATE_GTT_MAP);
-		if (frame.bo == NULL) {
-			DBG(("%s: failed to allocate bo\n", __FUNCTION__));
-			return BadAlloc;
-		}
-
 		if (!sna_video_copy_data(sna, video, &frame, buf)) {
 			DBG(("%s: failed to copy frame\n", __FUNCTION__));
 			kgem_bo_destroy(&sna->kgem, frame.bo);
commit 35291d2db813f75fedcdca9920a40592acd3cca3
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun May 27 16:54:29 2012 +0100

    sna: Search the inactive bo cache for a mappable upload buffer
    
    See if we have a bo that we can cheaply map to an inplace upload, rather
    than rely on an existing GTT map.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 9a67c38..00ef82d 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -153,21 +153,25 @@ static int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
 
 static bool __kgem_throttle_retire(struct kgem *kgem, unsigned flags)
 {
-	if (flags & CREATE_NO_RETIRE)
+	if (flags & CREATE_NO_RETIRE) {
+		DBG(("%s: not retiring per-request\n", __FUNCTION__));
 		return false;
+	}
 
-	if (!kgem->need_retire)
+	if (!kgem->need_retire) {
+		DBG(("%s: nothing to retire\n", __FUNCTION__));
 		return false;
+	}
 
 	if (kgem_retire(kgem))
 		return true;
 
-	if (!kgem->need_throttle)
+	if (flags & CREATE_NO_THROTTLE || !kgem->need_throttle) {
+		DBG(("%s: not throttling\n", __FUNCTION__));
 		return false;
+	}
 
-	if ((flags & CREATE_NO_THROTTLE) == 0)
-		kgem_throttle(kgem);
-
+	kgem_throttle(kgem);
 	return kgem_retire(kgem);
 }
 
@@ -3707,6 +3711,8 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
 		 * XXX This is especially noticeable on memory constrained
 		 * devices like gen2 or with relatively slow gpu like i3.
 		 */
+		DBG(("%s: searching for an inactive GTT map for upload\n",
+		     __FUNCTION__));
 		old = search_linear_cache(kgem, alloc,
 					  CREATE_EXACT | CREATE_INACTIVE | CREATE_GTT_MAP);
 #if HAVE_I915_GEM_BUFFER_INFO
@@ -3731,6 +3737,13 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
 		if (old == NULL)
 			old = search_linear_cache(kgem, NUM_PAGES(size),
 						  CREATE_EXACT | CREATE_INACTIVE | CREATE_GTT_MAP);
+		if (old == NULL) {
+			old = search_linear_cache(kgem, alloc, CREATE_INACTIVE);
+			if (old && !kgem_bo_is_mappable(kgem, old)) {
+				_kgem_bo_destroy(kgem, old);
+				old = NULL;
+			}
+		}
 		if (old) {
 			DBG(("%s: reusing handle=%d for buffer\n",
 			     __FUNCTION__, old->handle));
commit 36d53ff52b055b2b5fc03aff7b2cab83037d9f42
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun May 27 16:46:42 2012 +0100

    sna: Validate all CRTCs after updating one
    
    Updating one CRTC may cause the kernel to turn off another, so be
    paranoid and run the check in a loop after applying the CRTC set.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index 1f2d085..92614d0 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -295,7 +295,7 @@ struct sna {
 
 Bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna);
 extern void sna_mode_remove_fb(struct sna *sna);
-extern void sna_mode_hotplug(struct sna *sna);
+extern void sna_mode_update(struct sna *sna);
 extern void sna_mode_fini(struct sna *sna);
 
 extern int sna_crtc_id(xf86CrtcPtr crtc);
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 4b142a3..a218d83 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -397,8 +397,8 @@ bool sna_crtc_is_bound(struct sna *sna, xf86CrtcPtr crtc)
 	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
 		return false;
 
-	DBG(("%s: mode valid?=%d, fb attached?=%d\n", __FUNCTION__,
-	     mode.mode_valid, sna->mode.fb_id == mode.fb_id));
+	DBG(("%s: crtc=%d, mode valid?=%d, fb attached?=%d\n", __FUNCTION__,
+	     mode.crtc_id, mode.mode_valid, sna->mode.fb_id == mode.fb_id));
 	return mode.mode_valid && sna->mode.fb_id == mode.fb_id;
 }
 
@@ -469,10 +469,8 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
 			   "failed to set mode: %s\n", strerror(-ret));
 		ret = FALSE;
-	} else {
-		sna_crtc->active = sna_crtc_is_bound(sna, crtc);
+	} else
 		ret = TRUE;
-	}
 
 	if (crtc->scrn->pScreen)
 		xf86_reload_cursors(crtc->scrn->pScreen);
@@ -520,6 +518,7 @@ sna_crtc_restore(struct sna *sna)
 		if (crtc->enabled)
 			sna_crtc_apply(crtc);
 	}
+	sna_mode_update(sna);
 
 	kgem_bo_retire(&sna->kgem, bo);
 	scrn->displayWidth = bo->pitch / sna->mode.cpp;
@@ -742,6 +741,7 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		crtc->mode = saved_mode;
 		return FALSE;
 	}
+	sna_mode_update(sna);
 
 	update_flush_interval(sna);
 	return TRUE;
@@ -1765,6 +1765,7 @@ sna_crtc_resize(ScrnInfoPtr scrn, int width, int height)
 		if (!sna_crtc_apply(crtc))
 			goto fail;
 	}
+	sna_mode_update(sna);
 
 	kgem_bo_retire(&sna->kgem, bo);
 
@@ -2243,7 +2244,7 @@ sna_wait_for_scanline(struct sna *sna,
 	return true;
 }
 
-void sna_mode_hotplug(struct sna *sna)
+void sna_mode_update(struct sna *sna)
 {
 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(sna->scrn);
 	int i;
@@ -2251,9 +2252,10 @@ void sna_mode_hotplug(struct sna *sna)
 	/* Validate CRTC attachments */
 	for (i = 0; i < xf86_config->num_crtc; i++) {
 		xf86CrtcPtr crtc = xf86_config->crtc[i];
-		if (crtc->enabled) {
-			struct sna_crtc *sna_crtc = crtc->driver_private;
+		struct sna_crtc *sna_crtc = crtc->driver_private;
+		if (crtc->enabled)
 			sna_crtc->active = sna_crtc_is_bound(sna, crtc);
-		}
+		else
+			sna_crtc->active = false;
 	}
 }
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index f3f19e1..39e67c4 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -608,7 +608,7 @@ sna_handle_uevents(int fd, void *closure)
 	if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
 	    hotplug && atoi(hotplug) == 1) {
 		DBG(("%s: hotplug event\n", __FUNCTION__));
-		sna_mode_hotplug(sna);
+		sna_mode_update(sna);
 		RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
 	}
 


More information about the xorg-commit mailing list