xf86-video-intel: 5 commits - src/sna/gen6_render.c src/sna/gen7_render.c src/sna/Makefile.am src/sna/sna_accel.c src/sna/sna_acpi.c src/sna/sna_driver.c src/sna/sna.h

Chris Wilson ickle at kemper.freedesktop.org
Fri Sep 6 08:17:02 PDT 2013


 src/sna/Makefile.am   |    1 
 src/sna/gen6_render.c |    8 +
 src/sna/gen7_render.c |   11 ++
 src/sna/sna.h         |   20 ++++
 src/sna/sna_accel.c   |  202 ++++++++++++++++++++++++++++++++++++++++++++------
 src/sna/sna_acpi.c    |  187 ++++++++++++++++++++++++++++++++++++++++++++++
 src/sna/sna_driver.c  |    6 +
 7 files changed, 412 insertions(+), 23 deletions(-)

New commits:
commit 489a93e4cc2e14e25339693933dddf4946717f11
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Sep 6 15:14:46 2013 +0100

    sna/gen6+: Switch to using the BLT more often when off AC
    
    The BLT is more power-efficient for the operations it can handle, so use
    it when possible (following the usual caveats) if we know we only have
    battery power.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c
index 52eabca..52e0171 100644
--- a/src/sna/gen6_render.c
+++ b/src/sna/gen6_render.c
@@ -1899,7 +1899,10 @@ static inline bool untiled_tlb_miss(struct kgem_bo *bo)
 
 static int prefer_blt_bo(struct sna *sna, struct kgem_bo *bo)
 {
-	if (RQ_IS_BLT(bo->rq))
+	if (bo->rq)
+		return RQ_IS_BLT(bo->rq);
+
+	if (sna->flags & SNA_POWERSAVE)
 		return true;
 
 	return bo->tiling == I915_TILING_NONE || bo->scanout;
@@ -1909,6 +1912,9 @@ inline static bool prefer_blt_ring(struct sna *sna,
 				   struct kgem_bo *bo,
 				   unsigned flags)
 {
+	if (sna->flags & SNA_POWERSAVE)
+		return true;
+
 	return can_switch_to_blt(sna, bo, flags);
 }
 
diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c
index be7dda0..c0d22df 100644
--- a/src/sna/gen7_render.c
+++ b/src/sna/gen7_render.c
@@ -2168,7 +2168,10 @@ static inline bool untiled_tlb_miss(struct kgem_bo *bo)
 
 static int prefer_blt_bo(struct sna *sna, struct kgem_bo *bo)
 {
-	if (RQ_IS_BLT(bo->rq))
+	if (bo->rq)
+		return RQ_IS_BLT(bo->rq);
+
+	if (sna->flags & SNA_POWERSAVE)
 		return true;
 
 	return bo->tiling == I915_TILING_NONE || (bo->scanout && !sna->kgem.has_wt);
@@ -2178,6 +2181,9 @@ inline static bool prefer_blt_ring(struct sna *sna,
 				   struct kgem_bo *bo,
 				   unsigned flags)
 {
+	if (sna->flags & SNA_POWERSAVE)
+		return true;
+
 	if (kgem_bo_is_render(bo))
 		return false;
 
@@ -2187,6 +2193,9 @@ inline static bool prefer_blt_ring(struct sna *sna,
 inline static bool prefer_render_ring(struct sna *sna,
 				      struct kgem_bo *bo)
 {
+	if (sna->flags & SNA_POWERSAVE)
+		return false;
+
 	if (sna->render_state.gen7.info->gt < 2)
 		return false;
 
commit f2ed1ac7b9807106405bbc2b18159a39c2d407d0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Sep 6 15:07:43 2013 +0100

    sna: Listen to ACPI events for power state notifications
    
    When on-battery, we would prefer to use more power efficient operations.
    For example, the BCS is far more economical to more data around with, but
    it doesn't have quite the same throughput as the hungry RCS. (Not that
    there is any reason why, the BCS is supposed to run at full memory
    speed, unfortunately that is main memory speed and not the caches...)
    
    Note: that X already listens to acpid for video switch notifications, it
    would be useful if we could extend that interface to emit power
    notifications as well.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/Makefile.am b/src/sna/Makefile.am
index 1c5dda0..5cf1cbf 100644
--- a/src/sna/Makefile.am
+++ b/src/sna/Makefile.am
@@ -47,6 +47,7 @@ libsna_la_SOURCES = \
 	rop.h \
 	sna.h \
 	sna_accel.c \
+	sna_acpi.c \
 	sna_blt.c \
 	sna_composite.c \
 	sna_cpu.c \
diff --git a/src/sna/sna.h b/src/sna/sna.h
index 5889c5f..a081c0e 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -231,6 +231,8 @@ struct sna {
 #define SNA_FORCE_SHADOW	0x20
 #define SNA_FLUSH_GTT		0x40
 #define SNA_IS_HOSTED		0x80
+#define SNA_PERFORMANCE		0x100
+#define SNA_POWERSAVE		0x200
 #define SNA_REPROBE		0x80000000
 
 	unsigned cpu_features;
@@ -323,6 +325,13 @@ struct sna {
 	InputHandlerProc uevent_handler;
 #endif
 
+	struct {
+		int fd;
+		uint8_t offset;
+		uint8_t remain;
+		char event[256];
+	} acpi;
+
 	struct sna_render render;
 
 #if DEBUG_MEMORY
@@ -939,6 +948,17 @@ box_intersect(BoxPtr a, const BoxRec *b)
 unsigned sna_cpu_detect(void);
 char *sna_cpu_features_to_string(unsigned features, char *line);
 
+/* sna_acpi.c */
+int sna_acpi_open(void);
+void sna_acpi_init(struct sna *sna);
+void _sna_acpi_wakeup(struct sna *sna);
+static inline void sna_acpi_wakeup(struct sna *sna, void *read_mask)
+{
+	if (sna->acpi.fd >= 0 && FD_ISSET(sna->acpi.fd, (fd_set*)read_mask))
+		_sna_acpi_wakeup(sna);
+}
+void sna_acpi_fini(struct sna *sna);
+
 void sna_threads_init(void);
 int sna_use_threads (int width, int height, int threshold);
 void sna_threads_run(void (*func)(void *arg), void *arg);
diff --git a/src/sna/sna_acpi.c b/src/sna/sna_acpi.c
new file mode 100644
index 0000000..ff7364c
--- /dev/null
+++ b/src/sna/sna_acpi.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2013 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.
+ *
+ * Authors:
+ *    Chris Wilson <chris at chris-wilson.co.uk>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "sna.h"
+
+#define ACPI_SOCKET  "/var/run/acpid.socket"
+
+int sna_acpi_open(void)
+{
+	struct sockaddr_un addr;
+	int fd, ret;
+
+	DBG(("%s\n", __FUNCTION__));
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0)
+		return -1;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strcpy(addr.sun_path, ACPI_SOCKET);
+
+	ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+	if (ret < 0) {
+		close(fd);
+		return -1;
+	}
+
+	DBG(("%s: opened socket to APCI daemon, fd=%d\n", __FUNCTION__, fd));
+
+	return fd;
+}
+
+void _sna_acpi_wakeup(struct sna *sna)
+{
+	char *eol;
+	int n;
+
+	n = read(sna->acpi.fd,
+		 sna->acpi.event + sna->acpi.offset,
+		 sna->acpi.remain);
+	DBG(("%s: read %d bytes from acpid\n", __FUNCTION__, n));
+	if (n <= 0) {
+		/* We will get '0' if we run out of space whilst reading
+		 * one event - that should never happen, so treat it as
+		 * an error and give up.
+		 */
+		if (n < 0)
+			n = errno;
+		switch (n) {
+		case EAGAIN:
+		case EINTR:
+			return;
+		}
+
+		DBG(("%s: error [%d], detaching from acpid\n", __FUNCTION__, n));
+
+		/* XXX reattach later? */
+		RemoveGeneralSocket(sna->acpi.fd);
+		sna_acpi_fini(sna);
+		return;
+	}
+
+	sna->acpi.event[sna->acpi.offset + n] = '\0';
+	sna->acpi.offset += n;
+	sna->acpi.remain -= n;
+
+	DBG(("%s: event string [%d]: '%s'\n", __FUNCTION__, sna->acpi.offset, sna->acpi.event));
+
+	do {
+		eol = strchr(sna->acpi.event, '\n');
+		if (eol == NULL)
+			return;
+
+		if (strncmp(sna->acpi.event, "ac_adapter", 10) == 0) {
+			char *space = sna->acpi.event;
+			int state = -1;
+
+			/* ac_adapter ACAD 00000080 00000001 */
+
+			space = strchr(space, ' ');
+			if (space)
+				space = strchr(space + 1, ' ');
+			if (space)
+				space = strchr(space + 1, ' ');
+			if (space)
+				state = atoi(space + 1);
+
+			DBG(("%s: ac_adapter event new state=%d\n", __FUNCTION__, state));
+			if (state)
+				sna->flags &= ~SNA_POWERSAVE;
+			else
+				sna->flags |= SNA_POWERSAVE;
+		}
+
+		n = (sna->acpi.event + sna->acpi.offset) - ++eol;
+		memmove(sna->acpi.event, eol, n+1);
+		sna->acpi.offset = n;
+		sna->acpi.remain = sizeof(sna->acpi.event) - 1 - n;
+	} while (n);
+}
+
+static int read_state(const char *path)
+{
+	char buf[80];
+	int i, fd;
+
+	fd = open(path, 0);
+	if (fd < 0)
+		return -1;
+
+	i = read(fd, buf, sizeof(buf)-1);
+	if (i > 0) {
+		buf[i] = '\0';
+		i = atoi(buf);
+	}
+
+	close(fd);
+	return i;
+}
+
+void sna_acpi_init(struct sna *sna)
+{
+	if (sna->acpi.fd < 0)
+		return;
+
+	if (sna->flags & SNA_PERFORMANCE)
+		return;
+
+	DBG(("%s: attaching to acpid\n", __FUNCTION__));
+
+	AddGeneralSocket(sna->acpi.fd);
+	sna->acpi.remain = sizeof(sna->acpi.event) - 1;
+	sna->acpi.offset = 0;
+
+	/* Read initial states */
+	if (read_state("/sys/class/power_supply/ACAD/online") == 0) {
+		DBG(("%s: AC adapter is currently offline\n", __FUNCTION__));
+		sna->flags |= SNA_POWERSAVE;
+	}
+}
+
+void sna_acpi_fini(struct sna *sna)
+{
+	if (sna->acpi.fd < 0)
+		return;
+
+	close(sna->acpi.fd);
+	sna->acpi.fd = -1;
+
+	sna->flags &= ~SNA_POWERSAVE;
+}
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index 44eea33..4624998 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -421,6 +421,7 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
 		scrn->driverPrivate = sna;
 
 		sna->cpu_features = sna_cpu_detect();
+		sna->acpi.fd = sna_acpi_open();
 	}
 	sna = to_sna(scrn);
 	sna->scrn = scrn;
@@ -557,6 +558,8 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
 	if (sna_option_cast_to_bool(sna, OPTION_DRI, TRUE))
 		sna->dri_available = !!xf86LoadSubModule(scrn, "dri2");
 
+	sna_acpi_init(sna);
+
 	return TRUE;
 
 cleanup:
@@ -601,6 +604,8 @@ sna_wakeup_handler(WAKEUPHANDLER_ARGS_DECL)
 	if ((int)result < 0)
 		return;
 
+	sna_acpi_wakeup(sna, read_mask);
+
 	sna->WakeupHandler(WAKEUPHANDLER_ARGS);
 
 	sna_accel_wakeup_handler(sna);
@@ -1016,6 +1021,7 @@ static void sna_free_screen(FREE_SCREEN_ARGS_DECL)
 	scrn->driverPrivate = (void *)((uintptr_t)sna->info | 1);
 
 	sna_mode_fini(sna);
+	sna_acpi_fini(sna);
 	free(sna);
 
 	intel_put_device(scrn);
commit 56f532db2c9563c6d70da388f987f26530dcd38d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Sep 6 12:48:06 2013 +0100

    sna: Prefer to reuse CPU bo if it was last active rather than inplace uploads
    
    This helps short-circuit writes followed by immediate reads.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 39ae033..8a7a249 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -1447,23 +1447,38 @@ static inline bool pixmap_inplace(struct sna *sna,
 	if (FORCE_INPLACE)
 		return FORCE_INPLACE > 0;
 
-	if (wedged(sna) && !priv->pinned)
+	if (wedged(sna) && !priv->pinned) {
+		DBG(("%s: no, wedged and unpinned; pull pixmap back to CPU\n", __FUNCTION__));
 		return false;
+	}
 
 	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
-		if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ))
+		if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) {
+			DBG(("%s: no, GPU bo is busy\n", __FUNCTION__));
 			return false;
+		}
 
-		if ((flags & MOVE_READ) == 0)
+		if ((flags & MOVE_READ) == 0) {
+			DBG(("%s: %s, GPU bo is busy, but not reading\n", __FUNCTION__, priv->pinned ? "no" : "yes"));
 			return !priv->pinned;
+		}
 	}
 
-	if (priv->mapped)
+	if (priv->mapped) {
+		DBG(("%s: %s, already mapped\n", __FUNCTION__, has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no"));
 		return has_coherent_map(sna, priv->gpu_bo, flags);
+	}
+
+	if (priv->cpu_bo && priv->cpu) {
+		DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__));
+		return false;
+	}
 
 	if (flags & MOVE_READ &&
-	    (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL))
+	    (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL)) {
+		DBG(("%s:, no, reading and has CPU damage\n", __FUNCTION__));
 		return false;
+	}
 
 	return (pixmap->devKind * pixmap->drawable.height >> 12) >
 		sna->kgem.half_cpu_cache_pages;
@@ -2206,6 +2221,11 @@ static inline bool region_inplace(struct sna *sna,
 		return true;
 	}
 
+	if (priv->cpu_bo && priv->cpu) {
+		DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__));
+		return false;
+	}
+
 	DBG(("%s: (%dx%d), inplace? %d\n",
 	     __FUNCTION__,
 	     region->extents.x2 - region->extents.x1,
commit 7656755c9d5ac83848f924df3f6faa79a2a7955a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Sep 6 12:18:51 2013 +0100

    sna: Keep the CPU bo around if it was recently active
    
    Rather than always switching over to using the GPU bo and immediately
    discarding the CPU bo, keep it around as we may want to reuse the cached
    data.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 9703370..39ae033 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -520,11 +520,14 @@ static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
 		free(priv->ptr);
 }
 
-static void sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
+static void sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool active)
 {
 	assert(priv->cpu_damage == NULL);
 	assert(list_is_empty(&priv->flush_list));
 
+	if (active)
+		return;
+
 	if (IS_STATIC_PTR(priv->ptr))
 		return;
 
@@ -1873,12 +1876,12 @@ _sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags)
 				       pixmap->drawable.height);
 			sna_damage_destroy(&priv->cpu_damage);
 			priv->clear = false;
-			priv->cpu = false;
 			list_del(&priv->flush_list);
 
 			assert(!priv->shm);
 			assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush);
-			sna_pixmap_free_cpu(sna, priv);
+			sna_pixmap_free_cpu(sna, priv, priv->cpu);
+			priv->cpu = false;
 
 			assert_pixmap_damage(pixmap);
 			return true;
@@ -1894,7 +1897,7 @@ skip_inplace_map:
 			assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL);
 
 			sna_damage_destroy(&priv->cpu_damage);
-			sna_pixmap_free_cpu(sna, priv);
+			sna_pixmap_free_cpu(sna, priv, false);
 
 			if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, false))
 				return false;
@@ -1934,7 +1937,7 @@ skip_inplace_map:
 					       pixmap->drawable.width,
 					       pixmap->drawable.height);
 				sna_damage_destroy(&priv->cpu_damage);
-				sna_pixmap_free_cpu(sna, priv);
+				sna_pixmap_free_cpu(sna, priv, priv->cpu);
 				list_del(&priv->flush_list);
 				priv->clear = false;
 			}
@@ -1966,7 +1969,6 @@ skip_inplace_map:
 		pixmap->devPrivate.ptr =
 			kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
 		if (pixmap->devPrivate.ptr != NULL) {
-			priv->cpu = true;
 			priv->mapped = true;
 			pixmap->devKind = priv->gpu_bo->pitch;
 			if (flags & MOVE_WRITE) {
@@ -1975,10 +1977,11 @@ skip_inplace_map:
 					       pixmap->drawable.width,
 					       pixmap->drawable.height);
 				sna_damage_destroy(&priv->cpu_damage);
-				sna_pixmap_free_cpu(sna, priv);
+				sna_pixmap_free_cpu(sna, priv, priv->cpu);
 				list_del(&priv->flush_list);
 				priv->clear = false;
 			}
+			priv->cpu = true;
 
 			assert(IS_CPU_MAP(priv->gpu_bo->map));
 			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
@@ -1995,7 +1998,7 @@ skip_inplace_map:
 	    priv->cpu_bo && !priv->cpu_bo->flush &&
 	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
 		assert(!priv->shm);
-		sna_pixmap_free_cpu(sna, priv);
+		sna_pixmap_free_cpu(sna, priv, false);
 	}
 
 	if (pixmap->devPrivate.ptr == NULL &&
@@ -2423,7 +2426,7 @@ sna_drawable_move_region_to_cpu(DrawablePtr drawable,
 			sna_damage_all(&priv->gpu_damage,
 				       pixmap->drawable.width,
 				       pixmap->drawable.height);
-			sna_pixmap_free_cpu(sna, priv);
+			sna_pixmap_free_cpu(sna, priv, false);
 		}
 	}
 
@@ -3088,7 +3091,6 @@ done:
 		list_del(&priv->flush_list);
 	if (flags & MOVE_WRITE) {
 		priv->clear = false;
-		priv->cpu = false;
 		if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
 		    priv->cpu_damage == NULL &&
 		    box_inplace(pixmap, &r.extents)) {
@@ -3101,7 +3103,8 @@ done:
 				       pixmap->drawable.height);
 		}
 		if (DAMAGE_IS_ALL(priv->gpu_damage))
-			sna_pixmap_free_cpu(sna, priv);
+			sna_pixmap_free_cpu(sna, priv, priv->cpu);
+		priv->cpu = false;
 	}
 
 	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
@@ -3760,7 +3763,8 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
 		sna_damage_all(&priv->gpu_damage,
 			       pixmap->drawable.width,
 			       pixmap->drawable.height);
-		sna_pixmap_free_cpu(sna, priv);
+		sna_pixmap_free_cpu(sna, priv,
+				    (priv->create & KGEM_CAN_CREATE_LARGE) ? false : priv->cpu);
 	}
 done:
 	list_del(&priv->flush_list);
@@ -3769,7 +3773,7 @@ done:
 			      pixmap->drawable.width,
 			      pixmap->drawable.height);
 	if (DAMAGE_IS_ALL(priv->gpu_damage))
-		sna_pixmap_free_cpu(sna, priv);
+		sna_pixmap_free_cpu(sna, priv, priv->cpu);
 
 active:
 	if (flags & MOVE_WRITE)
@@ -4087,7 +4091,7 @@ try_upload_blt(PixmapPtr pixmap, RegionRec *region,
 		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
 			list_del(&priv->flush_list);
 			sna_damage_destroy(&priv->cpu_damage);
-			sna_pixmap_free_cpu(sna, priv);
+			sna_pixmap_free_cpu(sna, priv, priv->cpu);
 		}
 	}
 
@@ -4199,7 +4203,7 @@ try_upload_tiled_x(PixmapPtr pixmap, RegionRec *region,
 		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
 			list_del(&priv->flush_list);
 			sna_damage_destroy(&priv->cpu_damage);
-			sna_pixmap_free_cpu(sna, priv);
+			sna_pixmap_free_cpu(sna, priv, priv->cpu);
 		}
 	}
 	if (priv->cpu_damage)
commit 9a1f2ab84cfbcc1d37ae21de9a0ce6f1b5768e12
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Sep 6 11:43:24 2013 +0100

    sna: Try an inplace CopyArea fallback first
    
    This applies the copy-from-tiled-X GetImage optimistion to the
    ShmGetImage paths - when we don't have userptr available.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 33acb30..9703370 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -5008,6 +5008,139 @@ static bool use_shm_bo(struct sna *sna,
 	return false;
 }
 
+static bool
+sna_damage_contains_box__no_reduce__offset(struct sna_damage *damage,
+					   const BoxRec *extents,
+					   int16_t dx, int16_t dy)
+{
+	BoxRec _extents;
+
+	if (dx | dy) {
+		_extents.x1 = extents->x1 + dx;
+		_extents.x2 = extents->x2 + dx;
+		_extents.y1 = extents->y1 + dy;
+		_extents.y2 = extents->y2 + dy;
+		extents = &_extents;
+	}
+
+	return sna_damage_contains_box__no_reduce(damage, extents);
+}
+
+static bool
+sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
+			PixmapPtr src_pixmap, struct sna_pixmap *src_priv,
+			int dx, int dy,
+			PixmapPtr dst_pixmap, struct sna_pixmap *dst_priv)
+{
+	const BoxRec *box;
+	char *src;
+	int n;
+
+	assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel);
+
+	if (alu != GXcopy) {
+		DBG(("%s - no, complex alu [%d]\n", __FUNCTION__, alu));
+		return false;
+	}
+
+	if (!USE_INPLACE) {
+		DBG(("%s - no, compile time disabled\n", __FUNCTION__));
+		return false;
+	}
+
+	if (src_priv == NULL || src_priv->gpu_bo == NULL) {
+		DBG(("%s - no, no src GPU bo\n", __FUNCTION__));
+		return false;
+	}
+
+	if (dst_priv == src_priv) {
+		DBG(("%s - no, dst == src\n", __FUNCTION__));
+		return false;
+	}
+
+	switch (src_priv->gpu_bo->tiling) {
+	case I915_TILING_Y:
+		DBG(("%s - no, bad src tiling [Y]\n", __FUNCTION__));
+		return false;
+	case I915_TILING_X:
+		if (!sna->kgem.memcpy_from_tiled_x) {
+			DBG(("%s - no, bad src tiling [X]\n", __FUNCTION__));
+			return false;
+		}
+	default:
+		break;
+	}
+
+	if (!kgem_bo_can_map__cpu(&sna->kgem, src_priv->gpu_bo, false)) {
+		DBG(("%s - no, cannot map src for reads into the CPU\n", __FUNCTION__));
+		return false;
+	}
+
+	if (src_priv->gpu_damage == NULL ||
+	    !(DAMAGE_IS_ALL(src_priv->gpu_damage) ||
+	      sna_damage_contains_box__no_reduce__offset(src_priv->gpu_damage,
+							 &region->extents,
+							 dx, dy))) {
+		DBG(("%s - no, src is not damaged on the GPU\n", __FUNCTION__));
+		return false;
+	}
+
+	assert(sna_damage_contains_box(src_priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
+	assert(sna_damage_contains_box(src_priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
+
+	src = kgem_bo_map__cpu(&sna->kgem, src_priv->gpu_bo);
+	if (src == NULL) {
+		DBG(("%s - no, map failed\n", __FUNCTION__));
+		return false;
+	}
+
+	if (dst_priv &&
+	    !sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
+					     region, MOVE_WRITE | MOVE_INPLACE_HINT)) {
+		DBG(("%s - no, dst sync failed\n", __FUNCTION__));
+		return false;
+	}
+
+	kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC);
+
+	box = RegionRects(region);
+	n = RegionNumRects(region);
+	if (src_priv->gpu_bo->tiling) {
+		DBG(("%s: copy from a tiled CPU map\n", __FUNCTION__));
+		do {
+			memcpy_from_tiled_x(&sna->kgem, src, dst_pixmap->devPrivate.ptr,
+					    src_pixmap->drawable.bitsPerPixel,
+					    src_priv->gpu_bo->pitch,
+					    dst_pixmap->devKind,
+					    box->x1 + dx, box->y1 + dy,
+					    box->x1, box->y1,
+					    box->x2 - box->x1, box->y2 - box->y1);
+			box++;
+		} while (--n);
+	} else {
+		DBG(("%s: copy from a linear CPU map\n", __FUNCTION__));
+		do {
+			memcpy_blt(src, dst_pixmap->devPrivate.ptr,
+				   src_pixmap->drawable.bitsPerPixel,
+				   src_priv->gpu_bo->pitch,
+				   dst_pixmap->devKind,
+				   box->x1 + dx, box->y1 + dy,
+				   box->x1, box->y1,
+				   box->x2 - box->x1, box->y2 - box->y1);
+			box++;
+		} while (--n);
+	}
+
+	if (!src_priv->shm) {
+		src_pixmap->devPrivate.ptr = src;
+		src_pixmap->devKind = src_priv->gpu_bo->pitch;
+		src_priv->mapped = true;
+		src_priv->cpu = true;
+	}
+
+	return true;
+}
+
 static void
 sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
 	       RegionPtr region, int dx, int dy,
@@ -5475,7 +5608,10 @@ fallback:
 				    src_priv->clear_color);
 			box++;
 		} while (--n);
-	} else {
+	} else if (!sna_copy_boxes__inplace(sna, region, alu,
+					    src_pixmap, src_priv,
+					    src_dx, src_dy,
+					    dst_pixmap, dst_priv)) {
 		FbBits *dst_bits, *src_bits;
 		int dst_stride, src_stride;
 


More information about the xorg-commit mailing list