summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-10-20 17:37:41 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-10-20 17:58:55 +0100
commit1229bf6a690e7f315ab22957da23481f58515ff9 (patch)
tree361e8c5363092c5efe9466541aa3753084413893
parent3526d83e460ce6410f23f59d1315793ff9607253 (diff)
sna: Actually apply the composite offset for the self-copy
I translated the region to copy by the composite pixmap offset, only failed to use the translated region for the actual copy command (using instead the original boxes). Fix that mistake by avoiding the temporary region entirely and applying the translation inplace. We also have to be careful in the case of copying between two composited windows that have different offsets into the same screen pixmap. This fixes the regression introduced with a3466c8b69af (sna/accel: Implement a simpler path for CopyArea between the same pixmaps). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/sna_accel.c23
-rw-r--r--src/sna/sna_damage.c153
-rw-r--r--src/sna/sna_damage.h10
3 files changed, 175 insertions, 11 deletions
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 22f54682..8153d342 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -1254,7 +1254,6 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
PixmapPtr pixmap = get_drawable_pixmap(src);
struct sna_pixmap *priv = sna_pixmap(pixmap);
int alu = gc ? gc->alu : GXcopy;
- RegionRec region;
int16_t tx, ty;
if (n == 0 || (dx | dy) == 0)
@@ -1266,10 +1265,11 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
dx, dy, alu,
pixmap->drawable.width, pixmap->drawable.height));
- pixman_region_init_rects(&region, box, n);
- get_drawable_deltas(dst, pixmap, &tx, &ty);
- RegionTranslate(&region, tx, ty);
- assert_pixmap_contains_box(pixmap, RegionExtents(&region));
+ get_drawable_deltas(src, pixmap, &tx, &ty);
+ dx += tx;
+ dy += ty;
+ if (dst != src)
+ get_drawable_deltas(dst, pixmap, &tx, &ty);
if (priv && priv->gpu_bo) {
if (!sna_pixmap_move_to_gpu(pixmap)) {
@@ -1280,14 +1280,14 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
if (!sna->render.copy_boxes(sna, alu,
pixmap, priv->gpu_bo, dx, dy,
- pixmap, priv->gpu_bo, 0, 0,
+ pixmap, priv->gpu_bo, tx, ty,
box, n)) {
DBG(("%s: fallback - accelerated copy boxes failed\n",
__FUNCTION__));
goto fallback;
}
- sna_damage_add(&priv->gpu_damage, &region);
+ sna_damage_add_boxes(&priv->gpu_damage, box, n, tx, ty);
} else {
FbBits *dst_bits, *src_bits;
int stride, bpp;
@@ -1299,7 +1299,9 @@ fallback:
stride = pixmap->devKind;
bpp = pixmap->drawable.bitsPerPixel;
if (alu == GXcopy && !reverse && !upsidedown && bpp >= 8) {
- dst_bits = pixmap->devPrivate.ptr;
+ dst_bits = (FbBits *)
+ ((char *)pixmap->devPrivate.ptr +
+ ty * stride + tx * bpp / 8);
src_bits = (FbBits *)
((char *)pixmap->devPrivate.ptr +
dy * stride + dx * bpp / 8);
@@ -1323,9 +1325,9 @@ fallback:
stride,
(box->x1 + dx) * bpp,
- dst_bits + box->y1 * stride,
+ dst_bits + (box->y1 + ty) * stride,
stride,
- box->x1 * bpp,
+ (box->x1 + tx) * bpp,
(box->x2 - box->x1) * bpp,
(box->y2 - box->y1),
@@ -1336,7 +1338,6 @@ fallback:
}while (--n);
}
}
- RegionUninit(&region);
}
static void
diff --git a/src/sna/sna_damage.c b/src/sna/sna_damage.c
index f6ffef0b..b5d00846 100644
--- a/src/sna/sna_damage.c
+++ b/src/sna/sna_damage.c
@@ -231,6 +231,73 @@ _sna_damage_create_elt(struct sna_damage *damage,
boxes, count * sizeof(BoxRec));
}
+static void
+_sna_damage_create_elt_with_translation(struct sna_damage *damage,
+ enum mode mode,
+ const BoxRec *boxes, int count,
+ int16_t dx, int16_t dy)
+{
+ struct sna_damage_elt *elt;
+ int i;
+
+ DBG((" %s(%s): n=%d, prev=(%s, remain %d)\n", __FUNCTION__,
+ mode == ADD ? "add" : "subtract",
+ damage->n,
+ damage->n ? damage->elts[damage->n-1].mode == ADD ? "add" : "subtract" : "none",
+ damage->last_box ? damage->last_box->remain : 0));
+
+ if (damage->last_box && damage->elts[damage->n-1].mode == mode) {
+ int n;
+ BoxRec *b;
+
+ n = count;
+ if (n > damage->last_box->remain)
+ n = damage->last_box->remain;
+
+ elt = damage->elts + damage->n-1;
+ b = elt->box + elt->n;
+ for (i = 0; i < n; i++) {
+ b[i].x1 = boxes[i].x1 + dx;
+ b[i].x2 = boxes[i].x2 + dx;
+ b[i].y1 = boxes[i].y1 + dy;
+ b[i].y2 = boxes[i].y2 + dy;
+ }
+ elt->n += n;
+ damage->last_box->remain -= n;
+ if (damage->last_box->remain == 0)
+ damage->last_box = NULL;
+
+ count -=n;
+ boxes += n;
+ if (count == 0)
+ return;
+ }
+
+ if (damage->n == damage->size) {
+ int newsize = damage->size * 2;
+ struct sna_damage_elt *newelts = realloc(damage->elts,
+ newsize*sizeof(*elt));
+ if (newelts == NULL)
+ return;
+
+ damage->elts = newelts;
+ damage->size = newsize;
+ }
+
+ DBG((" %s(): new elt\n", __FUNCTION__));
+
+ elt = damage->elts + damage->n++;
+ elt->mode = mode;
+ elt->n = count;
+ elt->box = _sna_damage_create_boxes(damage, count);
+ for (i = 0; i < count; i++) {
+ elt->box[i].x1 = boxes[i].x1 + dx;
+ elt->box[i].x2 = boxes[i].x2 + dx;
+ elt->box[i].y1 = boxes[i].y1 + dy;
+ elt->box[i].y2 = boxes[i].y2 + dy;
+ }
+}
+
static void free_list(struct list *head)
{
while (!list_is_empty(head)) {
@@ -387,6 +454,92 @@ fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
}
#endif
+inline static struct sna_damage *
+__sna_damage_add_boxes(struct sna_damage *damage,
+ const BoxRec *box, int n,
+ int16_t dx, int16_t dy)
+{
+ BoxRec extents;
+ int i;
+
+ assert(n);
+
+ extents = box[0];
+ for (i = 1; i < n; i++) {
+ if (extents.x1 > box[i].x1)
+ extents.x1 = box[i].x1;
+ if (extents.x2 < box[i].x2)
+ extents.x2 = box[i].x2;
+ if (extents.y1 > box[i].y1)
+ extents.y1 = box[i].y1;
+ if (extents.y2 < box[i].y2)
+ extents.y2 = box[i].y2;
+ }
+
+ if (extents.y2 <= extents.y1 || extents.x2 <= extents.x1)
+ return damage;
+
+ extents.x1 += dx;
+ extents.x2 += dx;
+ extents.y1 += dy;
+ extents.y2 += dy;
+
+ if (!damage)
+ damage = _sna_damage_create();
+
+ if (damage->all)
+ return damage;
+
+ if (damage->mode == SUBTRACT)
+ __sna_damage_reduce(damage);
+ damage->mode = ADD;
+
+ if (pixman_region_contains_rectangle(&damage->region,
+ &extents) == PIXMAN_REGION_IN)
+ return damage;
+
+ _sna_damage_create_elt_with_translation(damage, ADD, box, n, dx, dy);
+
+ if (damage->extents.x1 > extents.x1)
+ damage->extents.x1 = extents.x1;
+ if (damage->extents.x2 < extents.x2)
+ damage->extents.x2 = extents.x2;
+
+ if (damage->extents.y1 > extents.y1)
+ damage->extents.y1 = extents.y1;
+ if (damage->extents.y2 < extents.y2)
+ damage->extents.y2 = extents.y2;
+
+ return damage;
+}
+
+#if DEBUG_DAMAGE
+struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
+ const BoxRec *box, int n,
+ int16_t dx, int16_t dy)
+{
+ char damage_buf[1000];
+
+ DBG(("%s(%s + [(%d, %d), (%d, %d) ... x %d])\n", __FUNCTION__,
+ _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
+ box->x1, box->y1, box->x2, box->y2, n));
+
+ damage = __sna_damage_add_box(damage, boxes, n, dx, dy);
+
+ ErrorF(" = %s\n",
+ _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
+
+ return damage;
+}
+#else
+struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
+ const BoxRec *box, int n,
+ int16_t dx, int16_t dy)
+{
+ return __sna_damage_add_boxes(damage, box, n, dx, dy);
+}
+#endif
+
inline static struct sna_damage *__sna_damage_add_box(struct sna_damage *damage,
const BoxRec *box)
{
diff --git a/src/sna/sna_damage.h b/src/sna/sna_damage.h
index 5fb9aef0..454ad84a 100644
--- a/src/sna/sna_damage.h
+++ b/src/sna/sna_damage.h
@@ -34,6 +34,16 @@ static inline void sna_damage_add_box(struct sna_damage **damage,
*damage = _sna_damage_add_box(*damage, box);
}
+struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
+ const BoxRec *box, int n,
+ int16_t dx, int16_t dy);
+static inline void sna_damage_add_boxes(struct sna_damage **damage,
+ const BoxRec *box, int n,
+ int16_t dx, int16_t dy)
+{
+ *damage = _sna_damage_add_boxes(*damage, box, n, dx, dy);
+}
+
struct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
int width, int height);
static inline bool sna_damage_is_all(struct sna_damage **damage,