[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

xserver-xorg-video-intel: Changes to 'upstream-experimental'



 NEWS                     |   21 ++
 configure.ac             |    2 
 man/intel.man            |    9 +
 src/intel_display.c      |   26 +++
 src/intel_options.c      |    1 
 src/intel_options.h      |    1 
 src/sna/gen2_render.c    |    1 
 src/sna/gen3_render.c    |    2 
 src/sna/gen4_render.c    |   12 +
 src/sna/gen5_render.c    |   94 ++++++-------
 src/sna/gen6_render.c    |   96 +++++--------
 src/sna/gen7_render.c    |   99 ++++++-------
 src/sna/kgem.c           |  334 +++++++++++++++++++++++++++--------------------
 src/sna/kgem.h           |   15 +-
 src/sna/sna_accel.c      |  156 +++++++++++----------
 src/sna/sna_blt.c        |    4 
 src/sna/sna_composite.c  |    4 
 src/sna/sna_display.c    |   64 ++++++---
 src/sna/sna_dri.c        |   47 ++----
 src/sna/sna_render.c     |    4 
 src/sna/sna_trapezoids.c |   34 +++-
 21 files changed, 586 insertions(+), 440 deletions(-)

New commits:
commit d933f3a7965c9aa70f70477be3bfe94d5ded948b
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Sun Sep 2 10:29:49 2012 +0100

    2.20.6 release
    
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/NEWS b/NEWS
index 54f2caa..a2caaa7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,24 @@
+Release 2.20.6 (2012-09-02)
+===========================
+A serious bug that caused a crash on SandyBridge and IvyBridge when
+mixing CPU and GPU operations on the same buffer, and an annoyance from
+bad scheduling of windowed swapbuffer updates causing low framerates and
+jitter. Plus the usual smattering of assertion fixes and a long standing
+issue with incoherent page access to a streaming buffer.
+
+ * Low frame rates in Blobby Valley when "fullscreen"
+   https://bugs.freedesktop.org/show_bug.cgi?id=54274
+
+ * Incoherent concurrent access with the CPU and GPU
+   https://bugs.freedesktop.org/show_bug.cgi
+   https://bugs.freedesktop.org/show_bug.cgi
+
+ * Add Option "Backlight" to override automatic selection of the
+   backlight interface.
+
+ * Avoid overwriting the composite operation info when testing if we
+   can transfer the operation to the BLT.
+
 Release 2.20.5 (2012-08-26)
 ===========================
 Another silly bug found, another small bugfix release. The goal was for
diff --git a/configure.ac b/configure.ac
index 114e721..c401a61 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,7 +23,7 @@
 # Initialize Autoconf
 AC_PREREQ([2.60])
 AC_INIT([xf86-video-intel],
-        [2.20.5],
+        [2.20.6],
         [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
         [xf86-video-intel])
 AC_CONFIG_SRCDIR([Makefile.am])

commit 62e7e69d88f7e5c8b0f0931fe887ee0c3bddb43f
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Sun Sep 2 09:55:07 2012 +0100

    sna: Tweak placement rules if we already have a CPU bo
    
    If we have a CPU bo, consider if it may be quicker to render to it then
    create a GPU bo.
    
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 7c598f1..bb7cda2 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -2427,23 +2427,43 @@ sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
 			goto use_cpu_bo;
 		}
 
-		if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
-			DBG(("%s: already using CPU bo, will not force allocation\n",
-			     __FUNCTION__));
-			goto use_cpu_bo;
-		}
+		if ((flags & IGNORE_CPU) == 0) {
+			if (priv->cpu_bo) {
+				if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) {
+					if (kgem_bo_is_busy(priv->cpu_bo)) {
+						DBG(("%s: already using CPU bo, will not force allocation\n",
+						     __FUNCTION__));
+						goto use_cpu_bo;
+					}
 
-		if (priv->cpu_damage && flags == 0) {
-			DBG(("%s: prefer cpu", __FUNCTION__));
-			goto use_cpu_bo;
-		}
+					if ((flags & RENDER_GPU) == 0) {
+						DBG(("%s: prefer cpu", __FUNCTION__));
+						goto use_cpu_bo;
+					}
+				} else {
+					if (kgem_bo_is_busy(priv->cpu_bo)) {
+						DBG(("%s: CPU bo active, must force allocation\n",
+						     __FUNCTION__));
+						goto create_gpu_bo;
+					}
+				}
+			}
 
-		if (priv->cpu_damage && !box_inplace(pixmap, box)) {
-			DBG(("%s: damaged with a small operation, will not force allocation\n",
-			     __FUNCTION__));
-			goto use_cpu_bo;
+			if (priv->cpu_damage) {
+				if ((flags & (PREFER_GPU | FORCE_GPU)) == 0) {
+					DBG(("%s: prefer cpu", __FUNCTION__));
+					goto use_cpu_bo;
+				}
+
+				if (!box_inplace(pixmap, box)) {
+					DBG(("%s: damaged with a small operation, will not force allocation\n",
+					     __FUNCTION__));
+					goto use_cpu_bo;
+				}
+			}
 		}
 
+create_gpu_bo:
 		move = MOVE_WRITE | MOVE_READ;
 		if (flags & FORCE_GPU)
 			move |= __MOVE_FORCE;

commit f837807cc257fbedd35fa6101dc0b4a57e5ad78d
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Sat Sep 1 10:36:09 2012 +0100

    sna/dri: Remove busy-wait spin from vblank chaining of swapbuffers
    
    The issue being that, due to the delay, the chained swap would miss its
    intended vblank and so cause an unwanted reduction in frame throughput
    and increase output latency even further. Since both client and server
    have other rate-limiting processes in place, we can forgo the stall here
    and still keep the clients in check.
    
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=54274
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 0210d73..77e4e26 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -1268,9 +1268,6 @@ void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 		break;
 
 	case DRI2_SWAP_THROTTLE:
-		if (!sna_dri_blit_complete(sna, info))
-			return;
-
 		DBG(("%s: %d complete, frame=%d tv=%d.%06d\n",
 		     __FUNCTION__, info->type,
 		     event->sequence, event->tv_sec, event->tv_usec));

commit b56e8c5105c858452ca4eabf15b298fc06dfd3c8
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Sat Sep 1 12:15:47 2012 +0100

    sna: Nullify gpu_bo after free in case final release is deferred in destroy
    
    As we may defer the actual release of the pixmap until after completion
    of the last shm operation, we need to make sure in that case we mark the
    GPU bo as released to prevent a use-after-free.
    
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 7dad94b..7c598f1 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -1073,8 +1073,10 @@ static Bool sna_destroy_pixmap(PixmapPtr pixmap)
 	sna = to_sna_from_pixmap(pixmap);
 
 	/* Always release the gpu bo back to the lower levels of caching */
-	if (priv->gpu_bo)
+	if (priv->gpu_bo) {
 		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
+		priv->gpu_bo = NULL;
+	}
 
 	if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) {
 		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);

commit c4d994014160d8c946af731196a908991c77d9f9
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Sat Sep 1 10:44:24 2012 +0100

    sna/gen2+: Add the missing assertions in case the drawrect is invalid
    
    Only the later gen had these useful assertions, add them to the rest
    just in case.
    
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c
index d2f6fe7..7d51823 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -543,6 +543,7 @@ gen2_get_batch(struct sna *sna)
 
 static void gen2_emit_target(struct sna *sna, const struct sna_composite_op *op)
 {
+	assert(!too_large(op->dst.width, op->dst.height));
 	assert(op->dst.bo->pitch >= 8 && op->dst.bo->pitch <= MAX_3D_PITCH);
 	assert(sna->render_state.gen2.vertex_offset == 0);
 
diff --git a/src/sna/gen3_render.c b/src/sna/gen3_render.c
index ab94bdb..c5ec9bc 100644
--- a/src/sna/gen3_render.c
+++ b/src/sna/gen3_render.c
@@ -1341,6 +1341,8 @@ static void gen3_emit_target(struct sna *sna,
 {
 	struct gen3_render_state *state = &sna->render_state.gen3;
 
+	assert(!too_large(width, height));
+
 	/* BUF_INFO is an implicit flush, so skip if the target is unchanged. */
 	assert(bo->unique_id != 0);
 	if (bo->unique_id != state->current_dst) {
diff --git a/src/sna/gen4_render.c b/src/sna/gen4_render.c
index e732810..d8b76a1 100644
--- a/src/sna/gen4_render.c
+++ b/src/sna/gen4_render.c
@@ -1283,6 +1283,9 @@ gen4_emit_drawing_rectangle(struct sna *sna, const struct sna_composite_op *op)
 	uint32_t limit = (op->dst.height - 1) << 16 | (op->dst.width - 1);
 	uint32_t offset = (uint16_t)op->dst.y << 16 | (uint16_t)op->dst.x;
 
+	assert(!too_large(op->dst.x, op->dst.y));
+	assert(!too_large(op->dst.width, op->dst.height));
+
 	if (sna->render_state.gen4.drawrect_limit == limit &&
 	    sna->render_state.gen4.drawrect_offset == offset)
 		return;

commit 25c1b478a957ceb0474e7121840b7eed1ba2e140
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Sat Sep 1 09:49:34 2012 +0100

    sna: Discard cached CPU upload early when clearing with a solid fill
    
    Otherwise we end up considering the GPU bo as a real target, causing
    confusion and failed asserts.
    
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 090da91..7dad94b 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -4153,6 +4153,10 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
 		DBG(("%s: overwritting CPU damage\n", __FUNCTION__));
 		if (region_subsumes_damage(region, dst_priv->cpu_damage)) {
 			DBG(("%s: discarding existing CPU damage\n", __FUNCTION__));
+			if (dst_priv->gpu_bo && dst_priv->gpu_bo->proxy) {
+				kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
+				dst_priv->gpu_bo = NULL;
+			}
 			sna_damage_destroy(&dst_priv->cpu_damage);
 			list_del(&dst_priv->list);
 		}
@@ -11580,6 +11584,10 @@ sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect)
 		    region_is_singular(gc->pCompositeClip)) {
 			if (region_subsumes_damage(&region, priv->cpu_damage)) {
 				DBG(("%s: discarding existing CPU damage\n", __FUNCTION__));
+				if (priv->gpu_bo && priv->gpu_bo->proxy) {
+					kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
+					priv->gpu_bo = NULL;
+				}
 				sna_damage_destroy(&priv->cpu_damage);
 				list_del(&priv->list);
 			}
diff --git a/src/sna/sna_composite.c b/src/sna/sna_composite.c
index d47479b..65dae9c 100644
--- a/src/sna/sna_composite.c
+++ b/src/sna/sna_composite.c
@@ -829,6 +829,10 @@ sna_composite_rectangles(CARD8		 op,
 		if (priv->cpu_damage &&
 		    region_subsumes_damage(&region, priv->cpu_damage)) {
 			DBG(("%s: discarding existing CPU damage\n", __FUNCTION__));
+			if (priv->gpu_bo && priv->gpu_bo->proxy) {
+				kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
+				priv->gpu_bo = NULL;
+			}
 			sna_damage_destroy(&priv->cpu_damage);
 			list_del(&priv->list);
 		}

commit 530b1d1516595cf14c5112d8833b870cd50eca46
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Thu Aug 30 22:21:57 2012 +0100

    sna/dri: Use common routine for testing busyness after flush
    
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 5fa17d7..0210d73 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -1206,24 +1206,21 @@ static void chain_swap(struct sna *sna,
 static bool sna_dri_blit_complete(struct sna *sna,
 				  struct sna_dri_frame_event *info)
 {
-	if (info->bo && kgem_bo_is_busy(info->bo)) {
-		kgem_retire(&sna->kgem);
-		if (kgem_bo_is_busy(info->bo)) {
-			drmVBlank vbl;
+	if (info->bo && __kgem_bo_is_busy(&sna->kgem, info->bo)) {
+		drmVBlank vbl;
 
-			DBG(("%s: vsync'ed blit is still busy, postponing\n",
-			     __FUNCTION__));
+		DBG(("%s: vsync'ed blit is still busy, postponing\n",
+		     __FUNCTION__));
 
-			VG_CLEAR(vbl);
-			vbl.request.type =
-				DRM_VBLANK_RELATIVE |
-				DRM_VBLANK_EVENT |
-				pipe_select(info->pipe);
-			vbl.request.sequence = 1;
-			vbl.request.signal = (unsigned long)info;
-			if (!sna_wait_vblank(sna, &vbl))
-				return false;
-		}
+		VG_CLEAR(vbl);
+		vbl.request.type =
+			DRM_VBLANK_RELATIVE |
+			DRM_VBLANK_EVENT |
+			pipe_select(info->pipe);
+		vbl.request.sequence = 1;
+		vbl.request.signal = (unsigned long)info;
+		if (!sna_wait_vblank(sna, &vbl))
+			return false;
 	}
 
 	return true;

commit 00d8c776b3607dbdab32c1126f91a7a38b8065f6
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Thu Aug 30 21:47:17 2012 +0100

    sna/dri: Hold a reference to the vsync blit
    
    Fixes regression from
    
    commit 96a921487ef00db03a12bec7b0821410d6b74c31
    Author: Chris Wilson <chris@chris-wilson.co.uk>
    Date:   Mon Aug 27 21:50:32 2012 +0100
    
        sna: Track outstanding requests per-ring
    
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index ed5e342..6df5a2e 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -1258,8 +1258,10 @@ inline static void kgem_bo_move_to_inactive(struct kgem *kgem,
 {
 	DBG(("%s: moving handle=%d to inactive\n", __FUNCTION__, bo->handle));
 
+	assert(bo->refcnt == 0);
 	assert(bo->reusable);
 	assert(bo->rq == NULL);
+	assert(bo->exec == NULL);
 	assert(bo->domain != DOMAIN_GPU);
 	assert(!kgem_busy(kgem, bo->handle));
 	assert(!bo->proxy);
@@ -1544,6 +1546,7 @@ destroy:
 
 static void kgem_bo_unref(struct kgem *kgem, struct kgem_bo *bo)
 {
+	assert(bo->refcnt);
 	if (--bo->refcnt == 0)
 		__kgem_bo_destroy(kgem, bo);
 }
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 06a940b..5fa17d7 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -616,7 +616,7 @@ sna_dri_copy_to_front(struct sna *sna, DrawablePtr draw, RegionPtr region,
 		if (flush) { /* STAT! */
 			struct kgem_request *rq = sna->kgem.next_request;
 			kgem_submit(&sna->kgem);
-			bo = rq->bo;
+			bo = kgem_bo_reference(rq->bo);
 		}
 	}
 

commit b2a6c74c2159c9968c19400d61a11f4773724b4a
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Wed Aug 29 14:51:40 2012 +0100

    sna: Remove inconsistent assertion
    
    As we now may not prefer to use the GPU even if all-damaged and clear,
    asserting that if we choose to use the CPU if clear is now bogus.
    
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 9c493c2..090da91 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -2379,6 +2379,7 @@ sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
 	if (priv->gpu_bo && priv->gpu_bo->proxy) {
 		DBG(("%s: cached upload proxy, discard and revert to GPU\n",
 		     __FUNCTION__));
+		assert(priv->gpu_damage == NULL);
 		kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem,
 				priv->gpu_bo);
 		priv->gpu_bo = NULL;
@@ -2548,7 +2549,6 @@ use_gpu_bo:
 	return priv->gpu_bo;
 
 use_cpu_bo:
-	assert(!priv->clear);
 	if (priv->cpu_bo == NULL)
 		return NULL;
 

commit deaa1cac269be03f4ec44092f70349ff466d59de
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Tue Aug 28 22:23:22 2012 +0100

    sna: Align active upload buffers to the next page for reuse
    
    If we write to the same page as it already active on the GPU then
    despite the invalidation performed at the beginning of each batch, we do
    not seem to correctly sample the new data.
    
    References: https://bugs.freedesktop.org/show_bug.cgi?id=51422
    References: https://bugs.freedesktop.org/show_bug.cgi?id=52299
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index e51bbc0..ed5e342 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -1910,13 +1910,18 @@ static void kgem_finish_buffers(struct kgem *kgem)
 		}
 
 		if (bo->mmapped) {
+			int used;
+
 			assert(!bo->need_io);
+
+			used = ALIGN(bo->used + PAGE_SIZE-1, PAGE_SIZE);
 			if (!DBG_NO_UPLOAD_ACTIVE &&
-			    bo->used + PAGE_SIZE <= bytes(&bo->base) &&
+			    used + PAGE_SIZE <= bytes(&bo->base) &&
 			    (kgem->has_llc || !IS_CPU_MAP(bo->base.map))) {
 				DBG(("%s: retaining upload buffer (%d/%d)\n",
 				     __FUNCTION__, bo->used, bytes(&bo->base)));
 				assert(!bo->base.snoop);
+				bo->used = used;
 				list_move(&bo->base.list,
 					  &kgem->active_buffers);
 				continue;

commit 9e0305a3928f253ded6c8e141a4dd42be3952eb9
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Tue Aug 28 20:49:20 2012 +0100

    sna: Discard inplace flag if we create a CPU map for the upload buffer
    
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index ba8b0b9..e51bbc0 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -4300,6 +4300,7 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
 			assert(bo->base.refcnt >= 1);
 			assert(bo->mmapped);
 			assert(!bo->base.snoop);
+			assert(!IS_CPU_MAP(bo->base.map) || kgem->has_llc);
 
 			if ((bo->write & ~flags) & KGEM_BUFFER_INPLACE) {
 				DBG(("%s: skip write %x buffer, need %x\n",
@@ -4435,9 +4436,11 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
 			assert(bo->mmapped);
 			assert(bo->base.refcnt == 1);
 
-			bo->mem = kgem_bo_map__gtt(kgem, &bo->base);
+			bo->mem = kgem_bo_map(kgem, &bo->base);
 			if (bo->mem) {
 				alloc = num_pages(&bo->base);
+				if (IS_CPU_MAP(bo->base.map))
+				    flags &= ~KGEM_BUFFER_INPLACE;
 				goto init;
 			} else {
 				bo->base.refcnt = 0;

commit f3e122554e88da0351bfb9a7a722f0715553689b
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Tue Aug 28 21:27:04 2012 +0100

    sna: Propagate the request to flush rather than directly submit the batch
    
    The subtly is that we need to reset the mode correctly after
    submitting the batch which was not handled by kgem_flush(). If we fail
    to set the appropriate mode then the next operation will be on a random
    ring, which can prove fatal with SandyBridge+.
    
    Reported-by: Reinis Danne <reinis.danne@gmail.com>
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 520f0b2..ba8b0b9 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -3480,7 +3480,8 @@ bool kgem_check_bo(struct kgem *kgem, ...)
 	int num_exec = 0;
 	int num_pages = 0;
 
-	kgem_flush(kgem);
+	if (kgem_flush(kgem))
+		return false;
 
 	va_start(ap, kgem);
 	while ((bo = va_arg(ap, struct kgem_bo *))) {
@@ -3516,7 +3517,8 @@ bool kgem_check_bo_fenced(struct kgem *kgem, struct kgem_bo *bo)
 {
 	uint32_t size;
 
-	kgem_flush(kgem);
+	if (kgem_flush(kgem))
+		return false;
 
 	while (bo->proxy)
 		bo = bo->proxy;
@@ -3561,7 +3563,8 @@ bool kgem_check_many_bo_fenced(struct kgem *kgem, ...)
 	int num_pages = 0;
 	int fenced_size = 0;
 
-	kgem_flush(kgem);
+	if (kgem_flush(kgem))
+		return false;
 
 	va_start(ap, kgem);
 	while ((bo = va_arg(ap, struct kgem_bo *))) {
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index a72fe42..d72db55 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -279,10 +279,9 @@ static inline void kgem_submit(struct kgem *kgem)
 		_kgem_submit(kgem);
 }
 
-static inline void kgem_flush(struct kgem *kgem)
+static inline bool kgem_flush(struct kgem *kgem)
 {
-	if (kgem->flush && kgem_is_idle(kgem))
-		_kgem_submit(kgem);
+	return kgem->flush && kgem_is_idle(kgem);
 }
 
 static inline void kgem_bo_submit(struct kgem *kgem, struct kgem_bo *bo)

commit b5c8efe4309248e62d94d80b37a70775284ae985
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Tue Aug 28 08:33:00 2012 +0100

    sna: Make sure we reset the domain tracking when exporting DRI bo
    
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index cd16ffe..520f0b2 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -3905,6 +3905,8 @@ uint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo)
 
 	/* The bo is outside of our control, so presume it is written to */
 	bo->needs_flush = true;
+	if (bo->domain != DOMAIN_GPU)
+		bo->domain = DOMAIN_NONE;
 
 	/* Henceforth, we need to broadcast all updates to clients and
 	 * flush our rendering before doing so.
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 8967ed9..06a940b 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -426,6 +426,8 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
 
 	kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
 	priv->gpu_bo = ref(bo);
+	if (bo->domain != DOMAIN_GPU)
+		bo->domain = DOMAIN_NONE;
 
 	/* Post damage on the new front buffer so that listeners, such
 	 * as DisplayLink know take a copy and shove it over the USB.

commit 96a921487ef00db03a12bec7b0821410d6b74c31
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Mon Aug 27 21:50:32 2012 +0100

    sna: Track outstanding requests per-ring
    
    In order to properly track when the GPU is idle, we need to account for
    the completion order that may differ on architectures like SandyBridge
    with multiple mostly independent rings.
    
    Reported-by: Clemens Eisserer <linuxhippy@gmail.com>
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=54127
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index dc7c95d..cd16ffe 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -353,7 +353,8 @@ kgem_busy(struct kgem *kgem, int handle)
 	busy.handle = handle;
 	busy.busy = !kgem->wedged;
 	(void)drmIoctl(kgem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
-	DBG(("%s: handle=%d, busy=%d, wedged=%d\n", busy.busy, kgem->wedged));
+	DBG(("%s: handle=%d, busy=%d, wedged=%d\n",
+	     __FUNCTION__, handle, busy.busy, kgem->wedged));
 
 	return busy.busy;
 }
@@ -551,6 +552,7 @@ static struct kgem_request *__kgem_request_alloc(void)
 
 	list_init(&rq->buffers);
 	rq->bo = NULL;
+	rq->ring = 0;
 
 	return rq;
 }
@@ -849,9 +851,10 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, int gen)
 	DBG(("%s: half cpu cache %d pages\n", __FUNCTION__,
 	     kgem->half_cpu_cache_pages));
 
+	list_init(&kgem->requests[0]);
+	list_init(&kgem->requests[1]);
 	list_init(&kgem->batch_buffers);
 	list_init(&kgem->active_buffers);
-	list_init(&kgem->requests);
 	list_init(&kgem->flushing);
 	list_init(&kgem->large);
 	list_init(&kgem->snoop);
@@ -1630,106 +1633,122 @@ static bool kgem_retire__requests(struct kgem *kgem)
 {
 	struct kgem_bo *bo;
 	bool retired = false;
+	int n;
 
-	while (!list_is_empty(&kgem->requests)) {
-		struct kgem_request *rq;
-
-		rq = list_first_entry(&kgem->requests,
-				      struct kgem_request,
-				      list);
-		if (kgem_busy(kgem, rq->bo->handle))
-			break;
-
-		DBG(("%s: request %d complete\n",
-		     __FUNCTION__, rq->bo->handle));
+	for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) {
+		while (!list_is_empty(&kgem->requests[n])) {
+			struct kgem_request *rq;
 
-		while (!list_is_empty(&rq->buffers)) {
-			bo = list_first_entry(&rq->buffers,
-					      struct kgem_bo,
-					      request);
+			rq = list_first_entry(&kgem->requests[n],
+					      struct kgem_request,
+					      list);
+			if (kgem_busy(kgem, rq->bo->handle))
+				break;
 
-			assert(bo->rq == rq);
-			assert(bo->exec == NULL);
-			assert(bo->domain == DOMAIN_GPU);
+			DBG(("%s: request %d complete\n",
+			     __FUNCTION__, rq->bo->handle));
 
-			list_del(&bo->request);
+			while (!list_is_empty(&rq->buffers)) {
+				bo = list_first_entry(&rq->buffers,
+						      struct kgem_bo,
+						      request);
 
-			if (bo->needs_flush)
-				bo->needs_flush = kgem_busy(kgem, bo->handle);
-			if (bo->needs_flush) {
-				DBG(("%s: moving %d to flushing\n",
-				     __FUNCTION__, bo->handle));
-				list_add(&bo->request, &kgem->flushing);
-				bo->rq = &_kgem_static_request;
-			} else {
-				bo->domain = DOMAIN_NONE;
-				bo->rq = NULL;
-			}
+				assert(bo->rq == rq);
+				assert(bo->exec == NULL);
+				assert(bo->domain == DOMAIN_GPU);
 
-			if (bo->refcnt)
-				continue;
+				list_del(&bo->request);
 
-			if (bo->snoop) {
+				if (bo->needs_flush)
+					bo->needs_flush = kgem_busy(kgem, bo->handle);
 				if (bo->needs_flush) {
+					DBG(("%s: moving %d to flushing\n",
+					     __FUNCTION__, bo->handle));
 					list_add(&bo->request, &kgem->flushing);
 					bo->rq = &_kgem_static_request;
 				} else {
-					kgem_bo_move_to_snoop(kgem, bo);
+					bo->domain = DOMAIN_NONE;
+					bo->rq = NULL;
 				}
-				continue;
-			}
 
-			if (!bo->reusable) {
-				DBG(("%s: closing %d\n",
-				     __FUNCTION__, bo->handle));
-				kgem_bo_free(kgem, bo);
-				continue;
-			}
+				if (bo->refcnt)
+					continue;
 
-			if (!bo->needs_flush) {
-				if (kgem_bo_set_purgeable(kgem, bo)) {
-					kgem_bo_move_to_inactive(kgem, bo);
-					retired = true;
-				} else {
+				if (bo->snoop) {
+					if (bo->needs_flush) {
+						list_add(&bo->request, &kgem->flushing);
+						bo->rq = &_kgem_static_request;
+					} else {
+						kgem_bo_move_to_snoop(kgem, bo);
+					}
+					continue;
+				}
+
+				if (!bo->reusable) {
 					DBG(("%s: closing %d\n",
 					     __FUNCTION__, bo->handle));
 					kgem_bo_free(kgem, bo);
+					continue;
+				}
+
+				if (!bo->needs_flush) {
+					if (kgem_bo_set_purgeable(kgem, bo)) {
+						kgem_bo_move_to_inactive(kgem, bo);
+						retired = true;
+					} else {
+						DBG(("%s: closing %d\n",
+						     __FUNCTION__, bo->handle));
+						kgem_bo_free(kgem, bo);
+					}
 				}
 			}
-		}
 
-		assert(rq->bo->rq == NULL);
-		assert(list_is_empty(&rq->bo->request));
+			assert(rq->bo->rq == NULL);
+			assert(list_is_empty(&rq->bo->request));
 
-		if (--rq->bo->refcnt == 0) {
-			if (kgem_bo_set_purgeable(kgem, rq->bo)) {
-				kgem_bo_move_to_inactive(kgem, rq->bo);
-				retired = true;
-			} else {
-				DBG(("%s: closing %d\n",
-				     __FUNCTION__, rq->bo->handle));
-				kgem_bo_free(kgem, rq->bo);
+			if (--rq->bo->refcnt == 0) {
+				if (kgem_bo_set_purgeable(kgem, rq->bo)) {
+					kgem_bo_move_to_inactive(kgem, rq->bo);
+					retired = true;
+				} else {
+					DBG(("%s: closing %d\n",
+					     __FUNCTION__, rq->bo->handle));
+					kgem_bo_free(kgem, rq->bo);
+				}
 			}
+
+			__kgem_request_free(rq);
+			kgem->num_requests--;
 		}
 
-		__kgem_request_free(rq);
+#if HAS_DEBUG_FULL
+		{
+			int count = 0;
+
+			list_for_each_entry(bo, &kgem->requests[n], request)
+				count++;
+
+			bo = NULL;
+			if (!list_is_empty(&kgem->requests[n]))
+				bo = list_first_entry(&kgem->requests[n],
+						      struct kgem_request,
+						      list)->bo;
+
+			ErrorF("%s: ring=%d, %d outstanding requests, oldest=%d\n",
+			       __FUNCTION__, n, count, bo ? bo->handle : 0);
+		}
+#endif
 	}
 
 #if HAS_DEBUG_FULL
 	{
 		int count = 0;
 
-		list_for_each_entry(bo, &kgem->requests, request)
-			count++;
-
-		bo = NULL;
-		if (!list_is_empty(&kgem->requests))
-			bo = list_first_entry(&kgem->requests,
-					      struct kgem_request,
-					      list)->bo;
+		for (n = 0; n < ARRAY_SIZE(kgem->requests); n++)
+			list_for_each_entry(bo, &kgem->requests[n], request)
+				count++;
 
-		ErrorF("%s: %d outstanding requests, oldest=%d\n",
-		       __FUNCTION__, count, bo ? bo->handle : 0);
+		assert(count == kgem->num_requests);
 	}
 #endif
 
@@ -1743,11 +1762,12 @@ bool kgem_retire(struct kgem *kgem)
 	DBG(("%s\n", __FUNCTION__));
 
 	retired |= kgem_retire__flushing(kgem);
-	retired |= kgem_retire__requests(kgem);
+	if (kgem->num_requests)
+		retired |= kgem_retire__requests(kgem);
 	retired |= kgem_retire__buffers(kgem);
 
 	kgem->need_retire =
-		!list_is_empty(&kgem->requests) ||
+		kgem->num_requests ||
 		!list_is_empty(&kgem->flushing);
 	DBG(("%s -- retired=%d, need_retire=%d\n",
 	     __FUNCTION__, retired, kgem->need_retire));
@@ -1759,20 +1779,29 @@ bool kgem_retire(struct kgem *kgem)
 
 bool __kgem_is_idle(struct kgem *kgem)
 {
-	struct kgem_request *rq;
+	int n;
 
-	assert(!list_is_empty(&kgem->requests));
+	assert(kgem->num_requests);
 
-	rq = list_last_entry(&kgem->requests, struct kgem_request, list);
-	if (kgem_busy(kgem, rq->bo->handle)) {
-		DBG(("%s: last requests handle=%d still busy\n",
-		     __FUNCTION__, rq->bo->handle));
-		return false;
-	}
+	for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) {
+		struct kgem_request *rq;
+
+		if (list_is_empty(&kgem->requests[n]))
+			continue;
+
+		rq = list_last_entry(&kgem->requests[n],
+				     struct kgem_request, list);
+		if (kgem_busy(kgem, rq->bo->handle)) {
+			DBG(("%s: last requests handle=%d still busy\n",
+			     __FUNCTION__, rq->bo->handle));
+			return false;
+		}
 
-	DBG(("%s: gpu idle (handle=%d)\n", __FUNCTION__, rq->bo->handle));
+		DBG(("%s: ring=%d idle (handle=%d)\n",
+		     __FUNCTION__, n, rq->bo->handle));
+	}
 	kgem_retire__requests(kgem);
-	assert(list_is_empty(&kgem->requests));
+	assert(kgem->num_requests == 0);
 	return true;
 }
 
@@ -1834,8 +1863,9 @@ static void kgem_commit(struct kgem *kgem)
 
 		gem_close(kgem->fd, rq->bo->handle);
 	} else {
-		list_add_tail(&rq->list, &kgem->requests);
+		list_add_tail(&rq->list, &kgem->requests[rq->ring]);
 		kgem->need_throttle = kgem->need_retire = 1;
+		kgem->num_requests++;
 	}
 
 	kgem->next_request = NULL;
@@ -1975,31 +2005,36 @@ decouple:
 
 static void kgem_cleanup(struct kgem *kgem)
 {
-	while (!list_is_empty(&kgem->requests)) {
-		struct kgem_request *rq;
+	int n;
 
-		rq = list_first_entry(&kgem->requests,
-				      struct kgem_request,
-				      list);
-		while (!list_is_empty(&rq->buffers)) {
-			struct kgem_bo *bo;
+	for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) {
+		while (!list_is_empty(&kgem->requests[n])) {
+			struct kgem_request *rq;
 
-			bo = list_first_entry(&rq->buffers,
-					      struct kgem_bo,
-					      request);
+			rq = list_first_entry(&kgem->requests[n],
+					      struct kgem_request,
+					      list);
+			while (!list_is_empty(&rq->buffers)) {
+				struct kgem_bo *bo;
 
-			list_del(&bo->request);
-			bo->rq = NULL;
-			bo->exec = NULL;
-			bo->domain = DOMAIN_NONE;
-			bo->dirty = false;
-			if (bo->refcnt == 0)
-				kgem_bo_free(kgem, bo);
-		}
+				bo = list_first_entry(&rq->buffers,
+						      struct kgem_bo,
+						      request);
 
-		__kgem_request_free(rq);
+				list_del(&bo->request);
+				bo->rq = NULL;
+				bo->exec = NULL;
+				bo->domain = DOMAIN_NONE;
+				bo->dirty = false;
+				if (bo->refcnt == 0)
+					kgem_bo_free(kgem, bo);
+			}
+
+			__kgem_request_free(rq);
+		}
 	}
 
+	kgem->num_requests = 0;
 	kgem_close_inactive(kgem);
 }
 
@@ -2169,6 +2204,7 @@ void _kgem_submit(struct kgem *kgem)
 		rq->bo->exec = &kgem->exec[i];
 		rq->bo->rq = rq; /* useful sanity check */
 		list_add(&rq->bo->request, &rq->buffers);
+		rq->ring = kgem->ring == KGEM_BLT;
 
 		kgem_fixup_self_relocs(kgem, rq->bo);
 
@@ -2366,12 +2402,12 @@ bool kgem_expire_cache(struct kgem *kgem)
 	}
 #ifdef DEBUG_MEMORY
 	{
-		long size = 0;
-		int count = 0;
+		long snoop_size = 0;
+		int snoop_count = 0;
 		list_for_each_entry(bo, &kgem->snoop, list)


Reply to: