xf86-video-intel: 8 commits - src/sna/kgem.c src/sna/kgem.h src/sna/sna_accel.c src/sna/sna_display.c src/sna/sna_dri2.c src/sna/sna.h src/sna/sna_render.c src/uxa/intel_display.c src/uxa/intel_driver.c

Chris Wilson ickle at kemper.freedesktop.org
Mon May 26 12:48:31 PDT 2014


 src/sna/kgem.c          |   38 ---
 src/sna/kgem.h          |    1 
 src/sna/sna.h           |    6 
 src/sna/sna_accel.c     |   14 -
 src/sna/sna_display.c   |   35 ++-
 src/sna/sna_dri2.c      |  515 ++++++++++++++++++++++++++----------------------
 src/sna/sna_render.c    |    4 
 src/uxa/intel_display.c |    6 
 src/uxa/intel_driver.c  |    2 
 9 files changed, 332 insertions(+), 289 deletions(-)

New commits:
commit 93b319cf9a355e8400b864046cdb4cfb56b657a0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 23 13:16:50 2014 +0100

    uxa: Silence the compiler over a couple of unused variables
    
    intel_driver.c: In function 'I830LeaveVT':
    intel_driver.c:1085:24: warning: unused variable 'intel' [-Wunused-variable]
      intel_screen_private *intel = intel_get_screen_private(scrn);
                            ^
    intel_driver.c: In function 'I830EnterVT':
    intel_driver.c:1102:24: warning: unused variable 'intel' [-Wunused-variable]
      intel_screen_private *intel = intel_get_screen_private(scrn);
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/uxa/intel_driver.c b/src/uxa/intel_driver.c
index 0a4fe2a..654038c 100644
--- a/src/uxa/intel_driver.c
+++ b/src/uxa/intel_driver.c
@@ -1048,7 +1048,6 @@ static void I830FreeScreen(FREE_SCREEN_ARGS_DECL)
 static void I830LeaveVT(VT_FUNC_ARGS_DECL)
 {
 	SCRN_INFO_PTR(arg);
-	intel_screen_private *intel = intel_get_screen_private(scrn);
 
 	xf86RotateFreeShadow(scrn);
 
@@ -1065,7 +1064,6 @@ static void I830LeaveVT(VT_FUNC_ARGS_DECL)
 static Bool I830EnterVT(VT_FUNC_ARGS_DECL)
 {
 	SCRN_INFO_PTR(arg);
-	intel_screen_private *intel = intel_get_screen_private(scrn);
 
 	if (intel_get_master(scrn)) {
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
commit e6ee0679374f8fc80cb34693f80affe6ea676ddb
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 23 14:29:42 2014 +0100

    uxa: Silence compiler for warnings in Cursor API changes
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/uxa/intel_display.c b/src/uxa/intel_display.c
index 857aa24..46a009e 100644
--- a/src/uxa/intel_display.c
+++ b/src/uxa/intel_display.c
@@ -446,7 +446,7 @@ __intel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
 	return ret;
 }
 
-#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,0)
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2)
 static Bool
 intel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
 {
@@ -656,7 +656,11 @@ static const xf86CrtcFuncsRec intel_crtc_funcs = {
 	.set_cursor_position = intel_crtc_set_cursor_position,
 	.show_cursor = intel_crtc_show_cursor,
 	.hide_cursor = intel_crtc_hide_cursor,
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2)
+	.load_cursor_argb_check = intel_crtc_load_cursor_argb,
+#else
 	.load_cursor_argb = intel_crtc_load_cursor_argb,
+#endif
 	.shadow_create = intel_crtc_shadow_create,
 	.shadow_allocate = intel_crtc_shadow_allocate,
 	.shadow_destroy = intel_crtc_shadow_destroy,
commit 4321e8decd7be9daaa49c6ab4e8bb9bd66faae31
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 23 14:29:42 2014 +0100

    sna: Silence compiler for warnings in Cursor API changes
    
    The API changed again in the RC, so update to keep the compiler quiet.
    At the same time, protect against the ARGB_CURSOR struct changes.
    
    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 8e876fe..2891b74 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -3447,6 +3447,15 @@ static struct sna_cursor *__sna_create_cursor(struct sna *sna, int size)
 	return c;
 }
 
+static uint32_t *get_cursor_argb(CursorPtr c)
+{
+#ifdef ARGB_CURSOR
+	return (uint32_t *)c->bits->argb;
+#else
+	return NULL;
+#endif
+}
+
 static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
 {
 	struct sna_cursor *cursor;
@@ -3475,7 +3484,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
 	       sna->cursor.ref->bits->width,
 	       sna->cursor.ref->bits->height,
 	       sna->cursor.serial,
-	       sna->cursor.ref->bits->argb!=NULL));
+	       get_cursor_argb(c) != NULL));
 
 	rotation = crtc->transform_in_use ? crtc->rotation : RR_Rotate_0;
 
@@ -3506,7 +3515,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
 	height = sna->cursor.ref->bits->height;
 	source = sna->cursor.ref->bits->source;
 	mask = sna->cursor.ref->bits->mask;
-	argb = (uint32_t *)sna->cursor.ref->bits->argb;
+	argb = get_cursor_argb(sna->cursor.ref);
 	pitch = BitmapBytePad(width);
 
 	image = cursor->image;
@@ -3686,7 +3695,7 @@ sna_set_cursor_colors(ScrnInfoPtr scrn, int _bg, int _fg)
 	if (sna->cursor.ref == NULL)
 		return;
 
-	if (sna->cursor.ref->bits->argb)
+	if (get_cursor_argb(sna->cursor.ref))
 		return;
 
 	sna->cursor.serial++;
@@ -3852,19 +3861,20 @@ disable:
 	sigio_unblock(sigio);
 }
 
-#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,0)
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2)
 static Bool
-sna_load_cursor_argb(ScrnInfoPtr scrn, CursorPtr cursor)
+sna_load_cursor_argb2(ScrnInfoPtr scrn, CursorPtr cursor)
 {
 	return TRUE;
 }
 
 static Bool
-sna_load_cursor_image(ScrnInfoPtr scrn, unsigned char *src)
+sna_load_cursor_image2(ScrnInfoPtr scrn, unsigned char *src)
 {
 	return TRUE;
 }
-#else
+#endif
+
 static void
 sna_load_cursor_argb(ScrnInfoPtr scrn, CursorPtr cursor)
 {
@@ -3874,7 +3884,6 @@ static void
 sna_load_cursor_image(ScrnInfoPtr scrn, unsigned char *src)
 {
 }
-#endif
 
 static int __cursor_size(CursorPtr cursor)
 {
@@ -3935,7 +3944,7 @@ sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
 	__DBG(("%s(%dx%d): ARGB?=%d, serial->%d, size->%d\n", __FUNCTION__,
 	       cursor->bits->width,
 	       cursor->bits->height,
-	       cursor->bits->argb!=NULL,
+	       get_cursor_argb(cursor) != NULL,
 	       sna->cursor.serial,
 	       sna->cursor.size));
 
@@ -4031,6 +4040,12 @@ sna_cursors_init(ScreenPtr screen, struct sna *sna)
 	cursor_info->UseHWCursorARGB = sna_use_hw_cursor;
 	cursor_info->LoadCursorARGB = sna_load_cursor_argb;
 #endif
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2)
+	cursor_info->LoadCursorImageCheck = sna_load_cursor_image2;
+#ifdef ARGB_CURSOR
+	cursor_info->LoadCursorARGBCheck = sna_load_cursor_argb2;
+#endif
+#endif
 
 	if (!xf86InitCursor(screen, cursor_info)) {
 		xf86DestroyCursorInfoRec(cursor_info);
commit 2a0dc7ed4961d5bda08bb583a7a6a2cc633b27e4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 26 08:23:45 2014 +0100

    sna/dri2: Move scanout processing from frame event to global
    
    The scanout is a global property, track it as so. The primary benefit to
    this is it strengthens our assertions that we never hand out an active
    scanout for use as a back buffer.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index f88690c..7a1b693 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -315,6 +315,10 @@ struct sna {
 
 #if HAVE_DRI2
 		void *flip_pending;
+		struct {
+			struct kgem_bo *bo;
+			uint32_t name;
+		} scanout[2];
 #endif
 	} dri2;
 
@@ -496,6 +500,7 @@ void sna_dri2_page_flip_handler(struct sna *sna, struct drm_event_vblank *event)
 void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event);
 void sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap);
 void sna_dri2_destroy_window(WindowPtr win);
+void sna_dri2_reset_scanout(struct sna *sna);
 void sna_dri2_close(struct sna *sna, ScreenPtr pScreen);
 #else
 static inline bool sna_dri2_open(struct sna *sna, ScreenPtr pScreen) { return false; }
@@ -503,6 +508,7 @@ static inline void sna_dri2_page_flip_handler(struct sna *sna, struct drm_event_
 static inline void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event) { }
 static inline void sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap) { }
 static inline void sna_dri2_destroy_window(WindowPtr win) { }
+static inline void sna_dri2_reset_scanout(struct sna *sna) { }
 static inline void sna_dri2_close(struct sna *sna, ScreenPtr pScreen) { }
 #endif
 
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index a81ce21..8e876fe 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -4505,6 +4505,8 @@ sna_crtc_config_notify(ScreenPtr screen)
 
 	DBG(("%s\n", __FUNCTION__));
 
+	sna_dri2_reset_scanout(sna);
+
 	sna_mode_update(sna);
 	sna_cursors_reload(sna);
 }
diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 829e5ba..8aef88d 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -112,11 +112,6 @@ struct sna_dri2_frame_event {
 
 	struct sna_dri2_frame_event *chain;
 
-	struct {
-		struct kgem_bo *bo;
-		uint32_t name;
-	} scanout[2];
-
 	struct list cache;
 
 	int mode;
@@ -130,15 +125,15 @@ sna_dri2_get_back(struct sna *sna, struct sna_dri2_frame_event *info)
 
 	DBG(("%s: scanout=(%d, %d), back=%d, cache?=%d\n",
 	     __FUNCTION__,
-	     info->scanout[0].bo ? info->scanout[0].bo->handle : 0,
-	     info->scanout[1].bo ? info->scanout[1].bo->handle : 0,
+	     sna->dri2.scanout[0].bo ? sna->dri2.scanout[0].bo->handle : 0,
+	     sna->dri2.scanout[1].bo ? sna->dri2.scanout[1].bo->handle : 0,
 	     get_private(info->back)->bo->handle,
 	     !list_is_empty(&info->cache)));
 
 	bo = get_private(info->back)->bo;
 	assert(bo->refcnt);
 	assert(bo->flush);
-	if (!(bo == info->scanout[0].bo || bo == info->scanout[1].bo)) {
+	if (!(bo == sna->dri2.scanout[0].bo || bo == sna->dri2.scanout[1].bo)) {
 		DBG(("%s: reuse unattached back\n", __FUNCTION__));
 		return;
 	}
@@ -173,15 +168,15 @@ sna_dri2_get_back(struct sna *sna, struct sna_dri2_frame_event *info)
 		}
 	}
 
-	assert(!(bo == info->scanout[0].bo || bo == info->scanout[1].bo));
+	assert(!(bo == sna->dri2.scanout[0].bo || bo == sna->dri2.scanout[1].bo));
 	assert(name);
 
 	unref(get_private(info->back)->bo);
 	get_private(info->back)->bo = bo;
 	info->back->name = name;
 
-	assert(get_private(info->back)->bo != info->scanout[0].bo);
-	assert(get_private(info->back)->bo != info->scanout[1].bo);
+	assert(get_private(info->back)->bo != sna->dri2.scanout[0].bo);
+	assert(get_private(info->back)->bo != sna->dri2.scanout[1].bo);
 
 	assert(bo->refcnt == 1);
 	assert(bo->flush);
@@ -247,6 +242,9 @@ sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
 			DBG(("%s: replacing back buffer\n", __FUNCTION__));
 			sna_dri2_get_back(to_sna_from_drawable(draw), info);
 		}
+
+		assert(get_private(buffer)->bo != to_sna_from_drawable(draw)->dri2.scanout[0].bo);
+		assert(get_private(buffer)->bo != to_sna_from_drawable(draw)->dri2.scanout[1].bo);
 	}
 }
 
@@ -1192,13 +1190,6 @@ sna_dri2_frame_event_info_free(struct sna *sna,
 	_sna_dri2_destroy_buffer(sna, info->front);
 	_sna_dri2_destroy_buffer(sna, info->back);
 
-	assert(info->scanout[1].bo == NULL);
-
-	if (info->scanout[0].bo) {
-		assert(info->scanout[0].bo->scanout);
-		kgem_bo_destroy(&sna->kgem, info->scanout[0].bo);
-	}
-
 	while (!list_is_empty(&info->cache)) {
 		struct dri_bo *c;
 
@@ -1254,6 +1245,25 @@ void sna_dri2_destroy_window(WindowPtr win)
 	free(priv);
 }
 
+static void
+update_scanout(struct sna *sna, struct sna_dri2_frame_event *info, struct kgem_bo *bo, int name)
+{
+	assert(sna->dri2.scanout[1].bo == NULL);
+	assert(sna->dri2.scanout[0].bo->scanout);
+	assert(sna->dri2.scanout[0].bo->refcnt);
+	sna->dri2.scanout[1] = sna->dri2.scanout[0];
+	sna->dri2.scanout[0].bo = ref(bo);
+	sna->dri2.scanout[0].name = name;
+	assert(sna->dri2.scanout[0].bo->scanout);
+
+	DBG(("%s: pending scanout handle=%d, active scanout handle=%d\n",
+	     __FUNCTION__, sna->dri2.scanout[0].bo->handle, sna->dri2.scanout[1].bo->handle));
+	assert(sna->dri2.scanout[0].bo->handle != sna->dri2.scanout[1].bo->handle);
+
+	assert(sna->dri2.flip_pending == NULL || sna->dri2.flip_pending == info);
+	sna->dri2.flip_pending = info;
+}
+
 static bool
 sna_dri2_page_flip(struct sna *sna, struct sna_dri2_frame_event *info)
 {
@@ -1264,29 +1274,22 @@ sna_dri2_page_flip(struct sna *sna, struct sna_dri2_frame_event *info)
 
 	assert(sna_pixmap_get_buffer(sna->front) == info->front);
 	assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo));
-	assert(info->scanout[0].bo);
-	assert(info->scanout[0].bo->scanout);
-	assert(info->scanout[1].bo == NULL);
+	assert(sna->dri2.scanout[0].bo);
+	assert(sna->dri2.scanout[0].bo->scanout);
+	assert(sna->dri2.scanout[1].bo == NULL);
 	assert(bo->refcnt);
 
 	info->count = sna_page_flip(sna, bo, info, info->pipe);
 	if (!info->count)
 		return false;
 
-	DBG(("%s: mark handle=%d as scanout, swap front (handle=%d, name=%d) and back (handle=%d, name=%d)\n",
+	update_scanout(sna, info, bo, info->back->name);
+
+	DBG(("%s: marked handle=%d as scanout, swap front (handle=%d, name=%d) and back (handle=%d, name=%d)\n",
 	     __FUNCTION__, bo->handle,
 	     get_private(info->front)->bo->handle, info->front->name,
 	     get_private(info->back)->bo->handle, info->back->name));
 
-	info->scanout[1] = info->scanout[0];
-	info->scanout[0].bo = ref(bo);
-	info->scanout[0].name = info->back->name;
-	assert(info->scanout[0].bo->scanout);
-
-	DBG(("%s: pending scanout handle=%d, active scanout handle=%d\n",
-	     __FUNCTION__, info->scanout[0].bo->handle, info->scanout[1].bo->handle));
-	assert(info->scanout[0].bo->handle != info->scanout[1].bo->handle);
-
 	tmp.bo = get_private(info->front)->bo;
 	tmp.name = info->front->name;
 
@@ -1298,8 +1301,6 @@ sna_dri2_page_flip(struct sna *sna, struct sna_dri2_frame_event *info)
 	info->back->name = tmp.name;
 	get_private(info->back)->bo = tmp.bo;
 
-	sna->dri2.flip_pending = info;
-
 	info->queued = true;
 	return true;
 }
@@ -1773,23 +1774,18 @@ sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_frame_event *info)
 	DBG(("%s(mode=%d)\n", __FUNCTION__, info->mode));
 
 	if (info->mode > 0){
+		struct kgem_bo *bo =get_private(info->front)->bo;
+
 		info->type = info->mode;
 
-		if (get_private(info->front)->bo != sna_pixmap(sna->front)->gpu_bo)
+		if (bo != sna_pixmap(sna->front)->gpu_bo)
 			return false;
 
-		info->count = sna_page_flip(sna,
-					    get_private(info->front)->bo,
-					    info, info->pipe);
+		info->count = sna_page_flip(sna, bo, info, info->pipe);
 		if (!info->count)
 			return false;
 
-		assert(info->scanout[0].bo->scanout);
-		info->scanout[1] = info->scanout[0];
-		info->scanout[0].bo = ref(get_private(info->front)->bo);
-		info->scanout[0].name = info->front->name;
-		assert(info->scanout[0].bo->scanout);
-		sna->dri2.flip_pending = info;
+		update_scanout(sna, info, bo, info->front->name);
 	} else {
 		info->type = -info->mode;
 
@@ -1870,18 +1866,18 @@ static void sna_dri2_flip_event(struct sna *sna,
 
 	assert(!sna->mode.shadow_flip);
 
-	if (flip->scanout[1].bo) {
+	if (sna->dri2.scanout[1].bo) {
 		struct dri_bo *c = NULL;
 
 		DBG(("%s: retiring previous scanout handle=%d, name=%d, refcnt=%d (current scanout handle=%d)\n",
 		     __FUNCTION__,
-		     flip->scanout[1].bo->handle,
-		     flip->scanout[1].name,
-		     flip->scanout[1].bo->refcnt,
-		     flip->scanout[0].bo->handle));
+		     sna->dri2.scanout[1].bo->handle,
+		     sna->dri2.scanout[1].name,
+		     sna->dri2.scanout[1].bo->refcnt,
+		     sna->dri2.scanout[0].bo->handle));
 
-		if (flip->scanout[1].bo != flip->scanout[0].bo &&
-		    flip->scanout[1].bo->refcnt == 1) {
+		if (sna->dri2.scanout[1].bo != sna->dri2.scanout[0].bo &&
+		    sna->dri2.scanout[1].bo->refcnt == 1) {
 			DBG(("%s: adding old scanout to flip cache\n", __FUNCTION__));
 			if (!list_is_empty(&flip->cache))
 				c = list_last_entry(&flip->cache, struct dri_bo, link);
@@ -1894,19 +1890,19 @@ static void sna_dri2_flip_event(struct sna *sna,
 			if (c == NULL)
 				c = malloc(sizeof(*c));
 			if (c != NULL) {
-				c->bo = flip->scanout[1].bo;
-				c->name = flip->scanout[1].name;
+				c->bo = sna->dri2.scanout[1].bo;
+				c->name = sna->dri2.scanout[1].name;
 				list_add(&c->link, &flip->cache);
 			}
 		}
 
 		if (c == NULL) {
 			DBG(("%s: not caching old scanout handle=%d, still busy\n",
-			     __FUNCTION__, flip->scanout[1].bo->handle));
-			kgem_bo_destroy(&sna->kgem, flip->scanout[1].bo);
+			     __FUNCTION__, sna->dri2.scanout[1].bo->handle));
+			kgem_bo_destroy(&sna->kgem, sna->dri2.scanout[1].bo);
 		}
 
-		flip->scanout[1].bo = NULL;
+		sna->dri2.scanout[1].bo = NULL;
 	}
 
 	if (sna->dri2.flip_pending == flip)
@@ -2114,9 +2110,12 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 		info->front = sna_dri2_reference_buffer(front);
 		info->back = sna_dri2_reference_buffer(back);
 
-		info->scanout[0].bo = ref(get_private(front)->bo);
-		info->scanout[0].name = info->front->name;
-		assert(info->scanout[0].bo->scanout);
+		if (sna->dri2.scanout[0].bo == NULL) {
+			sna->dri2.scanout[0].bo = ref(get_private(front)->bo);
+			sna->dri2.scanout[0].name = info->front->name;
+		}
+		assert(sna->dri2.scanout[0].bo == get_private(front)->bo);
+		assert(sna->dri2.scanout[0].bo->scanout);
 
 		if (sna->dri2.flip_pending) {
 			/* We need to first wait (one vblank) for the
@@ -2161,9 +2160,12 @@ out:
 	info->front = sna_dri2_reference_buffer(front);
 	info->back = sna_dri2_reference_buffer(back);
 
-	info->scanout[0].bo = ref(get_private(front)->bo);
-	info->scanout[0].name = info->front->name;
-	assert(info->scanout[0].bo->scanout);
+	if (sna->dri2.scanout[0].bo == NULL) {
+		sna->dri2.scanout[0].bo = ref(get_private(front)->bo);
+		sna->dri2.scanout[0].name = info->front->name;
+	}
+	assert(sna->dri2.scanout[0].bo == get_private(front)->bo);
+	assert(sna->dri2.scanout[0].bo->scanout);
 
 	/*
 	 * If divisor is zero, or current_msc is smaller than target_msc
@@ -2675,6 +2677,18 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
 	return DRI2ScreenInit(screen, &info);
 }
 
+void sna_dri2_reset_scanout(struct sna *sna)
+{
+	if (sna->dri2.scanout[1].bo != NULL) {
+		kgem_bo_destroy(&sna->kgem, sna->dri2.scanout[1].bo);
+		sna->dri2.scanout[1].bo = NULL;
+	}
+	if (sna->dri2.scanout[0].bo != NULL) {
+		kgem_bo_destroy(&sna->kgem, sna->dri2.scanout[0].bo);
+		sna->dri2.scanout[0].bo = NULL;
+	}
+}
+
 void sna_dri2_close(struct sna *sna, ScreenPtr screen)
 {
 	DBG(("%s()\n", __FUNCTION__));
commit 05f149285b429c7b3f25ac8049477230aaef512c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun May 25 07:14:53 2014 +0100

    sna/dri2: Defer reallocation of backbuffer until request
    
    If we defer the reallocation of the backbuffer until the client requests
    the set of current buffers (with GetBuffers), then we can often avoid
    allocating the fresh backbuffer as the flip often retires before the
    client is ready.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index d0abf87..829e5ba 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -51,35 +51,32 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <compositeext.h>
 #endif
 
-#if DRI2INFOREC_VERSION < 2
-#error DRI2 version supported by the Xserver is too old
-#endif
-
-#if DRI2INFOREC_VERSION < 6
-#define XORG_CAN_TRIPLE_BUFFER 0
-#define swap_limit(d, l) false
-#else
-#define XORG_CAN_TRIPLE_BUFFER 1
-static Bool
-sna_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit)
+static inline struct kgem_bo *ref(struct kgem_bo *bo)
 {
-	return swap_limit >= 1;
+	assert(bo->refcnt);
+	bo->refcnt++;
+	return bo;
 }
 
-static bool swap_limit(DrawablePtr draw, int limit)
+static inline void unref(struct kgem_bo *bo)
 {
-	DBG(("%s: setting swap limit to %d\n", __FUNCTION__, limit));
-	DRI2SwapLimit(draw, limit);
-	return true;
+	assert(bo->refcnt > 1);
+	bo->refcnt--;
 }
-#endif
 
-#if DRI2INFOREC_VERSION < 10
-#undef USE_ASYNC_SWAP
-#define USE_ASYNC_SWAP 0
-#endif
+struct sna_dri2_private {
+	PixmapPtr pixmap;
+	struct kgem_bo *bo;
+	bool scanout;
+	uint32_t size;
+	int refcnt;
+};
 
-#define COLOR_PREFER_TILING_Y 0
+static inline struct sna_dri2_private *
+get_private(void *buffer)
+{
+	return (struct sna_dri2_private *)((DRI2Buffer2Ptr)buffer+1);
+}
 
 enum frame_event_type {
 	WAITMSC = 0,
@@ -91,32 +88,182 @@ enum frame_event_type {
 	FLIP_COMPLETE,
 };
 
-struct sna_dri2_private {
-	PixmapPtr pixmap;
+struct dri_bo {
+	struct list link;
 	struct kgem_bo *bo;
-	bool scanout;
-	uint32_t size;
-	int refcnt;
+	uint32_t name;
 };
 
-static inline struct sna_dri2_private *
-get_private(void *buffer)
+struct sna_dri2_frame_event {
+	DrawablePtr draw;
+	ClientPtr client;
+	enum frame_event_type type;
+	xf86CrtcPtr crtc;
+	int pipe;
+	int count;
+	bool queued;
+
+	/* for swaps & flips only */
+	DRI2SwapEventPtr event_complete;
+	void *event_data;
+	DRI2BufferPtr front;
+	DRI2BufferPtr back;
+	struct kgem_bo *bo;
+
+	struct sna_dri2_frame_event *chain;
+
+	struct {
+		struct kgem_bo *bo;
+		uint32_t name;
+	} scanout[2];
+
+	struct list cache;
+
+	int mode;
+};
+
+static void
+sna_dri2_get_back(struct sna *sna, struct sna_dri2_frame_event *info)
 {
-	return (struct sna_dri2_private *)((DRI2Buffer2Ptr)buffer+1);
+	struct kgem_bo *bo;
+	uint32_t name;
+
+	DBG(("%s: scanout=(%d, %d), back=%d, cache?=%d\n",
+	     __FUNCTION__,
+	     info->scanout[0].bo ? info->scanout[0].bo->handle : 0,
+	     info->scanout[1].bo ? info->scanout[1].bo->handle : 0,
+	     get_private(info->back)->bo->handle,
+	     !list_is_empty(&info->cache)));
+
+	bo = get_private(info->back)->bo;
+	assert(bo->refcnt);
+	assert(bo->flush);
+	if (!(bo == info->scanout[0].bo || bo == info->scanout[1].bo)) {
+		DBG(("%s: reuse unattached back\n", __FUNCTION__));
+		return;
+	}
+
+	bo = NULL;
+	if (!list_is_empty(&info->cache)) {
+		struct dri_bo *c = list_first_entry(&info->cache, struct dri_bo, link);
+		if (c->bo) {
+			bo = c->bo;
+			name = c->name;
+			DBG(("%s: reuse cache handle=%d,name=%d\n", __FUNCTION__,
+			     bo->handle, name));
+			list_move_tail(&c->link, &info->cache);
+			c->bo = NULL;
+		}
+	}
+	if (bo == NULL) {
+		DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
+		bo = kgem_create_2d(&sna->kgem,
+				    info->draw->width,
+				    info->draw->height,
+				    info->draw->bitsPerPixel,
+				    get_private(info->front)->bo->tiling,
+				    CREATE_SCANOUT);
+		if (bo == NULL)
+			return;
+
+		name = kgem_bo_flink(&sna->kgem, bo);
+		if (name == 0) {
+			kgem_bo_destroy(&sna->kgem, bo);
+			return;
+		}
+	}
+
+	assert(!(bo == info->scanout[0].bo || bo == info->scanout[1].bo));
+	assert(name);
+
+	unref(get_private(info->back)->bo);
+	get_private(info->back)->bo = bo;
+	info->back->name = name;
+
+	assert(get_private(info->back)->bo != info->scanout[0].bo);
+	assert(get_private(info->back)->bo != info->scanout[1].bo);
+
+	assert(bo->refcnt == 1);
+	assert(bo->flush);
 }
 
-static inline struct kgem_bo *ref(struct kgem_bo *bo)
+static inline struct sna_dri2_frame_event *
+to_frame_event(uintptr_t  data)
 {
-	assert(bo->refcnt);
-	bo->refcnt++;
-	return bo;
+	 return (struct sna_dri2_frame_event *)(data & ~3);
 }
 
-static inline void unref(struct kgem_bo *bo)
+struct dri2_window {
+	struct sna_dri2_frame_event *chain;
+	xf86CrtcPtr crtc;
+	int64_t msc_delta;
+};
+
+static struct dri2_window *dri2_window(WindowPtr win)
 {
-	assert(bo->refcnt > 1);
-	bo->refcnt--;
+	return ((void **)__get_private(win, sna_window_key))[1];
+}
+
+static struct sna_dri2_frame_event *
+sna_dri2_window_get_chain(WindowPtr win)
+{
+	struct dri2_window *priv = dri2_window(win);
+	assert(priv != NULL);
+	return priv->chain;
+}
+
+#if DRI2INFOREC_VERSION < 2
+#error DRI2 version supported by the Xserver is too old
+#endif
+
+#if DRI2INFOREC_VERSION < 6
+#define XORG_CAN_TRIPLE_BUFFER 0
+#define swap_limit(d, l) false
+#else
+#define XORG_CAN_TRIPLE_BUFFER 1
+static Bool
+sna_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit)
+{
+	DBG(("%s: swap limit set to %d\n", __FUNCTION__, swap_limit));
+	return swap_limit >= 1;
+}
+
+static void
+sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
+{
+	DBG(("%s: reusing buffer pixmap=%ld, attachment=%d, handle=%d, name=%d\n",
+	     __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber,
+	     buffer->attachment, get_private(buffer)->bo->handle, buffer->name));
+	assert(get_private(buffer)->refcnt);
+	assert(get_private(buffer)->pixmap == NULL || get_private(buffer)->pixmap == get_drawable_pixmap(draw));
+	assert(get_private(buffer)->bo->refcnt);
+
+	if (buffer->attachment == DRI2BufferBackLeft &&
+	    draw->type != DRAWABLE_PIXMAP) {
+		struct sna_dri2_frame_event *info;
+
+		info = sna_dri2_window_get_chain((WindowPtr)draw);
+		if (info && info->back == buffer) {
+			DBG(("%s: replacing back buffer\n", __FUNCTION__));
+			sna_dri2_get_back(to_sna_from_drawable(draw), info);
+		}
+	}
+}
+
+static bool swap_limit(DrawablePtr draw, int limit)
+{
+	DBG(("%s: draw=%ld setting swap limit to %d\n", __FUNCTION__, (long)draw->id, limit));
+	DRI2SwapLimit(draw, limit);
+	return true;
 }
+#endif
+
+#if DRI2INFOREC_VERSION < 10
+#undef USE_ASYNC_SWAP
+#define USE_ASYNC_SWAP 0
+#endif
+
+#define COLOR_PREFER_TILING_Y 0
 
 /* Prefer to enable TILING_Y if this buffer will never be a
  * candidate for pageflipping
@@ -896,57 +1043,6 @@ static inline int sna_wait_vblank(struct sna *sna, union drm_wait_vblank *vbl, i
 
 #if DRI2INFOREC_VERSION >= 4
 
-struct dri_bo {
-	struct list link;
-	struct kgem_bo *bo;
-	uint32_t name;
-};
-
-struct sna_dri2_frame_event {
-	DrawablePtr draw;
-	ClientPtr client;
-	enum frame_event_type type;
-	xf86CrtcPtr crtc;
-	int pipe;
-	int count;
-	bool queued;
-
-	/* for swaps & flips only */
-	DRI2SwapEventPtr event_complete;
-	void *event_data;
-	DRI2BufferPtr front;
-	DRI2BufferPtr back;
-	struct kgem_bo *bo;
-
-	struct sna_dri2_frame_event *chain;
-
-	struct {
-		struct kgem_bo *bo;
-		uint32_t name;
-	} scanout[2];
-
-	struct list cache;
-
-	int mode;
-};
-
-static inline struct sna_dri2_frame_event *
-to_frame_event(uintptr_t  data)
-{
-	 return (struct sna_dri2_frame_event *)(data & ~1);
-}
-
-struct dri2_window {
-	struct sna_dri2_frame_event *chain;
-	xf86CrtcPtr crtc;
-	int64_t msc_delta;
-};
-
-static struct dri2_window *dri2_window(WindowPtr win)
-{
-	return ((void **)__get_private(win, sna_window_key))[1];
-}
-
 static void dri2_window_attach(WindowPtr win, struct dri2_window *priv)
 {
 	assert(win->drawable.type == DRAWABLE_WINDOW);
@@ -1018,14 +1114,6 @@ sna_dri2_get_crtc(DrawablePtr draw)
 	return sna_covering_crtc(sna, &box, NULL);
 }
 
-static struct sna_dri2_frame_event *
-sna_dri2_window_get_chain(WindowPtr win)
-{
-	struct dri2_window *priv = dri2_window(win);
-	assert(priv != NULL);
-	return priv->chain;
-}
-
 static void
 sna_dri2_remove_frame_event(WindowPtr win,
 			    struct sna_dri2_frame_event *info)
@@ -1195,6 +1283,10 @@ sna_dri2_page_flip(struct sna *sna, struct sna_dri2_frame_event *info)
 	info->scanout[0].name = info->back->name;
 	assert(info->scanout[0].bo->scanout);
 
+	DBG(("%s: pending scanout handle=%d, active scanout handle=%d\n",
+	     __FUNCTION__, info->scanout[0].bo->handle, info->scanout[1].bo->handle));
+	assert(info->scanout[0].bo->handle != info->scanout[1].bo->handle);
+
 	tmp.bo = get_private(info->front)->bo;
 	tmp.name = info->front->name;
 
@@ -1397,8 +1489,8 @@ static void frame_swap_complete(struct sna *sna,
 		return;
 
 	swap = sna_crtc_last_swap(frame->crtc);
-	DBG(("%s: pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n",
-	     __FUNCTION__, frame->pipe,
+	DBG(("%s: draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n",
+	     __FUNCTION__, (long)frame->draw, frame->pipe,
 	     (long long)swap->msc,
 	     (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc),
 	     swap->tv_sec, swap->tv_usec));
@@ -1416,8 +1508,8 @@ static void fake_swap_complete(struct sna *sna, ClientPtr client,
 	const struct ust_msc *swap;
 
 	swap = sna_crtc_last_swap(crtc);
-	DBG(("%s: pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
-	     __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1,
+	DBG(("%s: draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
+	     __FUNCTION__, (long)draw->id, crtc ? sna_crtc_to_pipe(crtc) : -1,
 	     (long long)swap->msc,
 	     (long long)draw_current_msc(draw, crtc, swap->msc),
 	     swap->tv_sec, swap->tv_usec));
@@ -1433,7 +1525,8 @@ static void chain_swap(struct sna *sna, DrawablePtr draw, struct sna_dri2_frame_
 	union drm_wait_vblank vbl;
 
 	assert(chain == sna_dri2_window_get_chain((WindowPtr)draw));
-	DBG(("%s: chaining type=%d\n", __FUNCTION__, chain->type));
+	DBG(("%s: chaining draw=%ld, type=%d\n",
+	     __FUNCTION__, (long)draw->id, chain->type));
 	switch (chain->type) {
 	case SWAP_THROTTLE:
 		DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
@@ -1661,7 +1754,7 @@ sna_dri2_immediate_blit(struct sna *sna,
 				}
 			}
 			if (event) {
-				DBG(("%s: fake triple bufferring, unblocking client\n", __FUNCTION__));
+				DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
 				frame_swap_complete(sna, info, DRI2_BLIT_COMPLETE);
 			}
 		}
@@ -1674,71 +1767,6 @@ sna_dri2_immediate_blit(struct sna *sna,
 	return ret;
 }
 
-static void
-sna_dri2_flip_get_back(struct sna *sna, struct sna_dri2_frame_event *info)
-{
-	struct kgem_bo *bo;
-	uint32_t name;
-
-	DBG(("%s: scanout=(%d, %d), back=%d, cache?=%d\n",
-	     __FUNCTION__,
-	     info->scanout[0].bo ? info->scanout[0].bo->handle : 0,
-	     info->scanout[1].bo ? info->scanout[1].bo->handle : 0,
-	     get_private(info->back)->bo->handle,
-	     !list_is_empty(&info->cache)));
-
-	bo = get_private(info->back)->bo;
-	assert(bo->refcnt);
-	assert(bo->flush);
-	if (!(bo == info->scanout[0].bo || bo == info->scanout[1].bo)) {
-		DBG(("%s: reuse unattached back\n", __FUNCTION__));
-		return;
-	}
-
-	bo = NULL;
-	if (!list_is_empty(&info->cache)) {
-		struct dri_bo *c = list_first_entry(&info->cache, struct dri_bo, link);
-		if (c->bo) {
-			bo = c->bo;
-			name = c->name;
-			DBG(("%s: reuse cache handle=%d,name=%d\n", __FUNCTION__,
-			     bo->handle, name));
-			list_move_tail(&c->link, &info->cache);
-			c->bo = NULL;
-		}
-	}
-	if (bo == NULL) {
-		DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
-		bo = kgem_create_2d(&sna->kgem,
-				    info->draw->width,
-				    info->draw->height,
-				    info->draw->bitsPerPixel,
-				    get_private(info->front)->bo->tiling,
-				    CREATE_SCANOUT);
-		if (bo == NULL)
-			return;
-
-		name = kgem_bo_flink(&sna->kgem, bo);
-		if (name == 0) {
-			kgem_bo_destroy(&sna->kgem, bo);
-			return;
-		}
-	}
-
-	assert(!(bo == info->scanout[0].bo || bo == info->scanout[1].bo));
-	assert(name);
-
-	unref(get_private(info->back)->bo);
-	get_private(info->back)->bo = bo;
-	info->back->name = name;
-
-	assert(get_private(info->back)->bo != info->scanout[0].bo);
-	assert(get_private(info->back)->bo != info->scanout[1].bo);
-
-	assert(bo->refcnt == 1);
-	assert(bo->flush);
-}
-
 static bool
 sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_frame_event *info)
 {
@@ -1775,11 +1803,11 @@ sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_frame_event *info)
 		if (!sna_dri2_page_flip(sna, info))
 			return false;
 
-		sna_dri2_flip_get_back(sna, info);
-#if !XORG_CAN_TRIPLE_BUFFER
-		DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
-		frame_swap_complete(sna, info, DRI2_FLIP_COMPLETE);
-#endif
+		if (!XORG_CAN_TRIPLE_BUFFER) {
+			sna_dri2_get_back(sna, info);
+			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
+			frame_swap_complete(sna, info, DRI2_FLIP_COMPLETE);
+		}
 	}
 
 	info->mode = 0;
@@ -1845,14 +1873,16 @@ static void sna_dri2_flip_event(struct sna *sna,
 	if (flip->scanout[1].bo) {
 		struct dri_bo *c = NULL;
 
-		DBG(("%s: retiring previous scanout handle=%d, name=%d, refcnt=%d\n",
+		DBG(("%s: retiring previous scanout handle=%d, name=%d, refcnt=%d (current scanout handle=%d)\n",
 		     __FUNCTION__,
 		     flip->scanout[1].bo->handle,
 		     flip->scanout[1].name,
-		     flip->scanout[1].bo->refcnt));
+		     flip->scanout[1].bo->refcnt,
+		     flip->scanout[0].bo->handle));
 
 		if (flip->scanout[1].bo != flip->scanout[0].bo &&
 		    flip->scanout[1].bo->refcnt == 1) {
+			DBG(("%s: adding old scanout to flip cache\n", __FUNCTION__));
 			if (!list_is_empty(&flip->cache))
 				c = list_last_entry(&flip->cache, struct dri_bo, link);
 			if (c) {
@@ -1870,8 +1900,11 @@ static void sna_dri2_flip_event(struct sna *sna,
 			}
 		}
 
-		if (c == NULL)
+		if (c == NULL) {
+			DBG(("%s: not caching old scanout handle=%d, still busy\n",
+			     __FUNCTION__, flip->scanout[1].bo->handle));
 			kgem_bo_destroy(&sna->kgem, flip->scanout[1].bo);
+		}
 
 		flip->scanout[1].bo = NULL;
 	}
@@ -2056,10 +2089,9 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 				_sna_dri2_destroy_buffer(sna, info->back);
 				info->back = sna_dri2_reference_buffer(back);
 			}
-			if (current_msc >= *target_msc) {
+			if (info->mode || current_msc >= *target_msc) {
 				DBG(("%s: executing xchg of pending flip\n",
 				     __FUNCTION__));
-				assert(info->mode == 0 || info->mode == FLIP_COMPLETE);
 				sna_dri2_exchange_buffers(draw, front, back);
 				info->mode = type = FLIP_COMPLETE;
 				goto new_back;
@@ -2104,13 +2136,12 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 		}
 
 		swap_limit(draw, 1 + (type == FLIP_THROTTLE));
-		if (type != FLIP) {
+		if (type == FLIP_COMPLETE) {
 new_back:
-			sna_dri2_flip_get_back(sna, info);
-			if (type == FLIP_COMPLETE) {
-				DBG(("%s: fake triple bufferring, unblocking client\n", __FUNCTION__));
-				frame_swap_complete(sna, info, DRI2_EXCHANGE_COMPLETE);
-			}
+			if (!XORG_CAN_TRIPLE_BUFFER)
+				sna_dri2_get_back(sna, info);
+			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
+			frame_swap_complete(sna, info, DRI2_EXCHANGE_COMPLETE);
 		}
 out:
 		DBG(("%s: target_msc=%llu\n", __FUNCTION__, current_msc + 1));
@@ -2214,9 +2245,9 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	struct sna_dri2_frame_event *info = NULL;
 	CARD64 current_msc;
 
-	DBG(("%s: pixmap=%ld, back=%u (refs=%d/%d, flush=%d) , fron=%u (refs=%d/%d, flush=%d)\n",
+	DBG(("%s: draw=%ld, pixmap=%ld, back=%u (refs=%d/%d, flush=%d) , fron=%u (refs=%d/%d, flush=%d)\n",
 	     __FUNCTION__,
-	     get_drawable_pixmap(draw)->drawable.serialNumber,
+	     (long)draw->id, get_drawable_pixmap(draw)->drawable.serialNumber,
 	     get_private(back)->bo->handle,
 	     get_private(back)->refcnt,
 	     get_private(back)->bo->refcnt,
@@ -2355,7 +2386,8 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
 	union drm_wait_vblank vbl;
 	xf86CrtcPtr crtc = sna_dri2_get_crtc(draw);
 
-	DBG(("%s(pipe=%d)\n", __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1));
+	DBG(("%s(draw=%ld, pipe=%d)\n", __FUNCTION__, draw->id,
+	     crtc ? sna_crtc_to_pipe(crtc) : -1));
 	if (crtc == NULL) {
 		const struct ust_msc *swap;
 
@@ -2632,7 +2664,7 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
 #if XORG_CAN_TRIPLE_BUFFER
 	info.version = 6;
 	info.SwapLimitValidate = sna_dri2_swap_limit_validate;
-	info.ReuseBufferNotify = NULL;
+	info.ReuseBufferNotify = sna_dri2_reuse_buffer;
 #endif
 
 #if USE_ASYNC_SWAP
commit e8d8f754ebf77f17a4666c8f649907bee50313bd
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 23 15:52:20 2014 +0100

    sna/dri2: Make the swap-limit transitions more obvious
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 4b1775d..d0abf87 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -1061,8 +1061,8 @@ sna_dri2_add_frame_event(DrawablePtr draw, ClientPtr client)
 	struct sna_dri2_frame_event *info, *chain;
 
 	assert(draw->type == DRAWABLE_WINDOW);
-	DBG(("%s: add[%p] to window %ld)\n",
-	     __FUNCTION__, info, (long)draw->id));
+	DBG(("%s: adding event to window %ld)\n",
+	     __FUNCTION__, (long)draw->id));
 
 	priv = dri2_window((WindowPtr)draw);
 	if (priv == NULL)
@@ -1209,7 +1209,6 @@ sna_dri2_page_flip(struct sna *sna, struct sna_dri2_frame_event *info)
 	sna->dri2.flip_pending = info;
 
 	info->queued = true;
-	swap_limit(info->draw, 1 + (info->type == FLIP_THROTTLE));
 	return true;
 }
 
@@ -2096,7 +2095,6 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 			     __FUNCTION__));
 			info->type = type = FLIP;
 			sna->dri2.flip_pending = info;
-			swap_limit(draw, 1);
 		} else {
 			info->type = type = use_triple_buffer(sna, client, *target_msc == 0);
 			if (!sna_dri2_page_flip(sna, info)) {
@@ -2105,7 +2103,8 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
 			}
 		}
 
-		if (info->type != FLIP) {
+		swap_limit(draw, 1 + (type == FLIP_THROTTLE));
+		if (type != FLIP) {
 new_back:
 			sna_dri2_flip_get_back(sna, info);
 			if (type == FLIP_COMPLETE) {
commit 9f4f855ba37966fb91d31e9081d03cf72affb154
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 26 07:06:18 2014 +0100

    sna: Implicit release of upload buffers considered bad
    
    Currently upload buffers are automatically decoupled when the buffer is
    retired. As retiring can happen during command setup after we have
    selected which bo to render with, this can free the bo we plan to use.
    Which is bad.
    
    Instead of making the release of upload buffers automatic, we manually
    check whether the buffer is idle before use as a source to consider
    scrapping it and replacing it with a real GPU bo. This is likely to keep
    upload buffers alive for longer (limiting reuse between Pixmaps but
    making reuse of the buffer within a Pixmap more likely) which is both
    good and bad. (Good - may improve the content cache, bad - may increase
    the amount of memory used by upload buffers for arbitrary long periods.)
    
    Reported-by: Matti Hämäläinen <ccr at tnsp.org>
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=79238
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 12e41ca..24ba6f2 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -2178,25 +2178,6 @@ static void kgem_bo_unref(struct kgem *kgem, struct kgem_bo *bo)
 		__kgem_bo_destroy(kgem, bo);
 }
 
-static void kgem_buffer_release(struct kgem *kgem, struct kgem_buffer *bo)
-{
-	assert(bo->base.io);
-	while (!list_is_empty(&bo->base.vma)) {
-		struct kgem_bo *cached;
-
-		cached = list_first_entry(&bo->base.vma, struct kgem_bo, vma);
-		assert(cached->proxy == &bo->base);
-		assert(cached != &bo->base);
-		list_del(&cached->vma);
-
-		assert(*(struct kgem_bo **)cached->map__gtt == cached);
-		*(struct kgem_bo **)cached->map__gtt = NULL;
-		cached->map__gtt = NULL;
-
-		kgem_bo_destroy(kgem, cached);
-	}
-}
-
 static bool kgem_retire__buffers(struct kgem *kgem)
 {
 	bool retired = false;
@@ -2217,7 +2198,6 @@ static bool kgem_retire__buffers(struct kgem *kgem)
 		DBG(("%s: releasing upload cache for handle=%d? %d\n",
 		     __FUNCTION__, bo->base.handle, !list_is_empty(&bo->base.vma)));
 		list_del(&bo->base.list);
-		kgem_buffer_release(kgem, bo);
 		kgem_bo_unref(kgem, &bo->base);
 		retired = true;
 	}
@@ -6670,17 +6650,6 @@ struct kgem_bo *kgem_upload_source_image(struct kgem *kgem,
 	return bo;
 }
 
-void kgem_proxy_bo_attach(struct kgem_bo *bo,
-			  struct kgem_bo **ptr)
-{
-	DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle));
-	assert(bo->map__gtt == NULL);
-	assert(bo->proxy);
-	list_add(&bo->vma, &bo->proxy->vma);
-	bo->map__gtt = ptr;
-	*ptr = kgem_bo_reference(bo);
-}
-
 void kgem_buffer_read_sync(struct kgem *kgem, struct kgem_bo *_bo)
 {
 	struct kgem_buffer *bo;
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index cbaaa5e..3524e7b 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -258,7 +258,6 @@ struct kgem_bo *kgem_upload_source_image(struct kgem *kgem,
 					 const void *data,
 					 const BoxRec *box,
 					 int stride, int bpp);
-void kgem_proxy_bo_attach(struct kgem_bo *bo, struct kgem_bo **ptr);
 
 int kgem_choose_tiling(struct kgem *kgem,
 		       int tiling, int width, int height, int bpp);
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index a1133a3..9ac3f3c 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -1981,7 +1981,8 @@ _sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags)
 			sna_pixmap_discard_shadow_damage(priv, NULL);
 	}
 
-	if (flags & MOVE_WRITE && priv->gpu_bo && priv->gpu_bo->proxy) {
+	if ((priv->gpu_bo && priv->gpu_bo->proxy) &&
+	    (flags & MOVE_WRITE || priv->gpu_bo->proxy->rq == NULL)) {
 		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
 		assert(DAMAGE_IS_ALL(priv->cpu_damage));
 		assert(!priv->pinned);
@@ -2415,7 +2416,8 @@ sna_drawable_move_region_to_cpu(DrawablePtr drawable,
 
 	assert(priv->gpu_damage == NULL || priv->gpu_bo);
 
-	if (flags & MOVE_WRITE && priv->gpu_bo && priv->gpu_bo->proxy) {
+	if ((priv->gpu_bo && priv->gpu_bo->proxy) &&
+	    (flags & MOVE_WRITE || priv->gpu_bo->proxy->rq == NULL)) {
 		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
 		assert(DAMAGE_IS_ALL(priv->cpu_damage));
 		assert(priv->gpu_damage == NULL);
@@ -3170,7 +3172,8 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
 		goto done;
 	}
 
-	if (flags & MOVE_WRITE && priv->gpu_bo && priv->gpu_bo->proxy) {
+	if ((priv->gpu_bo && priv->gpu_bo->proxy) &&
+	    (flags & MOVE_WRITE || priv->gpu_bo->proxy->rq == NULL)) {
 		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
 		assert(priv->gpu_damage == NULL);
 		assert(!priv->pinned);
@@ -3907,7 +3910,8 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
 		goto active;
 	}
 
-	if (flags & MOVE_WRITE && priv->gpu_bo && priv->gpu_bo->proxy) {
+	if ((priv->gpu_bo && priv->gpu_bo->proxy) &&
+	    (flags & MOVE_WRITE || priv->gpu_bo->proxy->rq == NULL)) {
 		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
 		assert(priv->gpu_damage == NULL);
 		assert(!priv->pinned);
@@ -6241,7 +6245,7 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
 				     __FUNCTION__));
 				assert(src_priv->gpu_damage == NULL);
 				assert(src_priv->gpu_bo == NULL);
-				kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo);
+				src_priv->gpu_bo = kgem_bo_reference(src_bo);
 			}
 
 			if (!sna->render.copy_boxes(sna, alu,
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index b67bd26..d3cb6a0 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -565,7 +565,7 @@ static struct kgem_bo *upload(struct sna *sna,
 			assert(priv->gpu_damage == NULL);
 			assert(priv->gpu_bo == NULL);
 			assert(bo->proxy != NULL);
-			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
+			priv->gpu_bo = kgem_bo_reference(bo);
 		}
 	}
 
@@ -1266,7 +1266,7 @@ sna_render_picture_extract(struct sna *sna,
 			assert(priv->gpu_damage == NULL);
 			assert(priv->gpu_bo == NULL);
 			assert(bo->proxy != NULL);
-			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
+			priv->gpu_bo = kgem_bo_reference(bo);
 		}
 	}
 
commit b508d8f3318c42a2a87b7731789b1d03610e9b46
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 26 06:54:03 2014 +0100

    sna: Assert that we do not replace active IO buffers
    
    References: https://bugs.freedesktop.org/show_bug.cgi?id=79238
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index f635150..12e41ca 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -6223,7 +6223,7 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
 			     __FUNCTION__, size, bo->used, bytes(&bo->base)));
 			gem_write__cachealigned(kgem->fd, bo->base.handle,
 						0, bo->used, bo->mem);
-			kgem_buffer_release(kgem, bo);
+			assert(list_is_empty(&bo->base.vma));
 			bo->need_io = 0;
 			bo->write = 0;
 			offset = 0;
@@ -6280,13 +6280,14 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
 				goto done;
 			}
 
-			if (size <= bytes(&bo->base) &&
+			if (bo->base.refcnt == 1 &&
+			    size <= bytes(&bo->base) &&
 			    (bo->base.rq == NULL ||
 			     !__kgem_busy(kgem, bo->base.handle))) {
 				DBG(("%s: reusing whole buffer? size=%d, total=%d\n",
 				     __FUNCTION__, size, bytes(&bo->base)));
 				__kgem_bo_clear_busy(&bo->base);
-				kgem_buffer_release(kgem, bo);
+				assert(list_is_empty(&bo->base.vma));
 
 				switch (bo->mmapped) {
 				case MMAPPED_CPU:


More information about the xorg-commit mailing list