xf86-video-intel: 4 commits - src/sna/kgem.c src/sna/sna_accel.c src/sna/sna_display.c src/sna/sna_dri2.c src/sna/sna_driver.c src/sna/sna.h test/.gitignore test/Makefile.am test/shm-test.c

Chris Wilson ickle at kemper.freedesktop.org
Sun Jun 15 23:06:39 PDT 2014


 src/sna/kgem.c        |    2 
 src/sna/sna.h         |    5 -
 src/sna/sna_accel.c   |   11 ++-
 src/sna/sna_display.c |   44 +++++++++---
 src/sna/sna_dri2.c    |  115 ++++++++++++++++++++-------------
 src/sna/sna_driver.c  |   14 +++-
 test/.gitignore       |    1 
 test/Makefile.am      |    1 
 test/shm-test.c       |  174 ++++++++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 310 insertions(+), 57 deletions(-)

New commits:
commit 243bd26ad31776b2dc45563107e669cf7b45fd91
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jun 15 21:42:10 2014 +0100

    sna: Clear our private hints about front rendering exported bo
    
    Unlike GLXWindows, GLXPixmaps are rendered directly into, without a
    staging copy. Therefore we must treat those carefully when exported and
    clear our hints everytime control passes back to the Client.
    
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=79999
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index a532b4a..7686944 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -148,7 +148,7 @@ struct sna_pixmap {
 	uint32_t clear_color;
 
 #define SOURCE_BIAS 4
-	uint16_t source_count;
+	uint8_t source_count;
 	uint8_t pinned :4;
 #define PIN_SCANOUT 0x1
 #define PIN_DRI2 0x2
@@ -159,7 +159,7 @@ struct sna_pixmap {
 #define MAPPED_NONE 0
 #define MAPPED_GTT 1
 #define MAPPED_CPU 2
-	uint8_t flush :1;
+	uint8_t flush :2;
 	uint8_t shm :1;
 	uint8_t clear :1;
 	uint8_t header :1;
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 930c40a..d48321d 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -16659,8 +16659,15 @@ void sna_accel_flush(struct sna *sna)
 			     priv->pixmap->drawable.serialNumber));
 			assert(priv->flush);
 			if (sna_pixmap_move_to_gpu(priv->pixmap,
-						   MOVE_READ | __MOVE_FORCE))
-				kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
+						   MOVE_READ | __MOVE_FORCE)) {
+				if (priv->flush & 2) {
+					kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
+					sna_damage_all(&priv->gpu_damage, priv->pixmap);
+					assert(priv->cpu_damage == NULL);
+					priv->clear = false;
+					priv->cpu = false;
+				}
+			}
 		}
 		(void)ret;
 	}
diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 4bcc018..9801aab 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -584,7 +584,16 @@ sna_dri2_create_buffer(DrawablePtr draw,
 		if (priv->gpu_bo->exec)
 			sna->kgem.flush = 1;
 
-		priv->flush = true;
+		priv->flush |= 1;
+		if (draw->type == DRAWABLE_PIXMAP) {
+			/* DRI2 renders directly into GLXPixmaps, treat as hostile */
+			kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
+			sna_damage_all(&priv->gpu_damage, pixmap);
+			priv->clear = false;
+			priv->cpu = false;
+			priv->flush |= 2;
+		}
+
 		sna_accel_watch_flush(sna, 1);
 	}
 
commit 500e77d765580e8581c95117b941a4daa940c21e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jun 15 20:55:30 2014 +0100

    sna: Add more DBG to track transitions between CRTC and its shadow or flip bo
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 88f1b91..bf07dbf 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -4437,6 +4437,7 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
 		list_for_each_entry_reverse(bo, &kgem->scanout, list) {
 			assert(bo->scanout);
 			assert(!bo->flush);
+			assert(!bo->refcnt);
 			assert_tiling(kgem, bo);
 
 			if (size > num_pages(bo) || num_pages(bo) > 2*size)
@@ -4484,6 +4485,7 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
 				struct drm_mode_fb_cmd arg;
 
 				assert(bo->scanout);
+				assert(!bo->refcnt);
 
 				if (size > num_pages(bo) || num_pages(bo) > 2*size)
 					continue;
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index e1839fc..5f32978 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -1061,12 +1061,13 @@ static bool wait_for_shadow(struct sna *sna, struct sna_pixmap *priv, unsigned f
 				struct sna_crtc *crtc =
 					list_first_entry(&sna->mode.shadow_crtc, struct sna_crtc, shadow_link);
 
-				DBG(("%s: copying replaced CRTC: (%d, %d), (%d, %d)\n",
+				DBG(("%s: copying replaced CRTC: (%d, %d), (%d, %d), handle=%d\n",
 				     __FUNCTION__,
 				     crtc->base->bounds.x1,
 				     crtc->base->bounds.y1,
 				     crtc->base->bounds.x2,
-				     crtc->base->bounds.y2));
+				     crtc->base->bounds.y2,
+				     crtc->shadow_bo->handle));
 				ret &= sna->render.copy_boxes(sna, GXcopy,
 							      pixmap, crtc->shadow_bo, -crtc->base->bounds.x1, -crtc->base->bounds.y1,
 							      pixmap, priv->gpu_bo, 0, 0,
@@ -1099,8 +1100,8 @@ static bool wait_for_shadow(struct sna *sna, struct sna_pixmap *priv, unsigned f
 				    priv->gpu_bo->tiling,
 				    CREATE_EXACT | CREATE_SCANOUT);
 		if (bo != NULL) {
-			DBG(("%s: replacing still-attached GPU bo\n",
-			     __FUNCTION__));
+			DBG(("%s: replacing still-attached GPU bo handle=%d, flips=%d\n",
+			     __FUNCTION__, priv->gpu_bo->tiling, sna->mode.flip_active));
 
 			RegionUninit(&sna->mode.shadow_region);
 			sna->mode.shadow_region.extents.x1 = 0;
@@ -1145,12 +1146,13 @@ static bool wait_for_shadow(struct sna *sna, struct sna_pixmap *priv, unsigned f
 			list_first_entry(&sna->mode.shadow_crtc, struct sna_crtc, shadow_link);
 		RegionRec region;
 
-		DBG(("%s: copying replaced CRTC: (%d, %d), (%d, %d)\n",
+		DBG(("%s: copying replaced CRTC: (%d, %d), (%d, %d), handle=%d\n",
 		     __FUNCTION__,
 		     crtc->base->bounds.x1,
 		     crtc->base->bounds.y1,
 		     crtc->base->bounds.x2,
-		     crtc->base->bounds.y2));
+		     crtc->base->bounds.y2,
+		     crtc->shadow_bo->handle));
 		ret = sna->render.copy_boxes(sna, GXcopy,
 					     pixmap, crtc->shadow_bo, -crtc->base->bounds.x1, -crtc->base->bounds.y1,
 					     pixmap, bo, 0, 0,
@@ -6306,6 +6308,7 @@ fixup_shadow:
 
 			assert(config->crtc[i]->enabled);
 			assert(crtc->dpms_mode <= DPMSModeOn);
+			assert(crtc->flip_bo == NULL);
 
 			arg.crtc_id = crtc->id;
 			arg.user_data = (uintptr_t)crtc;
@@ -6334,6 +6337,7 @@ fixup_shadow:
 				     crtc_offset, crtc->offset));
 fixup_flip:
 				if (sna_crtc_flip(sna, crtc)) {
+					assert(flip_bo != crtc->bo);
 					assert(crtc->bo->active_scanout);
 					assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
 					crtc->bo->active_scanout--;
@@ -6341,9 +6345,6 @@ fixup_flip:
 
 					crtc->bo = kgem_bo_reference(flip_bo);
 					crtc->bo->active_scanout++;
-
-					if (crtc->shadow_bo)
-						sna_shadow_set_crtc(sna, crtc->base, flip_bo);
 				} else {
 					if (sna->mode.flip_active == 0) {
 						DBG(("%s: abandoning flip attempt\n", __FUNCTION__));
@@ -6375,8 +6376,9 @@ fixup_flip:
 				if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy) == 0) {
 					if (busy.busy) {
 						int mode = KGEM_RENDER;
-						if (busy.busy & (1 << 17))
+						if ((busy.busy & (1 << 16)) == 0)
 							mode = KGEM_BLT;
+						DBG(("%s: marking flip bo as busy [%x -> mode=%d]\n", __FUNCTION__, busy.busy, mode));
 						kgem_bo_mark_busy(&sna->kgem, flip_bo, mode);
 					} else
 						__kgem_bo_clear_busy(flip_bo);
@@ -6436,8 +6438,11 @@ void sna_mode_wakeup(struct sna *sna)
 				assert(crtc->flip_bo);
 				assert(crtc->flip_bo->active_scanout);
 				assert(crtc->flip_bo->refcnt >= crtc->flip_bo->active_scanout);
+				assert(crtc->flip_bo != crtc->bo);
 
 				if (crtc->bo) {
+					DBG(("%s: removing handle=%d from scanout, installing handle=%d\n",
+					     __FUNCTION__, crtc->bo->handle, crtc->flip_bo->handle));
 					assert(crtc->bo->active_scanout);
 					assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
 					crtc->bo->active_scanout--;
diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index efc790f..4bcc018 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -52,6 +52,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <compositeext.h>
 #endif
 
+#define DBG_CAN_FLIP 1
+#define DBG_CAN_XCHG 1
+
 #if DRI2INFOREC_VERSION < 2
 #error DRI2 version supported by the Xserver is too old
 #endif
@@ -191,12 +194,14 @@ sna_dri2_get_back(struct sna *sna,
 		if (!found)
 			c = malloc(sizeof(*c));
 		if (c != NULL) {
-			c->bo = kgem_bo_reference(get_private(back)->bo);
+			c->bo = ref(get_private(back)->bo);
 			c->name = back->name;
 			list_add(&c->link, &info->cache);
+			DBG(("%s: cacheing handle=%d (name=%d)\n", __FUNCTION__, c->bo->handle, c->name));
 		}
 	}
 
+	assert(bo != get_private(back)->bo);
 	kgem_bo_destroy(&sna->kgem, get_private(back)->bo);
 	get_private(back)->bo = bo;
 	back->name = name;
@@ -243,8 +248,8 @@ sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
 	     __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)->bo->refcnt > get_private(buffer)->bo->active_scanout);
 	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) {
@@ -252,6 +257,7 @@ sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
 		sna_dri2_get_back(to_sna_from_drawable(draw), draw, buffer, dri2_chain(draw));
 
 		assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name);
+		assert(get_private(buffer)->bo->refcnt);
 		assert(get_private(buffer)->bo->active_scanout == 0);
 	}
 }
@@ -607,6 +613,7 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
 	assert(private->bo);
 
 	if (private->proxy) {
+		DBG(("%s: destroying proxy\n", __FUNCTION__));
 		_sna_dri2_destroy_buffer(sna, private->proxy);
 		private->pixmap = NULL;
 	}
@@ -788,7 +795,7 @@ static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kg
 	 * the cost of the query.
 	 */
 	mode = KGEM_RENDER;
-	if (busy.busy & (1 << 17))
+	if ((busy.busy & (1 << 16)) == 0)
 		mode = KGEM_BLT;
 	kgem_bo_mark_busy(&sna->kgem, busy.handle == src->handle ? src : dst, mode);
 	_kgem_set_mode(&sna->kgem, mode);
@@ -822,6 +829,11 @@ sna_dri2_copy_fallback(struct sna *sna, int bpp,
 	}
 }
 
+static bool is_front(int attachment)
+{
+	return attachment == DRI2BufferFrontLeft;
+}
+
 static struct kgem_bo *
 __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
 		      DRI2BufferPtr src, DRI2BufferPtr dst,
@@ -848,8 +860,7 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
 	 * now attached to invalid (non-DRI) pixmaps.
 	 */
 
-	assert(dst->attachment == DRI2BufferFrontLeft ||
-	       src->attachment == DRI2BufferFrontLeft);
+	assert(is_front(dst->attachment) || is_front(src->attachment));
 	assert(dst->attachment != src->attachment);
 
 	/* Copy the minimum of the Drawable / src / dst extents */
@@ -884,7 +895,7 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
 	}
 
 	sx = sy = dx = dy = 0;
-	if (dst->attachment == DRI2BufferFrontLeft) {
+	if (is_front(dst->attachment)) {
 		sx = -draw->x;
 		sy = -draw->y;
 	} else {
@@ -896,11 +907,13 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
 		int16_t tx, ty;
 
 		if (is_clipped(&win->clipList, draw)) {
-			DBG(("%s: draw=(%d, %d), delta=(%d, %d), clip.extents=(%d, %d), (%d, %d)\n",
-						__FUNCTION__, draw->x, draw->y,
-						get_drawable_dx(draw), get_drawable_dy(draw),
-						win->clipList.extents.x1, win->clipList.extents.y1,
-						win->clipList.extents.x2, win->clipList.extents.y2));
+			DBG(("%s: draw=(%d, %d), delta=(%d, %d), draw=(%d, %d),(%d, %d), clip.extents=(%d, %d), (%d, %d)\n",
+			     __FUNCTION__, draw->x, draw->y,
+			     get_drawable_dx(draw), get_drawable_dy(draw),
+			     clip.extents.x1, clip.extents.y1,
+			     clip.extents.x2, clip.extents.y2,
+			     win->clipList.extents.x1, win->clipList.extents.y1,
+			     win->clipList.extents.x2, win->clipList.extents.y2));
 
 			assert(region == NULL || region == &clip);
 			pixman_region_intersect(&clip, &win->clipList, &clip);
@@ -913,7 +926,7 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
 		}
 
 		if (get_drawable_deltas(draw, pixmap, &tx, &ty)) {
-			if (dst->attachment == DRI2BufferFrontLeft) {
+			if (is_front(dst->attachment)) {
 				pixman_region_translate(region ?: &clip, tx, ty);
 				sx -= tx;
 				sy -= ty;
@@ -926,16 +939,21 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
 		sync = false;
 
 	src_bo = src_priv->bo;
-	if (src->attachment == DRI2BufferFrontLeft) {
+	assert(src_bo->refcnt);
+	if (is_front(src->attachment)) {
 		struct sna_pixmap *priv;
 
 		priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ);
 		if (priv)
 			src_bo = priv->gpu_bo;
+		DBG(("%s: updated FrontLeft src_bo from handle=%d to handle=%d\n",
+		     __FUNCTION__, src_priv->bo->handle, src_bo->handle));
+		assert(src_bo->refcnt);
 	}
 
 	dst_bo = dst_priv->bo;
-	if (dst->attachment == DRI2BufferFrontLeft) {
+	assert(dst_bo->refcnt);
+	if (is_front(dst->attachment)) {
 		struct sna_pixmap *priv;
 		unsigned int flags;
 
@@ -948,6 +966,9 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
 			damage(pixmap, priv, region);
 			dst_bo = priv->gpu_bo;
 		}
+		DBG(("%s: updated FrontLeft dst_bo from handle=%d to handle=%d\n",
+		     __FUNCTION__, dst_priv->bo->handle, dst_bo->handle));
+		assert(dst_bo->refcnt);
 	} else
 		sync = false;
 
@@ -995,8 +1016,10 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
 		if (sync) { /* STAT! */
 			struct kgem_request *rq = sna->kgem.next_request;
 			kgem_submit(&sna->kgem);
-			if (rq->bo)
-				bo = kgem_bo_reference(rq->bo);
+			if (rq->bo) {
+				bo = ref(rq->bo);
+				DBG(("%s: recording sync fence handle=%d\n", bo->handle));
+			}
 		}
 	}
 
@@ -1220,6 +1243,8 @@ sna_dri2_event_free(struct sna *sna,
 		    DrawablePtr draw,
 		    struct sna_dri2_event *info)
 {
+	DBG(("%s\n", __FUNCTION__));
+
 	if (draw && draw->type == DRAWABLE_WINDOW)
 		sna_dri2_remove_event((WindowPtr)draw, info);
 	_sna_dri2_destroy_buffer(sna, info->front);
@@ -1231,14 +1256,17 @@ sna_dri2_event_free(struct sna *sna,
 		c = list_first_entry(&info->cache, struct dri_bo, link);
 		list_del(&c->link);
 
+		DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
 		if (c->bo)
 			kgem_bo_destroy(&sna->kgem, c->bo);
 
 		free(c);
 	}
 
-	if (info->bo)
+	if (info->bo) {
+		DBG(("%s: releasing batch handle=%d\n", __FUNCTION__, info->bo->handle));
 		kgem_bo_destroy(&sna->kgem, info->bo);
+	}
 
 	free(info);
 }
@@ -1332,6 +1360,10 @@ sna_dri2_flip(struct sna *sna, struct sna_dri2_event *info)
 	get_private(info->back)->bo = tmp_bo;
 	get_private(info->back)->stale = true;
 
+	assert(get_private(info->front)->bo->refcnt);
+	assert(get_private(info->back)->bo->refcnt);
+	assert(get_private(info->front)->bo != get_private(info->back)->bo);
+
 	info->queued = true;
 	return true;
 }
@@ -1348,6 +1380,9 @@ can_flip(struct sna * sna,
 
 	assert((sna->flags & SNA_NO_WAIT) == 0);
 
+	if (!DBG_CAN_FLIP)
+		return false;
+
 	if (draw->type == DRAWABLE_PIXMAP)
 		return false;
 
@@ -1367,14 +1402,6 @@ can_flip(struct sna * sna,
 		return false;
 	}
 
-	if (front->attachment != DRI2BufferFrontLeft) {
-		DBG(("%s: no, front attachment [%d] is not FrontLeft [%d]\n",
-		     __FUNCTION__,
-		     front->attachment,
-		     DRI2BufferFrontLeft));
-		return false;
-	}
-
 	if (sna->mode.shadow_active) {
 		DBG(("%s: no, shadow enabled\n", __FUNCTION__));
 		return false;
@@ -1473,6 +1500,8 @@ can_flip(struct sna * sna,
 		return false;
 	}
 
+	assert(dri2_window(win)->front == NULL);
+
 	return true;
 }
 
@@ -1485,6 +1514,9 @@ can_xchg(struct sna * sna,
 	WindowPtr win = (WindowPtr)draw;
 	PixmapPtr pixmap;
 
+	if (!DBG_CAN_XCHG)
+		return false;
+
 	if (draw->type == DRAWABLE_PIXMAP)
 		return false;
 
@@ -1494,14 +1526,6 @@ can_xchg(struct sna * sna,
 		return false;
 	}
 
-	if (front->attachment != DRI2BufferFrontLeft) {
-		DBG(("%s: no, front attachment [%d] is not FrontLeft [%d]\n",
-		     __FUNCTION__,
-		     front->attachment,
-		     DRI2BufferFrontLeft));
-		return false;
-	}
-
 	pixmap = get_window_pixmap(win);
 
 	DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d, pixmap size=%dx%d\n",
@@ -1582,6 +1606,9 @@ can_xchg_one(struct sna *sna,
 	WindowPtr win = (WindowPtr)draw;
 	PixmapPtr pixmap;
 
+	if (!DBG_CAN_XCHG)
+		return false;
+
 	if ((sna->flags & SNA_TEAR_FREE) == 0) {
 		DBG(("%s: no, requires TearFree\n",
 		     __FUNCTION__));
@@ -1597,14 +1624,6 @@ can_xchg_one(struct sna *sna,
 		return false;
 	}
 
-	if (front->attachment != DRI2BufferFrontLeft) {
-		DBG(("%s: no, front attachment [%d] is not FrontLeft [%d]\n",
-		     __FUNCTION__,
-		     front->attachment,
-		     DRI2BufferFrontLeft));
-		return false;
-	}
-
 	if (memcmp(&win->clipList.extents, &crtc->bounds, sizeof(crtc->bounds))) {
 		DBG(("%s: no, window [(%d, %d), (%d, %d)] does not cover CRTC [(%d, %d), (%d, %d)]\n",
 		     __FUNCTION__,
@@ -1654,6 +1673,7 @@ can_xchg_one(struct sna *sna,
 		return false;
 	}
 
+	assert(win != win->drawable.pScreen->root);
 	DBG(("%s: yes\n", __FUNCTION__));
 	return true;
 }
@@ -1671,6 +1691,7 @@ sna_dri2_exchange_buffers(DrawablePtr draw,
 
 	back_bo = get_private(back)->bo;
 	front_bo = get_private(front)->bo;
+	assert(front_bo != back_bo);
 
 	DBG(("%s: exchange front=%d/%d and back=%d/%d, pixmap=%ld %dx%d\n",
 	     __FUNCTION__,
@@ -1958,6 +1979,7 @@ void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 
 done:
 	sna_dri2_event_free(sna, draw, info);
+	DBG(("%s complete\n", __FUNCTION__));
 }
 
 static bool
commit 0a6a94630f4fec26bed2aefb25de1a165193ff10
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jun 15 14:04:50 2014 +0100

    test: Add a simple SHM test skeleton
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/.gitignore b/test/.gitignore
index 717ef07..b1ede80 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -24,3 +24,4 @@ dri2-swap
 dri2-test
 dri3-test
 present-test
+shm-test
diff --git a/test/Makefile.am b/test/Makefile.am
index e33a6b9..7947b83 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -20,6 +20,7 @@ stress_TESTS = \
 	render-copyarea-size \
 	render-copy-alphaless \
 	mixed-stress \
+	shm-test \
 	$(NULL)
 
 if DRI2
diff --git a/test/shm-test.c b/test/shm-test.c
new file mode 100644
index 0000000..684d142
--- /dev/null
+++ b/test/shm-test.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xlibint.h>
+#include <X11/extensions/Xrender.h>
+#include <X11/extensions/XShm.h>
+#if HAVE_X11_EXTENSIONS_SHMPROTO_H
+#include <X11/extensions/shmproto.h>
+#elif HAVE_X11_EXTENSIONS_SHMSTR_H
+#include <X11/extensions/shmstr.h>
+#else
+#error Failed to find the right header for X11 MIT-SHM protocol definitions
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <pciaccess.h>
+
+static int _x_error_occurred;
+
+static int
+can_use_shm(Display *dpy)
+{
+	int major, minor, has_pixmap;
+
+	if (!XShmQueryExtension(dpy))
+		return 0;
+
+	XShmQueryVersion(dpy, &major, &minor, &has_pixmap);
+	return has_pixmap;
+}
+
+static int test_subpage(Display *dpy)
+{
+	const int width = 10;
+	const int height = 10;
+	uint32_t pixel = 0xffffffff;
+	char *expected;
+	XShmSegmentInfo shm;
+	Pixmap pixmap, source;
+	XGCValues gcv;
+	GC gc;
+
+	printf("Creating %dx%d SHM pixmap\n", width, height);
+	_x_error_occurred = 0;
+
+	expected = malloc(4096);
+	if (expected == NULL)
+		return 0;
+
+	shm.shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
+	if (shm.shmid == -1)
+		return 0;
+
+	shm.shmaddr = shmat(shm.shmid, 0, 0);
+	if (shm.shmaddr == (char *) -1) {
+		shmctl(shm.shmid, IPC_RMID, NULL);
+		return 0;
+	}
+
+	shm.readOnly = False;
+	XShmAttach(dpy, &shm);
+
+	memset(shm.shmaddr, 0xcc, 4096);
+	memset(expected, 0xcc, 4096);
+	memset(expected + 64, 0xff, 4*width * height);
+
+	pixmap = XShmCreatePixmap(dpy, DefaultRootWindow(dpy),
+				  shm.shmaddr + 64, &shm, width, height, 24);
+	XSync(dpy, False);
+	shmctl(shm.shmid, IPC_RMID, NULL);
+
+	source = XCreatePixmap(dpy, DefaultRootWindow(dpy),
+			       width, height, 24);
+
+	gcv.graphics_exposures = False;
+	gcv.subwindow_mode = IncludeInferiors;
+	gcv.foreground = pixel;
+	gcv.function = GXcopy;
+	gcv.fill_style = FillSolid;
+	gc = XCreateGC(dpy, pixmap, GCGraphicsExposures | GCSubwindowMode | GCFillStyle | GCForeground | GCFunction, &gcv);
+
+	XCopyArea(dpy, pixmap, source, gc,
+		  0, 0, width, height, 0, 0);
+
+	XFillRectangle(dpy, source, gc, 0, 0, width, height);
+
+	XCopyArea(dpy, source, pixmap, gc,
+		  0, 0, width, height, 0, 0);
+	XSync(dpy, True);
+
+	if (_x_error_occurred == 0)
+		_x_error_occurred = memcmp(shm.shmaddr, expected, 4096);
+
+	printf("%s: %s\n", __func__, _x_error_occurred ? "failed" : "passed");
+
+	XShmDetach(dpy, &shm);
+	shmdt(shm.shmaddr);
+	free(expected);
+
+
+	return !_x_error_occurred;;
+}
+
+static int
+_check_error_handler(Display     *display,
+		     XErrorEvent *event)
+{
+	printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
+	       DisplayString(display),
+	       event->serial,
+	       event->error_code,
+	       event->request_code,
+	       event->minor_code);
+	_x_error_occurred++;
+	return False; /* ignored */
+}
+
+int main(void)
+{
+	Display *dpy;
+	int error = 0;
+
+	dpy = XOpenDisplay(NULL);
+	if (dpy == NULL)
+		return 77;
+
+	if (DefaultDepth(dpy, DefaultScreen(dpy)) != 24)
+		return 77;
+
+	if (!can_use_shm(dpy))
+		return 0;
+
+	XSetErrorHandler(_check_error_handler);
+
+	error += test_subpage(dpy);
+
+	return !!error;
+}
commit 981aafe797f25aca4977a22f271d387b7fb4ae63
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jun 13 21:41:36 2014 +0100

    sna: Enable TearFree by default for systems with PSR
    
    Panel Self-Refresh requires us to avoid frontbuffer rendering in order
    to be power efficient. This is a job for TearFree!
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index d0bb655..a532b4a 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -419,6 +419,7 @@ struct sna {
 
 bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna);
 bool sna_mode_fake_init(struct sna *sna, int num_fake);
+bool sna_mode_wants_tear_free(struct sna *sna);
 void sna_mode_adjust_frame(struct sna *sna, int x, int y);
 extern void sna_mode_discover(struct sna *sna);
 extern void sna_mode_check(struct sna *sna);
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index eeab349..e1839fc 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -5200,6 +5200,25 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
 	return scrn->modes != NULL;
 }
 
+bool
+sna_mode_wants_tear_free(struct sna *sna)
+{
+	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
+	int i;
+
+	for (i = 0; i < sna->mode.num_real_output; i++) {
+		struct sna_output *output = to_sna_output(config->output[i]);
+		int id = find_property(sna, output, "Panel Self-Refresh");
+		if (id !=-1 && output->prop_values[id] != -1) {
+			DBG(("%s: Panel Self-Refresh detected on %s\n",
+			     __FUNCTION__, config->output[i]->name));
+			return true;
+		}
+	}
+
+	return false;
+}
+
 void
 sna_mode_close(struct sna *sna)
 {
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index 4df93eb..79572a1 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -475,6 +475,18 @@ static void setup_dri(struct sna *sna)
 #endif
 }
 
+static bool enable_tear_free(struct sna *sna)
+{
+	/* Under certain conditions, we should enable TearFree by default,
+	 * for example when the hardware requires pageflipping to run within
+	 * its power/performance budget.
+	 */
+	if (sna_mode_wants_tear_free(sna))
+		return true;
+
+	return ENABLE_TEAR_FREE;
+}
+
 /**
  * This is called before ScreenInit to do any require probing of screen
  * configuration.
@@ -654,7 +666,7 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
 	scrn->currentMode = scrn->modes;
 
 	if (sna->flags & SNA_HAS_FLIP &&
-	    xf86ReturnOptValBool(sna->Options, OPTION_TEAR_FREE, ENABLE_TEAR_FREE))
+	    xf86ReturnOptValBool(sna->Options, OPTION_TEAR_FREE, enable_tear_free(sna)))
 		sna->flags |= SNA_TEAR_FREE;
 	xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "TearFree %sabled\n",
 		   sna->flags & SNA_TEAR_FREE ? "en" : "dis");


More information about the xorg-commit mailing list