xf86-video-intel: 3 commits - src/sna/kgem.c src/sna/sna_accel.c src/sna/sna_display.c src/sna/sna_dri.c src/sna/sna_driver.c src/sna/sna.h src/sna/sna_render.c src/sna/sna_video.c

Chris Wilson ickle at kemper.freedesktop.org
Wed Jun 8 11:39:07 PDT 2011


 src/sna/kgem.c        |    1 
 src/sna/sna.h         |   47 +--
 src/sna/sna_accel.c   |    1 
 src/sna/sna_display.c |  374 +++++++++++++++++-------
 src/sna/sna_dri.c     |  756 ++++++++++++++++++++++++++++----------------------
 src/sna/sna_driver.c  |   13 
 src/sna/sna_render.c  |    4 
 src/sna/sna_video.c   |  178 -----------
 8 files changed, 716 insertions(+), 658 deletions(-)

New commits:
commit 68755bc5ff830dc5ed6a34b18a1217b7d1003ce4
Author: Chad Versace <chad at chad-versace.us>
Date:   Wed Jun 8 18:34:02 2011 +0100

    sna/dri: Add support for DRI2BufferStencil and DRI2BufferHiz
    
    Based on Chad's commits 2662db5b and 3daba7e6:
    
    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 a4dd524..3b085b4 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -186,7 +186,32 @@ sna_dri_create_buffer(DrawablePtr drawable, unsigned int attachment,
 		bpp = pixmap->drawable.bitsPerPixel;
 		break;
 
-	default:
+	case DRI2BufferStencil:
+		/*
+		 * The stencil buffer has quirky pitch requirements.  From Vol
+		 * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface
+		 * Pitch":
+		 *    The pitch must be set to 2x the value computed based on
+		 *    width, as the stencil buffer is stored with two rows
+		 *    interleaved.
+		 * To accomplish this, we resort to the nasty hack of doubling
+		 * the drm region's cpp and halving its height.
+		 *
+		 * If we neglect to double the pitch, then
+		 * drm_intel_gem_bo_map_gtt() maps the memory incorrectly.
+		 */
+		bpp = format ? format : drawable->bitsPerPixel;
+		bo = kgem_create_2d(&sna->kgem,
+				    drawable->width,
+				    drawable->height/2, 2*bpp,
+				    I915_TILING_Y,
+				    CREATE_EXACT);
+		break;
+
+	case DRI2BufferDepth:
+	case DRI2BufferDepthStencil:
+	case DRI2BufferHiz:
+	case DRI2BufferAccum:
 		bpp = format ? format : drawable->bitsPerPixel,
 		bo = kgem_create_2d(&sna->kgem,
 				    drawable->width, drawable->height, bpp,
@@ -194,6 +219,9 @@ sna_dri_create_buffer(DrawablePtr drawable, unsigned int attachment,
 				    I915_TILING_Y,
 				    CREATE_EXACT);
 		break;
+
+	default:
+		break;
 	}
 	if (bo == NULL)
 		goto err;
commit 0030c3aab6172cdb83ca8f1b7b07c7db5915990d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jun 8 18:31:12 2011 +0100

    sna/dri: Drop support for old dri2 versions with incompatible ABI
    
    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 c0bb809..a4dd524 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -66,6 +66,10 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #include "dri2.h"
 
+#if DRI2INFOREC_VERSION < 2
+#error DRI2 version supported by the Xserver is too old
+#endif
+
 #if DEBUG_DRI
 #undef DBG
 #define DBG(x) ErrorF x
@@ -130,123 +134,6 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
 	return priv->gpu_bo;
 }
 
-#if DRI2INFOREC_VERSION < 2
-static DRI2BufferPtr
-sna_dri_create_buffers(DrawablePtr drawable, unsigned int *attachments,
-		      int count)
-{
-	ScreenPtr screen = drawable->pScreen;
-	ScrnInfoPtr scrn = xf86Screens[screen->myNum];
-	struct sna *sna = to_sna(scrn);
-	DRI2BufferPtr buffers;
-	struct sna_dri_private *privates;
-	int depth = -1;
-	int i;
-
-	buffers = calloc(count, sizeof *buffers);
-	if (buffers == NULL)
-		return NULL;
-	privates = calloc(count, sizeof *privates);
-	if (privates == NULL) {
-		free(buffers);
-		return NULL;
-	}
-
-	for (i = 0; i < count; i++) {
-		PixmapPtr pixmap = NULL;
-		if (attachments[i] == DRI2BufferFrontLeft) {
-			pixmap = get_drawable_pixmap(drawable);
-			pixmap->refcnt++;
-			bo = sna_pixmap_set_dri(sna, pixmap);
-		} else if (attachments[i] == DRI2BufferBackLeft) {
-			pixmap = screen->CreatePixmap(screen,
-						      drawable->width, drawable->height, drawable->depth,
-						      0);
-			if (!pixmap)
-				goto unwind;
-
-			bo = sna_pixmap_set_dri(sna, pixmap);
-		} else if (attachments[i] == DRI2BufferStencil && depth != -1) {
-			buffers[i] = buffers[depth];
-			buffers[i].attachment = attachments[i];
-			privates[depth].refcnt++;
-			continue;
-		} else {
-			unsigned int tiling = I915_TILING_X;
-			if (SUPPORTS_YTILING(intel)) {
-				switch (attachment) {
-				case DRI2BufferDepth:
-				case DRI2BufferDepthStencil:
-					tiling = I915_TILING_Y;
-					break;
-				}
-			}
-
-			bo = kgem_create_2d(&intel->kgem,
-					    drawable->width,
-					    drawable->height,
-					    32, tiling);
-			if (!bo)
-				goto unwind;
-		}
-
-		if (attachments[i] == DRI2BufferDepth)
-			depth = i;
-
-		buffers[i].attachment = attachments[i];
-		buffers[i].pitch = pitch;
-		buffers[i].cpp = bpp / 8;
-		buffers[i].driverPrivate = &privates[i];
-		buffers[i].flags = 0;	/* not tiled */
-		buffers[i].name = kgem_bo_flink(&intel->kgem, bo);
-		privates[i].refcnt = 1;
-		privates[i].pixmap = pixmap;
-		privates[i].bo = bo;
-		privates[i].attachment = attachments[i];
-
-		if (buffers[i].name == 0)
-			goto unwind;
-	}
-
-	return buffers;
-
-unwind:
-	do {
-		if (--privates[i].refcnt == 0) {
-			if (privates[i].pixmap)
-				screen->DestroyPixmap(privates[i].pixmap);
-			else
-				gem_close(privates[i].handle);
-		}
-	} while (i--);
-	free(privates);
-	free(buffers);
-	return NULL;
-}
-
-static void
-sna_dri_destroy_buffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
-{
-	ScreenPtr screen = drawable->pScreen;
-	sna_dri_private *private;
-	int i;
-
-	for (i = 0; i < count; i++) {
-		private = buffers[i].driverPrivate;
-		if (private->pixmap)
-			screen->DestroyPixmap(private->pixmap);
-		else
-			kgem_delete(&intel->kgem, private->bo);
-	}
-
-	if (buffers) {
-		free(buffers[0].driverPrivate);
-		free(buffers);
-	}
-}
-
-#else
-
 static DRI2Buffer2Ptr
 sna_dri_create_buffer(DrawablePtr drawable, unsigned int attachment,
 		       unsigned int format)
@@ -358,8 +245,6 @@ static void sna_dri_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
 		free(buffer);
 }
 
-#endif
-
 static void sna_dri_reference_buffer(DRI2Buffer2Ptr buffer)
 {
 	if (buffer) {
@@ -1587,22 +1472,9 @@ Bool sna_dri_open(struct sna *sna, ScreenPtr screen)
 	DBG(("%s: loading dri driver '%s' [gen=%d] for device '%s'\n",
 	     __FUNCTION__, info.driverName, sna->kgem.gen, info.deviceName));
 
-#if DRI2INFOREC_VERSION == 1
-	info.version = 1;
-	info.CreateBuffers = sna_dri_create_buffers;
-	info.DestroyBuffers = sna_dri_destroy_buffers;
-#elif DRI2INFOREC_VERSION == 2
-	/* The ABI between 2 and 3 was broken so we could get rid of
-	 * the multi-buffer alloc functions.  Make sure we indicate the
-	 * right version so DRI2 can reject us if it's version 3 or above. */
-	info.version = 2;
-	info.CreateBuffer = sna_dri_create_buffer;
-	info.DestroyBuffer = sna_dri_destroy_buffer;
-#else
 	info.version = 3;
 	info.CreateBuffer = sna_dri_create_buffer;
 	info.DestroyBuffer = sna_dri_destroy_buffer;
-#endif
 
 	info.CopyRegion = sna_dri_copy_region;
 #if DRI2INFOREC_VERSION >= 4
commit 715d466ad44e82b740f5454c41db944863420596
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jun 8 13:32:59 2011 +0100

    sna/dri: valgrindify
    
    Lots of scary warnings found by valgrind.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 46cd474..979a552 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -199,7 +199,6 @@ gem_madvise(int fd, uint32_t handle, uint32_t state)
 	madv.madv = state;
 	madv.retained = 1;
 	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_MADVISE, &madv);
-	assert(ret == 0);
 
 	return madv.retained;
 	(void)ret;
diff --git a/src/sna/sna.h b/src/sna/sna.h
index e36ef48..ea2422a 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -130,21 +130,6 @@ enum DRI2FrameEventType {
 #define CREATE_PIXMAP_USAGE_SCRATCH_HEADER -1
 #endif
 
-typedef struct _DRI2FrameEvent {
-	XID drawable_id;
-	XID client_id;	/* fake client ID to track client destruction */
-	ClientPtr client;
-	enum DRI2FrameEventType type;
-	int frame;
-	int pipe;
-
-	/* for swaps & flips only */
-	DRI2SwapEventPtr event_complete;
-	void *event_data;
-	DRI2BufferPtr front;
-	DRI2BufferPtr back;
-} DRI2FrameEventRec, *DRI2FrameEventPtr;
-
 #define SNA_CURSOR_X			64
 #define SNA_CURSOR_Y			SNA_CURSOR_X
 
@@ -230,17 +215,16 @@ struct sna {
 		drmModeResPtr mode_res;
 		int cpp;
 
-		drmEventContext event_context;
-		DRI2FrameEventPtr flip_info;
-		int flip_count;
+		struct list outputs;
+		struct list crtcs;
+	} mode;
+
+	struct sna_dri {
 		int flip_pending[2];
 		unsigned int fe_frame;
 		unsigned int fe_tv_sec;
 		unsigned int fe_tv_usec;
-
-		struct list outputs;
-		struct list crtcs;
-	} mode;
+	} dri;
 
 	unsigned int tiling;
 #define SNA_TILING_FB		0x1
@@ -285,16 +269,20 @@ struct sna {
 };
 
 Bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna);
-extern void sna_mode_init(struct sna *sna);
 extern void sna_mode_remove_fb(struct sna *sna);
 extern void sna_mode_fini(struct sna *sna);
 
 extern int sna_crtc_id(xf86CrtcPtr crtc);
 extern int sna_output_dpms_status(xf86OutputPtr output);
 
-extern Bool sna_do_pageflip(struct sna *sna,
+extern int sna_do_pageflip(struct sna *sna,
 			    PixmapPtr pixmap,
-			    DRI2FrameEventPtr flip_info, int ref_crtc_hw_id);
+			    void *data,
+			    int ref_crtc_hw_id,
+			    PixmapPtr *old_front,
+			    uint32_t *old_fb);
+
+void sna_mode_delete_fb(struct sna *sna, PixmapPtr pixmap, uint32_t fb);
 
 static inline struct sna *
 to_sna(ScrnInfoPtr scrn)
@@ -326,12 +314,9 @@ extern xf86CrtcPtr sna_covering_crtc(ScrnInfoPtr scrn, BoxPtr box,
 extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
 				  xf86CrtcPtr crtc, RegionPtr clip);
 
-Bool sna_dri2_open(struct sna *sna, ScreenPtr pScreen);
-void sna_dri2_close(struct sna *sna, ScreenPtr pScreen);
-void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
-			  unsigned int tv_usec, DRI2FrameEventPtr flip_info);
-void sna_dri2_flip_event(unsigned int frame, unsigned int tv_sec,
-			 unsigned int tv_usec, DRI2FrameEventPtr flip_info);
+Bool sna_dri_open(struct sna *sna, ScreenPtr pScreen);
+void sna_dri_wakeup(struct sna *sna);
+void sna_dri_close(struct sna *sna, ScreenPtr pScreen);
 
 extern Bool sna_crtc_on(xf86CrtcPtr crtc);
 int sna_crtc_to_pipe(xf86CrtcPtr crtc);
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index d1f5abf..8e2bc33 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -3203,6 +3203,7 @@ Bool sna_accel_init(ScreenPtr screen, struct sna *sna)
 	list_init(&sna->dirty_pixmaps);
 	list_init(&sna->deferred_free);
 
+	AddGeneralSocket(sna->kgem.fd);
 	sna_accel_install_timers(sna);
 
 	screen->CreateGC = sna_create_gc;
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 847d821..4d11063 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -41,6 +41,7 @@
 #include <X11/Xatom.h>
 
 #include "sna.h"
+#include "sna_reg.h"
 
 #if DEBUG_DISPLAY
 #undef DBG
@@ -353,14 +354,12 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 	struct sna_crtc *sna_crtc = crtc->driver_private;
 	struct sna_mode *mode = &sna->mode;
 	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
-	uint32_t *output_ids;
+	uint32_t output_ids[16];
 	int output_count = 0;
 	int fb_id, x, y;
 	int i, ret = FALSE;
 
-	output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
-	if (!output_ids)
-		return FALSE;
+	assert(xf86_config->num_output < ARRAY_SIZE(output_ids));
 
 	for (i = 0; i < xf86_config->num_output; i++) {
 		xf86OutputPtr output = xf86_config->output[i];
@@ -375,8 +374,10 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 		output_count++;
 	}
 
-	if (!xf86CrtcRotate(crtc))
-		goto done;
+	if (!xf86CrtcRotate(crtc)) {
+		DBG(("%s: failed to rotate crtc\n", __FUNCTION__));
+		return FALSE;
+	}
 
 	crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
 			       crtc->gamma_blue, crtc->gamma_size);
@@ -389,6 +390,15 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 		x = 0;
 		y = 0;
 	}
+
+	DBG(("%s: applying crtc [%d] mode=%dx%d@%d, fb=%d%s update to %d outputs\n",
+	     __FUNCTION__, crtc_id(sna_crtc),
+	     sna_crtc->kmode.hdisplay,
+	     sna_crtc->kmode.vdisplay,
+	     sna_crtc->kmode.clock,
+	     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);
@@ -396,14 +406,14 @@ sna_crtc_apply(xf86CrtcPtr crtc)
 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
 			   "failed to set mode: %s\n", strerror(-ret));
 		ret = FALSE;
-	} else
+	} else {
+		sna_crtc->active = 1;
 		ret = TRUE;
+	}
 
 	if (scrn->pScreen)
 		xf86_reload_cursors(scrn->pScreen);
 
-done:
-	free(output_ids);
 	return ret;
 }
 
@@ -420,14 +430,16 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 	DisplayModeRec saved_mode;
 	int ret = TRUE;
 
-	DBG(("%s(rotation=%d, x=%d, y=%d)\n",
-	     __FUNCTION__, rotation, x, y));
+	DBG(("%s(rotation=%d, x=%d, y=%d, mode=%dx%d@%d)\n",
+	     __FUNCTION__, rotation, x, y,
+	     mode->HDisplay, mode->VDisplay, mode->Clock));
 
 	if (sna_mode->fb_id == 0) {
 		struct kgem_bo *bo = sna_pixmap_pin(sna->front);
 		if (!bo)
 			return FALSE;
 
+		assert(bo->tiling != I915_TILING_Y);
 		ret = drmModeAddFB(sna->kgem.fd,
 				   scrn->virtualX, scrn->virtualY,
 				   scrn->depth, scrn->bitsPerPixel,
@@ -538,6 +550,7 @@ sna_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
 		return NULL;
 	}
 
+	assert(bo->tiling != I915_TILING_Y);
 	if (drmModeAddFB(sna->kgem.fd,
 			 width, height, scrn->depth, scrn->bitsPerPixel,
 			 bo->pitch, bo->handle,
@@ -747,7 +760,7 @@ sna_output_attach_edid(xf86OutputPtr output)
 
 	xf86OutputSetEDID(output, mon);
 
-	if (edid_blob)
+	if (0&&edid_blob)
 		drmModeFreePropertyBlob(edid_blob);
 }
 
@@ -1362,7 +1375,7 @@ sna_visit_set_window_pixmap(WindowPtr window, pointer data)
 }
 
 static void
-sn_redirect_screen_pixmap(ScrnInfoPtr scrn, PixmapPtr old, PixmapPtr new)
+sna_redirect_screen_pixmap(ScrnInfoPtr scrn, PixmapPtr old, PixmapPtr new)
 {
 	ScreenPtr screen = scrn->pScreen;
 	struct sna_visit_set_pixmap_window visit;
@@ -1375,7 +1388,7 @@ sn_redirect_screen_pixmap(ScrnInfoPtr scrn, PixmapPtr old, PixmapPtr new)
 }
 
 static Bool
-sna_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
+sna_crtc_resize(ScrnInfoPtr scrn, int width, int height)
 {
 	struct sna *sna = to_sna(scrn);
 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
@@ -1409,6 +1422,7 @@ sna_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
 	if (!bo)
 		goto fail;
 
+	assert(bo->tiling != I915_TILING_Y);
 	if (drmModeAddFB(sna->kgem.fd, width, height,
 			 scrn->depth, scrn->bitsPerPixel,
 			 bo->pitch, bo->handle,
@@ -1420,6 +1434,9 @@ sna_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
 		goto fail;
 	}
 
+	DBG(("%s: handle %d attached to fb %d\n",
+	     __FUNCTION__, bo->handle, mode->fb_id));
+
 	for (i = 0; i < xf86_config->num_crtc; i++) {
 		xf86CrtcPtr crtc = xf86_config->crtc[i];
 
@@ -1434,7 +1451,9 @@ sna_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
 	scrn->virtualY = height;
 	scrn->displayWidth = bo->pitch / sna->mode.cpp;
 
-	sn_redirect_screen_pixmap(scrn, old_front, sna->front);
+	sna_redirect_screen_pixmap(scrn, old_front, sna->front);
+	assert(scrn->pScreen->GetScreenPixmap(scrn->pScreen) == sna->front);
+	assert(scrn->pScreen->GetWindowPixmap(scrn->pScreen->root) == sna->front);
 
 	if (old_fb_id)
 		drmModeRmFB(sna->kgem.fd, old_fb_id);
@@ -1443,6 +1462,7 @@ sna_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
 	return TRUE;
 
 fail:
+	DBG(("%s: restoring original front pixmap and fb\n", __FUNCTION__));
 	if (old_fb_id != mode->fb_id)
 		drmModeRmFB(sna->kgem.fd, mode->fb_id);
 	mode->fb_id = old_fb_id;
@@ -1453,10 +1473,10 @@ fail:
 	return FALSE;
 }
 
-static Bool do_page_flip(struct sna *sna,
-			 int ref_crtc_hw_id)
+static int do_page_flip(struct sna *sna, void *data, int ref_crtc_hw_id)
 {
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
+	int count = 0;
 	int i;
 
 	/*
@@ -1470,7 +1490,7 @@ static Bool do_page_flip(struct sna *sna,
 	 */
 	for (i = 0; i < config->num_crtc; i++) {
 		struct sna_crtc *crtc = config->crtc[i]->driver_private;
-		uintptr_t data;
+		uintptr_t evdata;
 
 		if (!config->crtc[i]->enabled)
 			continue;
@@ -1478,41 +1498,54 @@ static Bool do_page_flip(struct sna *sna,
 		/* Only the reference crtc will finally deliver its page flip
 		 * completion event. All other crtc's events will be discarded.
 		 */
+		evdata = (uintptr_t)data;
+		evdata |= sna_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id;
 
-		data = (uintptr_t)sna;
-		data |= sna_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id;
-
+		DBG(("%s: crtc %d [ref? %d] --> fb %d\n",
+		     __FUNCTION__, crtc_id(crtc),
+		     sna_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id,
+		     sna->mode.fb_id));
 		if (drmModePageFlip(sna->kgem.fd,
 				    crtc_id(crtc),
 				    sna->mode.fb_id,
 				    DRM_MODE_PAGE_FLIP_EVENT,
-				    (void*)data)) {
+				    (void*)evdata)) {
 			xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
 				   "flip queue failed: %s\n", strerror(errno));
-			return FALSE;
+			continue;
 		}
+
+		count++;
 	}
 
-	return TRUE;
+	return count;
 }
 
-Bool
+int
 sna_do_pageflip(struct sna *sna,
 		PixmapPtr pixmap,
-		DRI2FrameEventPtr flip_info, int ref_crtc_hw_id)
+		void *data,
+		int ref_crtc_hw_id,
+		PixmapPtr *old_front,
+		uint32_t *old_fb)
 {
 	ScrnInfoPtr scrn = sna->scrn;
 	struct sna_mode *mode = &sna->mode;
 	struct kgem_bo *bo = sna_pixmap_pin(pixmap);
-	int old_fb_id;
+	int count;
+
+	assert(pixmap != sna->front);
 
 	if (!bo)
-		return FALSE;
+		return 0;
+
+	*old_fb = mode->fb_id;
+	*old_front = sna->front;
 
 	/*
 	 * Create a new handle for the back buffer
 	 */
-	old_fb_id = mode->fb_id;
+	assert(bo->tiling != I915_TILING_Y);
 	if (drmModeAddFB(sna->kgem.fd, scrn->virtualX, scrn->virtualY,
 			 scrn->depth, scrn->bitsPerPixel,
 			 bo->pitch, bo->handle,
@@ -1521,9 +1554,14 @@ sna_do_pageflip(struct sna *sna,
 		       __FUNCTION__,
 		       scrn->virtualX, scrn->virtualY,
 		       scrn->depth, scrn->bitsPerPixel, bo->pitch);
-		return FALSE;
+		return 0;
 	}
 
+	DBG(("%s: handle %d attached to fb %d\n",
+	     __FUNCTION__, bo->handle, mode->fb_id));
+
+	if (kgem_bo_is_dirty(bo))
+		kgem_emit_flush(&sna->kgem);
 	kgem_submit(&sna->kgem);
 
 	/*
@@ -1535,83 +1573,32 @@ sna_do_pageflip(struct sna *sna,
 	 * Also, flips queued on disabled or incorrectly configured displays
 	 * may never complete; this is a configuration error.
 	 */
-	mode->fe_frame = 0;
-	mode->fe_tv_sec = 0;
-	mode->fe_tv_usec = 0;
-
-	mode->flip_info = flip_info;
-	mode->flip_count++;
-
-	if (do_page_flip(sna, ref_crtc_hw_id)) {
-		PixmapPtr old_front = sna->front;
-
+	count = do_page_flip(sna, data, ref_crtc_hw_id);
+	if (count > 0) {
 		sna->front = pixmap;
 		pixmap->refcnt++;
-		sn_redirect_screen_pixmap(scrn, old_front, sna->front);
+		sna_redirect_screen_pixmap(scrn, *old_front, sna->front);
 		scrn->displayWidth = bo->pitch / sna->mode.cpp;
-
-		drmModeRmFB(sna->kgem.fd, old_fb_id);
-		scrn->pScreen->DestroyPixmap(old_front);
-		return TRUE;
 	} else {
 		drmModeRmFB(sna->kgem.fd, mode->fb_id);
-		mode->fb_id = old_fb_id;
-		return FALSE;
+		mode->fb_id = *old_fb;
 	}
-}
 
-static const xf86CrtcConfigFuncsRec sna_xf86crtc_config_funcs = {
-	sna_xf86crtc_resize
-};
-
-static void
-sna_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
-		       unsigned int tv_usec, void *event_data)
-{
-	sna_dri2_frame_event(frame, tv_sec, tv_usec, event_data);
+	return count;
 }
 
-static void
-sna_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
-		      unsigned int tv_usec, void *event_data)
+void sna_mode_delete_fb(struct sna *sna, PixmapPtr pixmap, uint32_t fb)
 {
-	struct sna *sna = (struct sna *)((uintptr_t)event_data & ~1);
-	struct sna_mode *mode = &sna->mode;
-
-	/* Is this the event whose info shall be delivered to higher level? */
-	if ((uintptr_t)event_data & 1) {
-		/* Yes: Cache msc, ust for later delivery. */
-		mode->fe_frame = frame;
-		mode->fe_tv_sec = tv_sec;
-		mode->fe_tv_usec = tv_usec;
-	}
-
-	/* Last crtc completed flip? */
-	if (--mode->flip_count > 0)
-		return;
+	if (fb)
+		drmModeRmFB(sna->kgem.fd, fb);
 
-	if (mode->flip_info == NULL)
-		return;
-
-	/* Deliver cached msc, ust from reference crtc to flip event handler */
-	sna_dri2_flip_event(mode->fe_frame, mode->fe_tv_sec,
-			    mode->fe_tv_usec, mode->flip_info);
+	if (pixmap)
+		pixmap->drawable.pScreen->DestroyPixmap(pixmap);
 }
 
-static void
-drm_wakeup_handler(pointer data, int err, pointer p)
-{
-	struct sna *sna;
-	fd_set *read_mask;
-
-	if (data == NULL || err < 0)
-		return;
-
-	sna = data;
-	read_mask = p;
-	if (FD_ISSET(sna->kgem.fd, read_mask))
-		drmHandleEvent(sna->kgem.fd, &sna->mode.event_context);
-}
+static const xf86CrtcConfigFuncsRec sna_crtc_config_funcs = {
+	sna_crtc_resize
+};
 
 Bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
 {
@@ -1621,7 +1608,7 @@ Bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
 	list_init(&mode->crtcs);
 	list_init(&mode->outputs);
 
-	xf86CrtcConfigInit(scrn, &sna_xf86crtc_config_funcs);
+	xf86CrtcConfigInit(scrn, &sna_crtc_config_funcs);
 
 	mode->mode_res = drmModeGetResources(sna->kgem.fd);
 	if (!mode->mode_res) {
@@ -1642,29 +1629,10 @@ Bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
 
 	xf86InitialConfiguration(scrn, TRUE);
 
-	mode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
-	mode->event_context.vblank_handler = sna_vblank_handler;
-	mode->event_context.page_flip_handler = sna_page_flip_handler;
-
 	return TRUE;
 }
 
 void
-sna_mode_init(struct sna *sna)
-{
-	struct sna_mode *mode = &sna->mode;
-
-	/* We need to re-register the mode->fd for the synchronisation
-	 * feedback on every server generation, so perform the
-	 * registration within ScreenInit and not PreInit.
-	 */
-	mode->flip_count = 0;
-	AddGeneralSocket(sna->kgem.fd);
-	RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
-				       drm_wakeup_handler, sna);
-}
-
-void
 sna_mode_remove_fb(struct sna *sna)
 {
 	struct sna_mode *mode = &sna->mode;
@@ -1701,3 +1669,181 @@ sna_mode_fini(struct sna *sna)
 
 	/* mode->shadow_fb_id should have been destroyed already */
 }
+
+static void sna_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
+{
+	if (crtc->enabled) {
+		crtc_box->x1 = crtc->x;
+		crtc_box->x2 =
+		    crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
+		crtc_box->y1 = crtc->y;
+		crtc_box->y2 =
+		    crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
+	} else
+		crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
+}
+
+static void sna_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
+{
+	dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
+	dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
+	dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
+	dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
+	if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
+		dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
+}
+
+static int sna_box_area(BoxPtr box)
+{
+	return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1);
+}
+
+/*
+ * Return the crtc covering 'box'. If two crtcs cover a portion of
+ * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
+ * with greater coverage
+ */
+xf86CrtcPtr
+sna_covering_crtc(ScrnInfoPtr scrn,
+		  BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret)
+{
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+	xf86CrtcPtr crtc, best_crtc;
+	int coverage, best_coverage;
+	int c;
+	BoxRec crtc_box, cover_box;
+
+	DBG(("%s for box=(%d, %d), (%d, %d)\n",
+	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
+
+	best_crtc = NULL;
+	best_coverage = 0;
+	crtc_box_ret->x1 = 0;
+	crtc_box_ret->x2 = 0;
+	crtc_box_ret->y1 = 0;
+	crtc_box_ret->y2 = 0;
+	for (c = 0; c < xf86_config->num_crtc; c++) {
+		crtc = xf86_config->crtc[c];
+
+		/* If the CRTC is off, treat it as not covering */
+		if (!sna_crtc_on(crtc)) {
+			DBG(("%s: crtc %d off, skipping\n", __FUNCTION__, c));
+			continue;
+		}
+
+		sna_crtc_box(crtc, &crtc_box);
+		sna_box_intersect(&cover_box, &crtc_box, box);
+		coverage = sna_box_area(&cover_box);
+		if (coverage && crtc == desired) {
+			DBG(("%s: box is on desired crtc [%p]\n",
+			     __FUNCTION__, crtc));
+			*crtc_box_ret = crtc_box;
+			return crtc;
+		}
+		if (coverage > best_coverage) {
+			*crtc_box_ret = crtc_box;
+			best_crtc = crtc;
+			best_coverage = coverage;
+		}
+	}
+	DBG(("%s: best crtc = %p\n", __FUNCTION__, best_crtc));
+	return best_crtc;
+}
+
+bool
+sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
+		      xf86CrtcPtr crtc, RegionPtr clip)
+{
+	pixman_box16_t box, crtc_box;
+	int pipe, event;
+	Bool full_height;
+	int y1, y2;
+	uint32_t *b;
+
+	/* XXX no wait for scanline support on SNB? */
+	if (sna->kgem.gen >= 60)
+		return false;
+
+	if (!pixmap_is_scanout(pixmap))
+		return false;
+
+	if (crtc == NULL) {
+		if (clip) {
+			crtc_box = *REGION_EXTENTS(NULL, clip);
+		} else {
+			crtc_box.x1 = 0; /* XXX drawable offsets? */
+			crtc_box.y1 = 0;
+			crtc_box.x2 = pixmap->drawable.width;
+			crtc_box.y2 = pixmap->drawable.height;
+		}
+		crtc = sna_covering_crtc(sna->scrn, &crtc_box, NULL, &crtc_box);
+	}
+
+	if (crtc == NULL)
+		return false;
+
+	if (clip) {
+		box = *REGION_EXTENTS(unused, clip);
+
+		if (crtc->transform_in_use)
+			pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
+
+		/* We could presume the clip was correctly computed... */
+		sna_crtc_box(crtc, &crtc_box);
+		sna_box_intersect(&box, &crtc_box, &box);
+
+		/*
+		 * Make sure we don't wait for a scanline that will
+		 * never occur
+		 */
+		y1 = (crtc_box.y1 <= box.y1) ? box.y1 - crtc_box.y1 : 0;
+		y2 = (box.y2 <= crtc_box.y2) ?
+			box.y2 - crtc_box.y1 : crtc_box.y2 - crtc_box.y1;
+		if (y2 <= y1)
+			return false;
+
+		full_height = FALSE;
+		if (y1 == 0 && y2 == (crtc_box.y2 - crtc_box.y1))
+			full_height = TRUE;
+	} else {
+		sna_crtc_box(crtc, &crtc_box);
+		y1 = crtc_box.y1;
+		y2 = crtc_box.y2;
+		full_height = TRUE;
+	}
+
+	/*
+	 * Pre-965 doesn't have SVBLANK, so we need a bit
+	 * of extra time for the blitter to start up and
+	 * do its job for a full height blit
+	 */
+	if (sna_crtc_to_pipe(crtc) == 0) {
+		pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
+		event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
+		if (full_height)
+			event = MI_WAIT_FOR_PIPEA_SVBLANK;
+	} else {
+		pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
+		event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
+		if (full_height)
+			event = MI_WAIT_FOR_PIPEB_SVBLANK;
+	}
+
+	if (crtc->mode.Flags & V_INTERLACE) {
+		/* DSL count field lines */
+		y1 /= 2;
+		y2 /= 2;
+	}
+
+	b = kgem_get_batch(&sna->kgem, 5);
+	/* The documentation says that the LOAD_SCAN_LINES command
+	 * always comes in pairs. Don't ask me why. */
+	b[0] = MI_LOAD_SCAN_LINES_INCL | pipe;
+	b[1] = (y1 << 16) | (y2-1);
+	b[2] = MI_LOAD_SCAN_LINES_INCL | pipe;
+	b[3] = (y1 << 16) | (y2-1);
+	b[4] = MI_WAIT_FOR_EVENT | event;
+	kgem_advance_batch(&sna->kgem, 5);
+	return true;
+}
+
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index ea84fb2..c0bb809 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -69,15 +69,43 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #if DEBUG_DRI
 #undef DBG
 #define DBG(x) ErrorF x
+#else
+#define NDEBUG 1
 #endif
 
-struct sna_dri2_private {
+struct sna_dri_private {
 	int refcnt;
 	PixmapPtr pixmap;
 	struct kgem_bo *bo;
 	unsigned int attachment;
 };
 
+struct sna_dri_frame_event {
+	struct sna *sna;
+	XID drawable_id;
+	XID client_id;	/* fake client ID to track client destruction */
+	ClientPtr client;
+	enum DRI2FrameEventType type;
+	int frame;
+	int pipe;
+	int count;
+
+	/* for swaps & flips only */
+	DRI2SwapEventPtr event_complete;
+	void *event_data;
+	DRI2BufferPtr front;
+	DRI2BufferPtr back;
+
+	PixmapPtr old_front;
+	uint32_t old_fb;
+};
+
+static struct sna_dri_frame_event *
+to_frame_event(void *data)
+{
+	 return (struct sna_dri_frame_event *)((uintptr_t)data & ~1);
+}
+
 static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
 					  PixmapPtr pixmap)
 {
@@ -104,14 +132,14 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
 
 #if DRI2INFOREC_VERSION < 2
 static DRI2BufferPtr
-sna_dri2_create_buffers(DrawablePtr drawable, unsigned int *attachments,
+sna_dri_create_buffers(DrawablePtr drawable, unsigned int *attachments,
 		      int count)
 {
 	ScreenPtr screen = drawable->pScreen;
 	ScrnInfoPtr scrn = xf86Screens[screen->myNum];
 	struct sna *sna = to_sna(scrn);
 	DRI2BufferPtr buffers;
-	struct sna_dri2_private *privates;
+	struct sna_dri_private *privates;
 	int depth = -1;
 	int i;
 
@@ -197,10 +225,10 @@ unwind:
 }
 
 static void
-sna_dri2_destroy_buffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
+sna_dri_destroy_buffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
 {
 	ScreenPtr screen = drawable->pScreen;
-	sna_dri2_private *private;
+	sna_dri_private *private;
 	int i;
 
 	for (i = 0; i < count; i++) {
@@ -220,25 +248,25 @@ sna_dri2_destroy_buffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
 #else
 
 static DRI2Buffer2Ptr
-sna_dri2_create_buffer(DrawablePtr drawable, unsigned int attachment,
+sna_dri_create_buffer(DrawablePtr drawable, unsigned int attachment,
 		       unsigned int format)
 {
 	ScreenPtr screen = drawable->pScreen;
 	ScrnInfoPtr scrn = xf86Screens[screen->myNum];
 	struct sna *sna = to_sna(scrn);
 	DRI2Buffer2Ptr buffer;
-	struct sna_dri2_private *private;
+	struct sna_dri_private *private;
 	PixmapPtr pixmap;
 	struct kgem_bo *bo;
 	int bpp, usage;
 
-	DBG(("%s(attachment=%d, format=%d)\n",
-	     __FUNCTION__, attachment, format));
+	DBG(("%s(attachment=%d, format=%d, drawable=%dx%d)\n",
+	     __FUNCTION__, attachment, format,drawable->width,drawable->height));
 
 	buffer = calloc(1, sizeof *buffer + sizeof *private);
 	if (buffer == NULL)
 		return NULL;
-	private = (struct sna_dri2_private *)(buffer + 1);
+	private = (struct sna_dri_private *)(buffer + 1);
 
 	pixmap = NULL;
 	usage = CREATE_PIXMAP_USAGE_SCRATCH;
@@ -248,14 +276,17 @@ sna_dri2_create_buffer(DrawablePtr drawable, unsigned int attachment,
 		pixmap->refcnt++;
 		bo = sna_pixmap_set_dri(sna, pixmap);
 		bpp = pixmap->drawable.bitsPerPixel;
+		DBG(("%s: attaching to front buffer %dx%d\n",
+		     __FUNCTION__,
+		     pixmap->drawable.width, pixmap->drawable.height));
 		break;
 
-	case DRI2BufferFakeFrontLeft:
-	case DRI2BufferFakeFrontRight:
-		usage = 0;
-	case DRI2BufferFrontRight:
 	case DRI2BufferBackLeft:
 	case DRI2BufferBackRight:
+	case DRI2BufferFrontRight:
+		usage = 0;
+	case DRI2BufferFakeFrontLeft:
+	case DRI2BufferFakeFrontRight:
 		pixmap = screen->CreatePixmap(screen,
 					      drawable->width,
 					      drawable->height,
@@ -308,10 +339,10 @@ err:
 	return NULL;
 }
 
-static void sna_dri2_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
+static void sna_dri_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
 {
 	if (buffer && buffer->driverPrivate) {
-		struct sna_dri2_private *private = buffer->driverPrivate;
+		struct sna_dri_private *private = buffer->driverPrivate;
 		if (--private->refcnt == 0) {
 			if (private->pixmap) {
 				ScreenPtr screen = private->pixmap->drawable.pScreen;
@@ -329,10 +360,10 @@ static void sna_dri2_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
 
 #endif
 
-static void sna_dri2_reference_buffer(DRI2Buffer2Ptr buffer)
+static void sna_dri_reference_buffer(DRI2Buffer2Ptr buffer)
 {
 	if (buffer) {
-		struct sna_dri2_private *private = buffer->driverPrivate;
+		struct sna_dri_private *private = buffer->driverPrivate;
 		private->refcnt++;
 	}
 }
@@ -396,12 +427,12 @@ static void damage(DrawablePtr drawable, RegionPtr region)
 }
 
 static void
-sna_dri2_copy_region(DrawablePtr drawable, RegionPtr region,
+sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
 		     DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
 {
 	struct sna *sna = to_sna_from_drawable(drawable);
-	struct sna_dri2_private *srcPrivate = sourceBuffer->driverPrivate;
-	struct sna_dri2_private *dstPrivate = destBuffer->driverPrivate;
+	struct sna_dri_private *srcPrivate = sourceBuffer->driverPrivate;
+	struct sna_dri_private *dstPrivate = destBuffer->driverPrivate;
 	ScreenPtr screen = drawable->pScreen;
 	DrawablePtr src = (srcPrivate->attachment == DRI2BufferFrontLeft)
 		? drawable : &srcPrivate->pixmap->drawable;
@@ -464,13 +495,16 @@ sna_dri2_copy_region(DrawablePtr drawable, RegionPtr region,
 
 
 static int
-sna_dri2_get_pipe(DrawablePtr pDraw)
+sna_dri_get_pipe(DrawablePtr pDraw)
 {
 	ScreenPtr pScreen = pDraw->pScreen;
 	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
 	BoxRec box, crtcbox;
 	xf86CrtcPtr crtc;
-	int pipe = -1;
+	int pipe;
+
+	if (pDraw->type == DRAWABLE_PIXMAP)
+		return -1;
 
 	box.x1 = pDraw->x;
 	box.y1 = pDraw->y;
@@ -480,6 +514,7 @@ sna_dri2_get_pipe(DrawablePtr pDraw)
 	crtc = sna_covering_crtc(pScrn, &box, NULL, &crtcbox);
 
 	/* Make sure the CRTC is valid and this is the real front buffer */
+	pipe = -1;
 	if (crtc != NULL && !crtc->rotatedData)
 		pipe = sna_crtc_to_pipe(crtc);
 
@@ -495,9 +530,9 @@ sna_dri2_get_pipe(DrawablePtr pDraw)
 static RESTYPE frame_event_client_type, frame_event_drawable_type;
 
 static int
-sna_dri2_frame_event_client_gone(void *data, XID id)
+sna_dri_frame_event_client_gone(void *data, XID id)
 {
-	DRI2FrameEventPtr frame_event = data;
+	struct sna_dri_frame_event *frame_event = data;
 
 	frame_event->client = NULL;
 	frame_event->client_id = None;
@@ -505,25 +540,25 @@ sna_dri2_frame_event_client_gone(void *data, XID id)
 }
 
 static int
-sna_dri2_frame_event_drawable_gone(void *data, XID id)
+sna_dri_frame_event_drawable_gone(void *data, XID id)
 {
-	DRI2FrameEventPtr frame_event = data;
+	struct sna_dri_frame_event *frame_event = data;
 
 	frame_event->drawable_id = None;
 	return Success;
 }
 
 static Bool
-sna_dri2_register_frame_event_resource_types(void)
+sna_dri_register_frame_event_resource_types(void)
 {
 	frame_event_client_type =
-		CreateNewResourceType(sna_dri2_frame_event_client_gone,
+		CreateNewResourceType(sna_dri_frame_event_client_gone,
 				      "Frame Event Client");
 	if (!frame_event_client_type)
 		return FALSE;
 
 	frame_event_drawable_type =
-		CreateNewResourceType(sna_dri2_frame_event_drawable_gone,
+		CreateNewResourceType(sna_dri_frame_event_drawable_gone,
 				      "Frame Event Drawable");
 	if (!frame_event_drawable_type)
 		return FALSE;
@@ -537,7 +572,7 @@ sna_dri2_register_frame_event_resource_types(void)
  * client exits while the swap is pending
  */
 static Bool
-sna_dri2_add_frame_event(DRI2FrameEventPtr frame_event)
+sna_dri_add_frame_event(struct sna_dri_frame_event *frame_event)
 {
 	frame_event->client_id = FakeClientID(frame_event->client->index);
 
@@ -559,7 +594,7 @@ sna_dri2_add_frame_event(DRI2FrameEventPtr frame_event)
 }
 
 static void
-sna_dri2_del_frame_event(DRI2FrameEventPtr frame_event)
+sna_dri_del_frame_event(struct sna_dri_frame_event *frame_event)
 {
 	if (frame_event->client_id)
 		FreeResourceByType(frame_event->client_id,
@@ -573,59 +608,17 @@ sna_dri2_del_frame_event(DRI2FrameEventPtr frame_event)
 }
 
 static void
-sna_dri2_exchange_buffers(DrawablePtr draw,
+sna_dri_exchange_buffers(DrawablePtr draw,
 			  DRI2BufferPtr front, DRI2BufferPtr back)
 {
-	struct sna_dri2_private *front_priv, *back_priv;
-	struct sna_pixmap *front_sna, *back_sna;
-	struct kgem_bo *bo;
 	int tmp;
 
 	DBG(("%s()\n", __FUNCTION__));
 
-	front_priv = front->driverPrivate;
-	back_priv = back->driverPrivate;
-
-	front_sna = sna_pixmap(front_priv->pixmap);
-	back_sna = sna_pixmap(back_priv->pixmap);
-
-	/* Force a copy/readback for the next CPU access */
-	if (!front_sna->gpu_only) {
-		sna_damage_all(&front_sna->gpu_damage,
-			       front_priv->pixmap->drawable.width,
-			       front_priv->pixmap->drawable.height);
-		sna_damage_destroy(&front_sna->cpu_damage);
-	}
-	if (front_sna->mapped) {
-		munmap(front_priv->pixmap->devPrivate.ptr,
-		       front_sna->gpu_bo->size);
-		front_sna->mapped = false;
-	}
-	if (!back_sna->gpu_only) {
-		sna_damage_all(&back_sna->gpu_damage,
-			       back_priv->pixmap->drawable.width,
-			       back_priv->pixmap->drawable.height);
-		sna_damage_destroy(&back_sna->cpu_damage);
-	}
-	if (back_sna->mapped) {
-		munmap(back_priv->pixmap->devPrivate.ptr,
-		       back_sna->gpu_bo->size);
-		back_sna->mapped = false;
-	}
-
 	/* Swap BO names so DRI works */
 	tmp = front->name;
 	front->name = back->name;
 	back->name = tmp;
-
-	/* and swap bo so future flips work */
-	bo = front_priv->bo;
-	front_priv->bo = back_priv->bo;
-	back_priv->bo = bo;
-
-	bo = front_sna->gpu_bo;
-	front_sna->gpu_bo = back_sna->gpu_bo;
-	back_sna->gpu_bo = bo;
 }
 
 /*
@@ -633,56 +626,65 @@ sna_dri2_exchange_buffers(DrawablePtr draw,
  * flipping buffers as necessary.
  */
 static Bool
-sna_dri2_schedule_flip(struct sna *sna,
-		       ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
-		       DRI2BufferPtr back, DRI2SwapEventPtr func, void *data,
-		       unsigned int target_msc)
+sna_dri_schedule_flip(struct sna *sna,
+		      ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
+		      DRI2BufferPtr back, DRI2SwapEventPtr func, void *data,
+		      unsigned int target_msc)
 {
-	struct sna_dri2_private *back_priv;
-	DRI2FrameEventPtr flip_info;
+	struct sna_dri *dri = &sna->dri;
+	struct sna_dri_private *back_priv;
+	struct sna_dri_frame_event *info;
 
 	/* Main crtc for this drawable shall finally deliver pageflip event. */
-	int ref_crtc_hw_id = sna_dri2_get_pipe(draw);
+	int ref_crtc_hw_id = sna_dri_get_pipe(draw);
 
 	DBG(("%s()\n", __FUNCTION__));
 
-	flip_info = calloc(1, sizeof(DRI2FrameEventRec));
-	if (!flip_info)
+	info = calloc(1, sizeof(struct sna_dri_frame_event));
+	if (!info)
 		return FALSE;
 
-	flip_info->drawable_id = draw->id;
-	flip_info->client = client;
-	flip_info->type = DRI2_SWAP;
-	flip_info->event_complete = func;
-	flip_info->event_data = data;
-	flip_info->frame = target_msc;
+	info->sna = sna;
+	info->drawable_id = draw->id;
+	info->client = client;
+	info->type = DRI2_SWAP;
+	info->event_complete = func;
+	info->event_data = data;
+	info->frame = target_msc;
 
-	if (!sna_dri2_add_frame_event(flip_info)) {
-		free(flip_info);
+	if (!sna_dri_add_frame_event(info)) {
+		free(info);
 		return FALSE;
 	}
 
+	dri->fe_frame = 0;
+	dri->fe_tv_sec = 0;
+	dri->fe_tv_usec = 0;
+
 	/* Page flip the full screen buffer */
 	back_priv = back->driverPrivate;
-	if (sna_do_pageflip(sna,
-			    back_priv->pixmap,
-			    flip_info, ref_crtc_hw_id))
+	info->count = sna_do_pageflip(sna,
+				      back_priv->pixmap,
+				      info, ref_crtc_hw_id,
+				      &info->old_front,
+				      &info->old_fb);
+	if (info->count)
 		return TRUE;
 
-	sna_dri2_del_frame_event(flip_info);
-	free(flip_info);
+	sna_dri_del_frame_event(info);
+	free(info);
 	return FALSE;
 }
 
 static Bool
-can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
+can_exchange(DRI2BufferPtr front,
+	     DRI2BufferPtr back)
 {
-	struct sna_dri2_private *front_priv = front->driverPrivate;
-	struct sna_dri2_private *back_priv = back->driverPrivate;
+	struct sna_dri_private *front_priv = front->driverPrivate;
+	struct sna_dri_private *back_priv = back->driverPrivate;
 	PixmapPtr front_pixmap = front_priv->pixmap;
 	PixmapPtr back_pixmap = back_priv->pixmap;
-	struct sna_pixmap *front_sna = sna_pixmap(front_pixmap);
-	struct sna_pixmap *back_sna = sna_pixmap(back_pixmap);
+	struct sna_pixmap *front_sna, *back_sna;
 
 	if (front_pixmap->drawable.width != back_pixmap->drawable.width) {
 		DBG(("%s -- no, size mismatch: front width=%d, back=%d\n",
@@ -709,6 +711,8 @@ can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
 	}
 
 	/* prevent an implicit tiling mode change */
+	front_sna = sna_pixmap(front_pixmap);
+	back_sna = sna_pixmap(back_pixmap);
 	if (front_sna->gpu_bo->tiling != back_sna->gpu_bo->tiling) {
 		DBG(("%s -- no, tiling mismatch: front %d, back=%d\n",
 		     __FUNCTION__,
@@ -726,9 +730,117 @@ can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
 	return TRUE;
 }
 
-void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
-			  unsigned int tv_usec, DRI2FrameEventPtr swap_info)
+static Bool
+can_flip(struct sna * sna,
+	 DrawablePtr draw,
+	 DRI2BufferPtr front,
+	 DRI2BufferPtr back)
 {
+	struct sna_dri_private *front_priv = front->driverPrivate;
+	struct sna_dri_private *back_priv = back->driverPrivate;
+	struct sna_pixmap *front_sna, *back_sna;
+	WindowPtr win = (WindowPtr)draw;
+	PixmapPtr front_pixmap;
+	PixmapPtr back_pixmap = back_priv->pixmap;
+
+	ScreenPtr screen = draw->pScreen;
+
+	assert(draw->type == DRAWABLE_WINDOW);
+
+	if (front_priv->attachment != DRI2BufferFrontLeft) {
+		DBG(("%s: no, front attachment [%d] is not FrontLeft [%d]\n",
+		     __FUNCTION__,
+		     front_priv->attachment,
+		     DRI2BufferFrontLeft));
+		return FALSE;
+	}
+
+	if (sna->shadow) {
+		DBG(("%s: no, shadow enabled\n", __FUNCTION__));
+		return FALSE;
+	}
+
+	front_pixmap = screen->GetWindowPixmap(win);
+	if (front_pixmap != sna->front) {
+		DBG(("%s: no, window is not on the front buffer\n",
+		     __FUNCTION__));
+		return FALSE;
+	}
+
+	if (!RegionEqual(&win->clipList, &screen->root->winSize)) {
+		DBG(("%s: no, window is clipped: clip region=(%d, %d), (%d, %d), root size=(%d, %d), (%d, %d)\n",
+		     __FUNCTION__,
+		     win->clipList.extents.x1,
+		     win->clipList.extents.y1,
+		     win->clipList.extents.x2,
+		     win->clipList.extents.y2,
+		     screen->root->winSize.extents.x1,
+		     screen->root->winSize.extents.y1,
+		     screen->root->winSize.extents.x2,
+		     screen->root->winSize.extents.y2));
+		return FALSE;
+	}
+
+	if (draw->width != front_pixmap->drawable.width ||
+	    draw->height != front_pixmap->drawable.height) {
+		DBG(("%s: no, window is not full size (%dx%d)!=(%dx%d)\n",
+		     __FUNCTION__,
+		     draw->width, draw->height,
+		     front_pixmap->drawable.width,
+		     front_pixmap->drawable.height));
+		return FALSE;
+	}
+
+	if (front_pixmap->drawable.width != back_pixmap->drawable.width) {
+		DBG(("%s -- no, size mismatch: front width=%d, back=%d\n",
+		     __FUNCTION__,
+		     front_pixmap->drawable.width,
+		     back_pixmap->drawable.width));
+		return FALSE;
+	}
+
+	if (front_pixmap->drawable.height != back_pixmap->drawable.height) {
+		DBG(("%s -- no, size mismatch: front height=%d, back=%d\n",
+		     __FUNCTION__,
+		     front_pixmap->drawable.height,
+		     back_pixmap->drawable.height));
+		return FALSE;
+	}
+
+	if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) {
+		DBG(("%s -- no, depth mismatch: front bpp=%d, back=%d\n",
+		     __FUNCTION__,
+		     front_pixmap->drawable.bitsPerPixel,
+		     back_pixmap->drawable.bitsPerPixel));
+		return FALSE;
+	}
+
+	/* prevent an implicit tiling mode change */
+	front_sna = sna_pixmap(front_pixmap);
+	back_sna  = sna_pixmap(back_pixmap);
+	if (front_sna->gpu_bo->tiling != back_sna->gpu_bo->tiling) {
+		DBG(("%s -- no, tiling mismatch: front %d, back=%d\n",
+		     __FUNCTION__,
+		     front_sna->gpu_bo->tiling,
+		     back_sna->gpu_bo->tiling));
+		return FALSE;
+	}
+
+	if (front_sna->gpu_only != back_sna->gpu_only) {
+		DBG(("%s -- no, mismatch in gpu_only: front %d, back=%d\n",
+		     __FUNCTION__, front_sna->gpu_only, back_sna->gpu_only));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void sna_dri_vblank_handle(int fd,
+				  unsigned int frame, unsigned int tv_sec,
+				  unsigned int tv_usec,
+				  void *data)
+{
+	struct sna_dri_frame_event *swap_info = data;
 	DrawablePtr drawable;
 	ScreenPtr screen;
 	ScrnInfoPtr scrn;
@@ -754,10 +866,9 @@ void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
 	switch (swap_info->type) {
 	case DRI2_FLIP:
 		/* If we can still flip... */
-		if (DRI2CanFlip(drawable) &&
-		    !sna->shadow &&
-		    can_exchange(swap_info->front, swap_info->back) &&
-		    sna_dri2_schedule_flip(sna,
+		if (can_flip(sna, drawable,
+			     swap_info->front, swap_info->back) &&
+		    sna_dri_schedule_flip(sna,
 					   swap_info->client,
 					   drawable,
 					   swap_info->front,
@@ -765,7 +876,7 @@ void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
 					   swap_info->event_complete,
 					   swap_info->event_data,
 					   swap_info->frame)) {
-			sna_dri2_exchange_buffers(drawable,
+			sna_dri_exchange_buffers(drawable,
 						  swap_info->front,
 						  swap_info->back);
 			break;
@@ -776,12 +887,12 @@ void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
 
 		if (DRI2CanExchange(drawable) &&
 		    can_exchange(swap_info->front, swap_info->back)) {
-			sna_dri2_exchange_buffers(drawable,
+			sna_dri_exchange_buffers(drawable,
 						  swap_info->front,
 						  swap_info->back);
 			swap_type = DRI2_EXCHANGE_COMPLETE;
 		} else {
-			sna_dri2_copy_region(drawable, NULL,
+			sna_dri_copy_region(drawable, NULL,
 					     swap_info->front,
 					     swap_info->back);
 			swap_type = DRI2_BLIT_COMPLETE;
@@ -807,81 +918,108 @@ void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
 	}
 
 done:
-	sna_dri2_del_frame_event(swap_info);
-	sna_dri2_destroy_buffer(drawable, swap_info->front);
-	sna_dri2_destroy_buffer(drawable, swap_info->back);
+	sna_dri_del_frame_event(swap_info);
+	sna_dri_destroy_buffer(drawable, swap_info->front);
+	sna_dri_destroy_buffer(drawable, swap_info->back);
 	free(swap_info);
 }
 
-void sna_dri2_flip_event(unsigned int frame, unsigned int tv_sec,
-			 unsigned int tv_usec, DRI2FrameEventPtr flip)
+static void sna_dri_flip_event(struct sna *sna, struct sna_dri_frame_event *flip)
 {
 	DrawablePtr drawable;
-	ScreenPtr screen;
-	ScrnInfoPtr scrn;
 	int status;
 
 	DBG(("%s(frame=%d, tv=%d.%06d, type=%d)\n",
-	     __FUNCTION__, frame, tv_sec, tv_usec, flip->type));
+	     __FUNCTION__,
+	     sna->dri.fe_frame,
+	     sna->dri.fe_tv_sec,
+	     sna->dri.fe_tv_usec,
+	     flip->type));
 
 	if (!flip->drawable_id)
-		status = BadDrawable;
-	else
-		status = dixLookupDrawable(&drawable,
-					   flip->drawable_id,
-					   serverClient,
-					   M_ANY, DixWriteAccess);
-	if (status != Success) {
-		sna_dri2_del_frame_event(flip);
-		free(flip);
 		return;
-	}
 
-	screen = drawable->pScreen;
-	scrn = xf86Screens[screen->myNum];
+	status = dixLookupDrawable(&drawable,
+				   flip->drawable_id,
+				   serverClient,
+				   M_ANY, DixWriteAccess);
+	if (status != Success)
+		return;
 
 	/* We assume our flips arrive in order, so we don't check the frame */
 	switch (flip->type) {
 	case DRI2_SWAP:
+		/* Deliver cached msc, ust from reference crtc */
 		/* Check for too small vblank count of pageflip completion, taking wraparound
 		 * into account. This usually means some defective kms pageflip completion,
 		 * causing wrong (msc, ust) return values and possible visual corruption.
 		 */
-		if ((frame < flip->frame) && (flip->frame - frame < 5)) {
+		if ((sna->dri.fe_frame < flip->frame) &&
+		    (flip->frame - sna->dri.fe_frame < 5)) {
 			static int limit = 5;
 
 			/* XXX we are currently hitting this path with older
 			 * kernels, so make it quieter.
 			 */
 			if (limit) {
-				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+				xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
 					   "%s: Pageflip completion has impossible msc %d < target_msc %d\n",
-					   __func__, frame, flip->frame);
+					   __func__, sna->dri.fe_frame, flip->frame);
 				limit--;
 			}
 
 			/* All-0 values signal timestamping failure. */
-			frame = tv_sec = tv_usec = 0;
+			sna->dri.fe_frame = sna->dri.fe_tv_sec = sna->dri.fe_tv_usec = 0;
 		}
 
 		DBG(("%s: swap complete\n", __FUNCTION__));
-		DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
+		DRI2SwapComplete(flip->client, drawable,
+				 sna->dri.fe_frame,
+				 sna->dri.fe_tv_sec,
+				 sna->dri.fe_tv_usec,
 				 DRI2_FLIP_COMPLETE, flip->client ? flip->event_complete : NULL,
 				 flip->event_data);
 		break;
+
 	case DRI2_ASYNC_SWAP:
-		DBG(("%s: asunc swap flip completed\n", __FUNCTION__));
-		to_sna(scrn)->mode.flip_pending[flip->pipe]--;
+		DBG(("%s: async swap flip completed on pipe %d, pending %d\n",
+		     __FUNCTION__, flip->pipe, sna->dri.flip_pending[flip->pipe]));
+		sna->dri.flip_pending[flip->pipe]--;
 		break;
+
 	default:
-		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
 			   "%s: unknown vblank event received\n", __func__);
 		/* Unknown type */
 		break;
 	}
+}
+
+static void
+sna_dri_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
+			  unsigned int tv_usec, void *data)
+{
+	struct sna_dri_frame_event *info = to_frame_event(data);
+	struct sna_dri *dri = &info->sna->dri;
+
+	DBG(("%s: pending flip_count=%d\n", __FUNCTION__, info->count));
+
+	/* Is this the event whose info shall be delivered to higher level? */
+	if ((uintptr_t)data & 1) {
+		/* Yes: Cache msc, ust for later delivery. */
+		dri->fe_frame = frame;
+		dri->fe_tv_sec = tv_sec;
+		dri->fe_tv_usec = tv_usec;
+	}
+
+	if (--info->count)
+		return;
 
-	sna_dri2_del_frame_event(flip);
-	free(flip);
+	sna_dri_flip_event(info->sna, info);
+
+	sna_mode_delete_fb(info->sna, info->old_front, info->old_fb);
+	sna_dri_del_frame_event(info);
+	free(info);
 }
 
 /*
@@ -905,7 +1043,7 @@ void sna_dri2_flip_event(unsigned int frame, unsigned int tv_sec,
  * can send any swap complete events that have been requested.
  */
 static int
-sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
+sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		       DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
 		       CARD64 remainder, DRI2SwapEventPtr func, void *data)
 {
@@ -913,8 +1051,8 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	ScrnInfoPtr scrn = xf86Screens[screen->myNum];
 	struct sna *sna = to_sna(scrn);
 	drmVBlank vbl;
-	int ret, pipe = sna_dri2_get_pipe(draw), flip = 0;
-	DRI2FrameEventPtr swap_info = NULL;
+	int ret, pipe = sna_dri_get_pipe(draw), flip = 0;
+	struct sna_dri_frame_event *swap_info = NULL;
 	enum DRI2FrameEventType swap_type = DRI2_SWAP;
 	CARD64 current_msc;
 
@@ -930,7 +1068,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	divisor &= 0xffffffff;
 	remainder &= 0xffffffff;
 
-	swap_info = calloc(1, sizeof(DRI2FrameEventRec));
+	swap_info = calloc(1, sizeof(struct sna_dri_frame_event));
 	if (!swap_info)
 		goto blit_fallback;
 
@@ -941,14 +1079,14 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	swap_info->front = front;
 	swap_info->back = back;
 
-	if (!sna_dri2_add_frame_event(swap_info)) {
+	if (!sna_dri_add_frame_event(swap_info)) {
 		free(swap_info);
 		swap_info = NULL;
 		goto blit_fallback;
 	}
 
-	sna_dri2_reference_buffer(front);
-	sna_dri2_reference_buffer(back);
+	sna_dri_reference_buffer(front);
+	sna_dri_reference_buffer(back);
 
 	/* Get current count */
 	vbl.request.type = DRM_VBLANK_RELATIVE;
@@ -966,7 +1104,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	current_msc = vbl.reply.sequence;
 
 	/* Flips need to be submitted one frame before */
-	if (!sna->shadow && DRI2CanFlip(draw) && can_exchange(front, back)) {
+	if (can_flip(sna, draw, front, back)) {
 		DBG(("%s: can flip\n", __FUNCTION__));
 		swap_type = DRI2_FLIP;
 		flip = 1;
@@ -1069,13 +1207,13 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 
 blit_fallback:
 	DBG(("%s -- blit\n", __FUNCTION__));
-	sna_dri2_copy_region(draw, NULL, front, back);
+	sna_dri_copy_region(draw, NULL, front, back);
 
 	DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
 	if (swap_info) {
-		sna_dri2_del_frame_event(swap_info);
-		sna_dri2_destroy_buffer(draw, swap_info->front);
-		sna_dri2_destroy_buffer(draw, swap_info->back);
+		sna_dri_del_frame_event(swap_info);
+		sna_dri_destroy_buffer(draw, swap_info->front);
+		sna_dri_destroy_buffer(draw, swap_info->back);
 		free(swap_info);
 	}
 	*target_msc = 0; /* offscreen, so zero out target vblank count */
@@ -1084,14 +1222,14 @@ blit_fallback:
 
 #if DRI2INFOREC_VERSION >= 6
 static void
-sna_dri2_async_swap(ClientPtr client, DrawablePtr draw,
+sna_dri_async_swap(ClientPtr client, DrawablePtr draw,
 		  DRI2BufferPtr front, DRI2BufferPtr back,
 		  DRI2SwapEventPtr func, void *data)
 {
 	ScreenPtr screen = draw->pScreen;
 	ScrnInfoPtr scrn = xf86Screens[screen->myNum];
 	struct sna *sna = to_sna(scrn);
-	int pipe = sna_dri2_get_pipe(draw);
+	int pipe = sna_dri_get_pipe(draw);
 	int type = DRI2_EXCHANGE_COMPLETE;
 
 	DBG(("%s()\n", __FUNCTION__));
@@ -1100,68 +1238,116 @@ sna_dri2_async_swap(ClientPtr client, DrawablePtr draw,
 	if (pipe == -1)
 		goto exchange;
 
-	if (sna->shadow ||
-	    !DRI2CanFlip(draw) ||
-	    !can_exchange(front, back)) {
-		sna_dri2_copy_region(draw, NULL, front, back);
+	if (!can_flip(sna, draw, front, back)) {
+		/* Do an synchronous copy instead */
+		struct sna_dri_private *front_priv = front->driverPrivate;
+		struct sna_dri_private *back_priv = back->driverPrivate;
+		BoxRec box, *boxes;
+		PixmapPtr dst;
+		int n;
+
+		DBG(("%s: fallback blit: %dx%d\n",
+		     __FUNCTION__, draw->width, draw->height));
+
+		/* XXX clipping */
+		if (draw->type == DRAWABLE_PIXMAP) {
+			box.x1 = box.y1 = 0;
+			box.x2 = draw->width;
+			box.y2 = draw->height;
+
+			dst = front_priv->pixmap;
+			boxes = &box;
+			n = 1;
+		} else {
+			WindowPtr win = (WindowPtr)draw;
+
+			dst = sna->front;
+			boxes = REGION_RECTS(&win->clipList);
+			n = REGION_NUM_RECTS(&win->clipList);
+		}
+
+		sna->render.copy_boxes(sna, GXcopy,
+				       back_priv->pixmap, back_priv->bo, 0, 0,
+				       dst, sna_pixmap_get_bo(dst), 0, 0,
+				       boxes, n);
+
 		DRI2SwapComplete(client, draw, 0, 0, 0,
 				 DRI2_BLIT_COMPLETE, func, data);
 		return;
 	}
 
-	if (!sna->mode.flip_pending[pipe]) {
-		DRI2FrameEventPtr info;
-		struct sna_dri2_private *backPrivate = back->driverPrivate;
-		DrawablePtr src = &backPrivate->pixmap->drawable;
+	if (!sna->dri.flip_pending[pipe]) {
+		struct sna_dri_frame_event *info;
+		struct sna_dri_private *back_priv = back->driverPrivate;
+		struct sna_pixmap *priv;
+		PixmapPtr src = back_priv->pixmap;
 		PixmapPtr copy;
-		GCPtr gc;
+		BoxRec box;
+
+		DBG(("%s: no pending flip on pipe %d, so updating scanout\n",
+		     __FUNCTION__, pipe));
 
 		copy = screen->CreatePixmap(screen,
-					    src->width, src->height, src->depth,
-					    0);
-		if (!copy)
+					    src->drawable.width,
+					    src->drawable.height,
+					    src->drawable.depth,
+					    SNA_CREATE_FB);
+		if (copy == NullPixmap)
 			goto exchange;
 
-		if (!sna_pixmap_force_to_gpu(copy)) {
+		priv = sna_pixmap_force_to_gpu(copy);
+		if (priv == NULL) {
 			screen->DestroyPixmap(copy);
 			goto exchange;
 		}
 
-		/* copy back to new buffer, and schedule flip */
-		gc = GetScratchGC(src->depth, screen);
-		if (!gc) {
+		box.x1 = box.y1 = 0;
+		box.x2 = src->drawable.width;
+		box.y2 = src->drawable.height;
+		if (!sna->render.copy_boxes(sna, GXcopy,
+					    src, back_priv->bo, 0, 0,
+					    copy, priv->gpu_bo, 0, 0,
+					    &box, 1)) {
 			screen->DestroyPixmap(copy);
 			goto exchange;
 		}
-		ValidateGC(src, gc);
-
-		gc->ops->CopyArea(src, &copy->drawable, gc,
-				  0, 0,
-				  draw->width, draw->height,
-				  0, 0);
-		FreeScratchGC(gc);
+		sna_damage_all(&priv->gpu_damage,
+			       src->drawable.width, src->drawable.height);
+		assert(priv->cpu_damage == NULL);
 
-		info = calloc(1, sizeof(DRI2FrameEventRec));
+		info = calloc(1, sizeof(struct sna_dri_frame_event));
 		if (!info) {
 			screen->DestroyPixmap(copy);
 			goto exchange;
 		}
 
+		info->sna = sna;
 		info->drawable_id = draw->id;
 		info->client = client;
 		info->type = DRI2_ASYNC_SWAP;
 		info->pipe = pipe;
 
-		sna->mode.flip_pending[pipe]++;
-		sna_do_pageflip(sna, copy, info,
-				sna_dri2_get_pipe(draw));
+		if (!sna_dri_add_frame_event(info)) {
+			free(info);
+			screen->DestroyPixmap(copy);
+			goto exchange;
+		}
+
+		info->count = sna_do_pageflip(sna, copy, info, pipe,
+					      &info->old_front, &info->old_fb);
 		screen->DestroyPixmap(copy);
 
+		if (info->count == 0) {
+			free(info);
+			goto exchange;
+		}
+
 		type = DRI2_FLIP_COMPLETE;
+		sna->dri.flip_pending[pipe]++;
 	}
 
 exchange:
-	sna_dri2_exchange_buffers(draw, front, back);
+	sna_dri_exchange_buffers(draw, front, back);
 	DRI2SwapComplete(client, draw, 0, 0, 0, type, func, data);
 }
 #endif
@@ -1171,13 +1357,13 @@ exchange:
  * crtc.
  */
 static int
-sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
+sna_dri_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
 {
 	ScreenPtr screen = draw->pScreen;
 	ScrnInfoPtr scrn = xf86Screens[screen->myNum];
 	struct sna *sna = to_sna(scrn);
 	drmVBlank vbl;
-	int ret, pipe = sna_dri2_get_pipe(draw);
+	int ret, pipe = sna_dri_get_pipe(draw);
 
 	DBG(("%s()\n", __FUNCTION__));
 
@@ -1219,15 +1405,15 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
  * we receive it.
  */
 static int
-sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
+sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 			   CARD64 divisor, CARD64 remainder)
 {
 	ScreenPtr screen = draw->pScreen;
 	ScrnInfoPtr scrn = xf86Screens[screen->myNum];
 	struct sna *sna = to_sna(scrn);
-	DRI2FrameEventPtr wait_info;
+	struct sna_dri_frame_event *wait_info;
 	drmVBlank vbl;
-	int ret, pipe = sna_dri2_get_pipe(draw);
+	int ret, pipe = sna_dri_get_pipe(draw);
 	CARD64 current_msc;
 
 	DBG(("%s(target_msc=%llu, divisor=%llu, rem=%llu)\n",
@@ -1246,7 +1432,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
 	if (pipe == -1)
 		goto out_complete;
 
-	wait_info = calloc(1, sizeof(DRI2FrameEventRec));
+	wait_info = calloc(1, sizeof(struct sna_dri_frame_event));
 	if (!wait_info)
 		goto out_complete;
 
@@ -1358,7 +1544,7 @@ out_complete:
 
 static int dri2_server_generation;
 
-Bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
+Bool sna_dri_open(struct sna *sna, ScreenPtr screen)
 {
 	DRI2InfoRec info;
 	int dri2_major = 1;
@@ -1386,7 +1572,7 @@ Bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
 
 	if (serverGeneration != dri2_server_generation) {
 	    dri2_server_generation = serverGeneration;
-	    if (!sna_dri2_register_frame_event_resource_types()) {
+	    if (!sna_dri_register_frame_event_resource_types()) {
 		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
 			   "Cannot register DRI2 frame event resources\n");
 		return FALSE;
@@ -1403,34 +1589,34 @@ Bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
 
 #if DRI2INFOREC_VERSION == 1
 	info.version = 1;
-	info.CreateBuffers = sna_dri2_create_buffers;
-	info.DestroyBuffers = sna_dri2_destroy_buffers;
+	info.CreateBuffers = sna_dri_create_buffers;
+	info.DestroyBuffers = sna_dri_destroy_buffers;
 #elif DRI2INFOREC_VERSION == 2
 	/* The ABI between 2 and 3 was broken so we could get rid of
 	 * the multi-buffer alloc functions.  Make sure we indicate the
 	 * right version so DRI2 can reject us if it's version 3 or above. */
 	info.version = 2;
-	info.CreateBuffer = sna_dri2_create_buffer;
-	info.DestroyBuffer = sna_dri2_destroy_buffer;
+	info.CreateBuffer = sna_dri_create_buffer;
+	info.DestroyBuffer = sna_dri_destroy_buffer;
 #else
 	info.version = 3;
-	info.CreateBuffer = sna_dri2_create_buffer;
-	info.DestroyBuffer = sna_dri2_destroy_buffer;
+	info.CreateBuffer = sna_dri_create_buffer;
+	info.DestroyBuffer = sna_dri_destroy_buffer;
 #endif
 
-	info.CopyRegion = sna_dri2_copy_region;
+	info.CopyRegion = sna_dri_copy_region;
 #if DRI2INFOREC_VERSION >= 4
 	{
 	    info.version = 4;
-	    info.ScheduleSwap = sna_dri2_schedule_swap;
-	    info.GetMSC = sna_dri2_get_msc;
-	    info.ScheduleWaitMSC = sna_dri2_schedule_wait_msc;
+	    info.ScheduleSwap = sna_dri_schedule_swap;
+	    info.GetMSC = sna_dri_get_msc;
+	    info.ScheduleWaitMSC = sna_dri_schedule_wait_msc;
 	    info.numDrivers = 1;
 	    info.driverNames = driverNames;
 	    driverNames[0] = info.driverName;
 #if DRI2INFOREC_VERSION >= 6
 	    info.version = 6;
-	    info.AsyncSwap = sna_dri2_async_swap;
+	    info.AsyncSwap = sna_dri_async_swap;
 #endif
 	}
 #endif
@@ -1438,7 +1624,21 @@ Bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
 	return DRI2ScreenInit(screen, &info);
 }
 
-void sna_dri2_close(struct sna *sna, ScreenPtr screen)
+void
+sna_dri_wakeup(struct sna *sna)
+{
+	drmEventContext ctx;
+
+	DBG(("%s\n", __FUNCTION__));
+
+	ctx.version = DRM_EVENT_CONTEXT_VERSION;
+	ctx.vblank_handler = sna_dri_vblank_handle;
+	ctx.page_flip_handler = sna_dri_page_flip_handler;
+
+	drmHandleEvent(sna->kgem.fd, &ctx);
+}
+
+void sna_dri_close(struct sna *sna, ScreenPtr screen)
 {
 	DBG(("%s()\n", __FUNCTION__));
 	DRI2CloseScreen(screen);
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index bbd1d49..9d8a067 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -561,7 +561,14 @@ sna_wakeup_handler(int i, pointer data, unsigned long result, pointer read_mask)
 	sna->WakeupHandler = screen->WakeupHandler;
 	screen->WakeupHandler = sna_wakeup_handler;
 
+	/* despite all appearances, result is just a signed int */
+	if ((int)result < 0)
+		return;
+
 	sna_accel_wakeup_handler(sna);
+
+	if (FD_ISSET(sna->kgem.fd, (fd_set*)read_mask))
+		sna_dri_wakeup(sna);
 }
 
 #if HAVE_UDEV
@@ -704,7 +711,7 @@ static Bool sna_close_screen(int scrnIndex, ScreenPtr screen)
 	(*screen->CloseScreen) (scrnIndex, screen);
 
 	if (sna->directRenderingOpen) {
-		sna_dri2_close(sna, screen);
+		sna_dri_close(sna, screen);
 		sna->directRenderingOpen = FALSE;
 	}
 
@@ -725,7 +732,7 @@ sna_screen_init(int scrnIndex, ScreenPtr screen, int argc, char **argv)
 	scrn->videoRam = device->regions[2].size / 1024;
 
 #ifdef DRI2
-	sna->directRenderingOpen = sna_dri2_open(sna, screen);
+	sna->directRenderingOpen = sna_dri_open(sna, screen);
 	if (sna->directRenderingOpen)
 		xf86DrvMsg(scrn->scrnIndex, X_INFO,
 			   "direct rendering: DRI2 Enabled\n");
@@ -823,8 +830,6 @@ sna_screen_init(int scrnIndex, ScreenPtr screen, int argc, char **argv)
 	if (serverGeneration == 1)
 		xf86ShowUnusedOptions(scrn->scrnIndex, scrn->options);
 
-	sna_mode_init(sna);
-
 	sna->suspended = FALSE;
 
 #if HAVE_UDEV
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index d7d7e5f..63747ea 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -254,7 +254,7 @@ move_to_gpu(PixmapPtr pixmap, const BoxRec *box)
 	if (w == pixmap->drawable.width || h == pixmap->drawable.height) {
 		DBG(("%s: migrating whole pixmap (%dx%d) for source\n",
 		     __FUNCTION__,
-		     pixmap->drawble->width,
+		     pixmap->drawable.width,
 		     pixmap->drawable.height));
 		return TRUE;
 	}
@@ -303,7 +303,7 @@ texture_is_cpu(PixmapPtr pixmap, const BoxRec *box)
 {
 	Bool ret = _texture_is_cpu(pixmap, box);
 	ErrorF("%s(pixmap=%p, box=((%d, %d), (%d, %d)) = %d\n",
-	       __FUNCTION__, pixmap, box, ret);
+	       __FUNCTION__, pixmap, box->x1, box->y1, box->x2, box->y2, ret);
 	return ret;
 }
 #else
diff --git a/src/sna/sna_video.c b/src/sna/sna_video.c
index b6cbda2..8839ab7 100644
--- a/src/sna/sna_video.c
+++ b/src/sna/sna_video.c
@@ -514,184 +514,6 @@ sna_video_copy_data(struct sna *sna,
 	return TRUE;
 }
 
-static void sna_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
-{
-	if (crtc->enabled) {
-		crtc_box->x1 = crtc->x;
-		crtc_box->x2 =
-		    crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
-		crtc_box->y1 = crtc->y;
-		crtc_box->y2 =
-		    crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
-	} else
-		crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
-}
-
-static void sna_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
-{
-	dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
-	dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
-	dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
-	dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
-	if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
-		dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
-}
-
-static int sna_box_area(BoxPtr box)
-{
-	return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1);
-}
-
-/*
- * Return the crtc covering 'box'. If two crtcs cover a portion of
- * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
- * with greater coverage
- */
-
-xf86CrtcPtr
-sna_covering_crtc(ScrnInfoPtr scrn,
-		  BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret)
-{
-	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
-	xf86CrtcPtr crtc, best_crtc;
-	int coverage, best_coverage;
-	int c;
-	BoxRec crtc_box, cover_box;
-
-	DBG(("%s for box=(%d, %d), (%d, %d)\n",
-	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
-
-	best_crtc = NULL;
-	best_coverage = 0;
-	crtc_box_ret->x1 = 0;
-	crtc_box_ret->x2 = 0;
-	crtc_box_ret->y1 = 0;
-	crtc_box_ret->y2 = 0;
-	for (c = 0; c < xf86_config->num_crtc; c++) {
-		crtc = xf86_config->crtc[c];
-
-		/* If the CRTC is off, treat it as not covering */
-		if (!sna_crtc_on(crtc)) {
-			DBG(("%s: crtc %d off, skipping\n", __FUNCTION__, c));
-			continue;
-		}
-
-		sna_crtc_box(crtc, &crtc_box);
-		sna_box_intersect(&cover_box, &crtc_box, box);
-		coverage = sna_box_area(&cover_box);
-		if (coverage && crtc == desired) {
-			DBG(("%s: box is on desired crtc [%p]\n",
-			     __FUNCTION__, crtc));
-			*crtc_box_ret = crtc_box;
-			return crtc;
-		}
-		if (coverage > best_coverage) {
-			*crtc_box_ret = crtc_box;
-			best_crtc = crtc;
-			best_coverage = coverage;
-		}
-	}
-	DBG(("%s: best crtc = %p\n", __FUNCTION__, best_crtc));
-	return best_crtc;
-}
-
-bool
-sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
-		      xf86CrtcPtr crtc, RegionPtr clip)
-{
-	pixman_box16_t box, crtc_box;
-	int pipe, event;
-	Bool full_height;
-	int y1, y2;
-	uint32_t *b;
-
-	/* XXX no wait for scanline support on SNB? */
-	if (sna->kgem.gen >= 60)
-		return false;
-
-	if (!pixmap_is_scanout(pixmap))
-		return false;
-
-	if (crtc == NULL) {
-		if (clip) {
-			crtc_box = *REGION_EXTENTS(NULL, clip);
-		} else {
-			crtc_box.x1 = 0; /* XXX drawable offsets? */
-			crtc_box.y1 = 0;
-			crtc_box.x2 = pixmap->drawable.width;
-			crtc_box.y2 = pixmap->drawable.height;
-		}
-		crtc = sna_covering_crtc(sna->scrn, &crtc_box, NULL, &crtc_box);
-	}
-
-	if (crtc == NULL)
-		return false;
-
-	if (clip) {
-		box = *REGION_EXTENTS(unused, clip);
-
-		if (crtc->transform_in_use)
-			pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
-
-		/* We could presume the clip was correctly computed... */
-		sna_crtc_box(crtc, &crtc_box);
-		sna_box_intersect(&box, &crtc_box, &box);
-
-		/*
-		 * Make sure we don't wait for a scanline that will
-		 * never occur
-		 */
-		y1 = (crtc_box.y1 <= box.y1) ? box.y1 - crtc_box.y1 : 0;
-		y2 = (box.y2 <= crtc_box.y2) ?
-			box.y2 - crtc_box.y1 : crtc_box.y2 - crtc_box.y1;
-		if (y2 <= y1)
-			return false;
-
-		full_height = FALSE;
-		if (y1 == 0 && y2 == (crtc_box.y2 - crtc_box.y1))
-			full_height = TRUE;
-	} else {
-		sna_crtc_box(crtc, &crtc_box);
-		y1 = crtc_box.y1;
-		y2 = crtc_box.y2;
-		full_height = TRUE;
-	}
-
-	/*
-	 * Pre-965 doesn't have SVBLANK, so we need a bit
-	 * of extra time for the blitter to start up and
-	 * do its job for a full height blit
-	 */
-	if (sna_crtc_to_pipe(crtc) == 0) {
-		pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
-		event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
-		if (full_height)
-			event = MI_WAIT_FOR_PIPEA_SVBLANK;
-	} else {
-		pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
-		event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
-		if (full_height)
-			event = MI_WAIT_FOR_PIPEB_SVBLANK;
-	}
-
-	if (crtc->mode.Flags & V_INTERLACE) {
-		/* DSL count field lines */
-		y1 /= 2;
-		y2 /= 2;
-	}
-
-	b = kgem_get_batch(&sna->kgem, 5);
-	/* The documentation says that the LOAD_SCAN_LINES command
-	 * always comes in pairs. Don't ask me why. */
-	b[0] = MI_LOAD_SCAN_LINES_INCL | pipe;
-	b[1] = (y1 << 16) | (y2-1);
-	b[2] = MI_LOAD_SCAN_LINES_INCL | pipe;
-	b[3] = (y1 << 16) | (y2-1);
-	b[4] = MI_WAIT_FOR_EVENT | event;
-	kgem_advance_batch(&sna->kgem, 5);
-	return true;
-}
-
 void sna_video_init(struct sna *sna, ScreenPtr screen)
 {
 	XF86VideoAdaptorPtr *adaptors, *newAdaptors;


More information about the xorg-commit mailing list