summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-01-27 20:12:49 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2012-01-27 20:34:30 +0000
commitd02bd80b2f9f8ee3840be5d8d6b8d389192c57f5 (patch)
tree47cace3a3a9d272aed6c375574ff637868ebb5cf
parentea433995a37f0a9d1579f74029418f22a63a2bc0 (diff)
sna: Use a proxy rather than a temporary bo for too-tall but thin targets
If the render target is thin enough to fit within the 3D pipeline, but is too tall, we can fudge the address of the origin and coordinates to fit within the constaints of the pipeline. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/sna_damage.c20
-rw-r--r--src/sna/sna_damage.h12
-rw-r--r--src/sna/sna_render.c61
-rw-r--r--src/sna/sna_render.h1
4 files changed, 82 insertions, 12 deletions
diff --git a/src/sna/sna_damage.c b/src/sna/sna_damage.c
index d15ec60a..ab825aa5 100644
--- a/src/sna/sna_damage.c
+++ b/src/sna/sna_damage.c
@@ -187,6 +187,11 @@ static struct sna_damage *_sna_damage_create(void)
return damage;
}
+struct sna_damage *sna_damage_create(void)
+{
+ return _sna_damage_create();
+}
+
static bool _sna_damage_create_boxes(struct sna_damage *damage,
int count)
{
@@ -1395,6 +1400,21 @@ int _sna_damage_get_boxes(struct sna_damage *damage, BoxPtr *boxes)
}
#endif
+struct sna_damage *_sna_damage_combine(struct sna_damage *l,
+ struct sna_damage *r,
+ int dx, int dy)
+{
+ if (r->dirty)
+ __sna_damage_reduce(r);
+
+ if (pixman_region_not_empty(&r->region)) {
+ pixman_region_translate(&r->region, dx, dy);
+ l = __sna_damage_add(l, &r->region);
+ }
+
+ return l;
+}
+
void __sna_damage_destroy(struct sna_damage *damage)
{
free_list(&damage->embedded_box.list);
diff --git a/src/sna/sna_damage.h b/src/sna/sna_damage.h
index 228aba02..422a1243 100644
--- a/src/sna/sna_damage.h
+++ b/src/sna/sna_damage.h
@@ -27,6 +27,18 @@ struct sna_damage {
#define DAMAGE_MARK_ALL(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))|1))
#define DAMAGE_PTR(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))&~1))
+struct sna_damage *sna_damage_create(void);
+
+struct sna_damage *_sna_damage_combine(struct sna_damage *l,
+ struct sna_damage *r,
+ int dx, int dy);
+static inline void sna_damage_combine(struct sna_damage **l,
+ struct sna_damage *r,
+ int dx, int dy)
+{
+ *l = _sna_damage_combine(*l, r, dx, dy);
+}
+
fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
RegionPtr region);
static inline void sna_damage_add(struct sna_damage **damage,
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index 513b4895..f9151e08 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -1519,14 +1519,39 @@ sna_render_composite_redirect(struct sna *sna,
if (!width || !height)
return FALSE;
- priv = sna_pixmap(op->dst.pixmap);
- if (priv->gpu_bo == NULL) {
+ priv = sna_pixmap_force_to_gpu(op->dst.pixmap, MOVE_READ | MOVE_WRITE);
+ if (priv == NULL) {
DBG(("%s: fallback -- no GPU bo attached\n", __FUNCTION__));
return FALSE;
}
- if (!sna_pixmap_move_to_gpu(op->dst.pixmap, MOVE_READ | MOVE_WRITE))
- return FALSE;
+ if (op->dst.pixmap->drawable.width <= sna->render.max_3d_size) {
+ int y1, y2;
+
+ assert(op->dst.pixmap.drawable.height > sna->render.max_3d_size);
+ y1 = y + op->dst.y;
+ y2 = y1 + height;
+ y1 &= y1 & (64 - 1);
+ y2 = ALIGN(y2, 64);
+
+ if (y2 - y1 <= sna->render.max_3d_size) {
+ t->box.x2 = t->box.x1 = op->dst.x;
+ t->box.y2 = t->box.y1 = op->dst.y;
+ t->real_bo = priv->gpu_bo;
+ t->real_damage = op->damage;
+ if (op->damage) {
+ t->damage = sna_damage_create();
+ op->damage = &t->damage;
+ }
+
+ op->dst.bo = kgem_create_proxy(priv->gpu_bo,
+ y1 * priv->gpu_bo->pitch,
+ (y2 - y1) * priv->gpu_bo->pitch);
+ op->dst.y += -y1;
+ op->dst.height = y2 - y1;
+ return TRUE;
+ }
+ }
/* We can process the operation in a single pass,
* but the target is too large for the 3D pipeline.
@@ -1557,12 +1582,17 @@ sna_render_composite_redirect(struct sna *sna,
}
t->real_bo = priv->gpu_bo;
+ t->real_damage = op->damage;
+ if (op->damage) {
+ t->damage = sna_damage_create();
+ op->damage = &t->damage;
+ }
+
op->dst.bo = bo;
op->dst.x = -x;
op->dst.y = -y;
op->dst.width = width;
op->dst.height = height;
- op->damage = NULL;
return TRUE;
}
@@ -1573,13 +1603,20 @@ sna_render_composite_redirect_done(struct sna *sna,
const struct sna_composite_redirect *t = &op->redirect;
if (t->real_bo) {
- DBG(("%s: copying temporary to dst\n", __FUNCTION__));
-
- sna_blt_copy_boxes(sna, GXcopy,
- op->dst.bo, -t->box.x1, -t->box.y1,
- t->real_bo, 0, 0,
- op->dst.pixmap->drawable.bitsPerPixel,
- &t->box, 1);
+ if (t->box.x2 > t->box.x1) {
+ DBG(("%s: copying temporary to dst\n", __FUNCTION__));
+ sna_blt_copy_boxes(sna, GXcopy,
+ op->dst.bo, -t->box.x1, -t->box.y1,
+ t->real_bo, 0, 0,
+ op->dst.pixmap->drawable.bitsPerPixel,
+ &t->box, 1);
+ }
+ if (t->damage) {
+ sna_damage_combine(t->real_damage, t->damage,
+ t->box.x1 - op->dst.x,
+ t->box.y1 - op->dst.y);
+ __sna_damage_destroy(t->damage);
+ }
kgem_bo_destroy(&sna->kgem, op->dst.bo);
}
diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
index c4711f4b..b23a8a72 100644
--- a/src/sna/sna_render.h
+++ b/src/sna/sna_render.h
@@ -86,6 +86,7 @@ struct sna_composite_op {
struct sna_composite_redirect {
struct kgem_bo *real_bo;
+ struct sna_damage **real_damage, *damage;
BoxRec box;
} redirect;