summaryrefslogtreecommitdiff
path: root/src/sna/sna_io.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-09-13 09:57:30 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-09-13 09:57:30 +0100
commitd87a56ed1789e0c5058b302bb930d7e952ff3e5e (patch)
tree01b43a905ef6c853aa66b5c44d280044b16d2146 /src/sna/sna_io.c
parent58a96f0f684fe0d7d1a7890c630539ef8b065d1e (diff)
sna: Teach sna_replace__xor() how to tile large uploads
This path is hit using eog+cairo-1.10 and a large image, e.g. http://marsrovers.jpl.nasa.gov/gallery/press/opportunity/20120705a/PIA15689_Greeley_Pan_wDeck_L257F.jpg Reported-by: Michael Laß <bevan@bi-co.net> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=54808 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/sna/sna_io.c')
-rw-r--r--src/sna/sna_io.c199
1 files changed, 154 insertions, 45 deletions
diff --git a/src/sna/sna_io.c b/src/sna/sna_io.c
index 738ec8e9..fa871331 100644
--- a/src/sna/sna_io.c
+++ b/src/sna/sna_io.c
@@ -81,7 +81,7 @@ static void read_boxes_inplace(struct kgem *kgem,
DBG(("%s x %d, tiling=%d\n", __FUNCTION__, n, bo->tiling));
if (!kgem_bo_can_map(kgem, bo))
- return false;
+ return;
kgem_bo_submit(kgem, bo);
@@ -907,6 +907,8 @@ void sna_write_boxes__xor(struct sna *sna, PixmapPtr dst,
{
struct kgem *kgem = &sna->kgem;
struct kgem_bo *src_bo;
+ BoxRec extents;
+ bool can_blt;
void *ptr;
int offset;
int n, cmd, br13;
@@ -923,65 +925,172 @@ fallback:
return;
}
- /* Try to avoid switching rings... */
- if (dst_bo->tiling == I915_TILING_Y || kgem->ring == KGEM_RENDER) {
- PixmapRec tmp;
- BoxRec extents;
+ can_blt = kgem_bo_can_blt(kgem, dst_bo) &&
+ (box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
+ extents = box[0];
+ for (n = 1; n < nbox; n++) {
+ if (box[n].x1 < extents.x1)
+ extents.x1 = box[n].x1;
+ if (box[n].x2 > extents.x2)
+ extents.x2 = box[n].x2;
- /* XXX Composite? Not that we should ever reach here! */
+ if (can_blt)
+ can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
- extents = box[0];
- for (n = 1; n < nbox; n++) {
- if (box[n].x1 < extents.x1)
- extents.x1 = box[n].x1;
- if (box[n].x2 > extents.x2)
- extents.x2 = box[n].x2;
+ if (box[n].y1 < extents.y1)
+ extents.y1 = box[n].y1;
+ if (box[n].y2 > extents.y2)
+ extents.y2 = box[n].y2;
+ }
- if (box[n].y1 < extents.y1)
- extents.y1 = box[n].y1;
- if (box[n].y2 > extents.y2)
- extents.y2 = box[n].y2;
- }
+ /* Try to avoid switching rings... */
+ if (!can_blt || kgem->ring == KGEM_RENDER ||
+ upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) {
+ PixmapRec tmp;
- tmp.drawable.width = extents.x2 - extents.x1;
+ tmp.drawable.width = extents.x2 - extents.x1;
tmp.drawable.height = extents.y2 - extents.y1;
- tmp.drawable.depth = dst->drawable.depth;
+ tmp.drawable.depth = dst->drawable.depth;
tmp.drawable.bitsPerPixel = dst->drawable.bitsPerPixel;
tmp.devPrivate.ptr = NULL;
assert(tmp.drawable.width);
assert(tmp.drawable.height);
- src_bo = kgem_create_buffer_2d(kgem,
- tmp.drawable.width,
- tmp.drawable.height,
- tmp.drawable.bitsPerPixel,
- KGEM_BUFFER_WRITE_INPLACE,
- &ptr);
- if (!src_bo)
- goto fallback;
+ DBG(("%s: upload (%d, %d)x(%d, %d), max %dx%d\n",
+ __FUNCTION__,
+ extents.x1, extents.y1,
+ tmp.drawable.width, tmp.drawable.height,
+ sna->render.max_3d_size, sna->render.max_3d_size));
+ if (must_tile(sna, tmp.drawable.width, tmp.drawable.height)) {
+ BoxRec tile, stack[64], *clipped, *c;
+ int step;
- for (n = 0; n < nbox; n++) {
- memcpy_xor(src, ptr, tmp.drawable.bitsPerPixel,
- stride, src_bo->pitch,
- box[n].x1 + src_dx,
- box[n].y1 + src_dy,
- box[n].x1 - extents.x1,
- box[n].y1 - extents.y1,
- box[n].x2 - box[n].x1,
- box[n].y2 - box[n].y1,
- and, or);
- }
+tile:
+ step = MIN(sna->render.max_3d_size - 4096 / dst->drawable.bitsPerPixel,
+ 8*(MAXSHORT&~63) / dst->drawable.bitsPerPixel);
+ while (step * step * 4 > sna->kgem.max_upload_tile_size)
+ step /= 2;
- n = sna->render.copy_boxes(sna, GXcopy,
- &tmp, src_bo, -extents.x1, -extents.y1,
- dst, dst_bo, dst_dx, dst_dy,
- box, nbox, 0);
+ DBG(("%s: tiling upload, using %dx%d tiles\n",
+ __FUNCTION__, step, step));
+
+ if (n > ARRAY_SIZE(stack)) {
+ clipped = malloc(sizeof(BoxRec) * n);
+ if (clipped == NULL)
+ goto fallback;
+ } else
+ clipped = stack;
- kgem_bo_destroy(&sna->kgem, src_bo);
+ for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
+ tile.y2 = tile.y1 + step;
+ if (tile.y2 > extents.y2)
+ tile.y2 = extents.y2;
- if (!n)
- goto fallback;
+ for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
+ tile.x2 = tile.x1 + step;
+ if (tile.x2 > extents.x2)
+ tile.x2 = extents.x2;
+
+ tmp.drawable.width = tile.x2 - tile.x1;
+ tmp.drawable.height = tile.y2 - tile.y1;
+
+ src_bo = kgem_create_buffer_2d(kgem,
+ tmp.drawable.width,
+ tmp.drawable.height,
+ tmp.drawable.bitsPerPixel,
+ KGEM_BUFFER_WRITE_INPLACE,
+ &ptr);
+ if (!src_bo) {
+ if (clipped != stack)
+ free(clipped);
+ goto fallback;
+ }
+
+ c = clipped;
+ for (n = 0; n < nbox; n++) {
+ *c = box[n];
+ if (!box_intersect(c, &tile))
+ continue;
+
+ DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
+ __FUNCTION__,
+ c->x1, c->y1,
+ c->x2, c->y2,
+ src_dx, src_dy,
+ c->x1 - tile.x1,
+ c->y1 - tile.y1));
+ memcpy_xor(src, ptr, tmp.drawable.bitsPerPixel,
+ stride, src_bo->pitch,
+ c->x1 + src_dx,
+ c->y1 + src_dy,
+ c->x1 - tile.x1,
+ c->y1 - tile.y1,
+ c->x2 - c->x1,
+ c->y2 - c->y1,
+ and, or);
+ c++;
+ }
+
+ if (c != clipped)
+ n = sna->render.copy_boxes(sna, GXcopy,
+ &tmp, src_bo, -tile.x1, -tile.y1,
+ dst, dst_bo, dst_dx, dst_dy,
+ clipped, c - clipped, 0);
+ else
+ n = 1;
+
+ kgem_bo_destroy(&sna->kgem, src_bo);
+
+ if (!n) {
+ if (clipped != stack)
+ free(clipped);
+ goto fallback;
+ }
+ }
+ }
+
+ if (clipped != stack)
+ free(clipped);
+ } else {
+ src_bo = kgem_create_buffer_2d(kgem,
+ tmp.drawable.width,
+ tmp.drawable.height,
+ tmp.drawable.bitsPerPixel,
+ KGEM_BUFFER_WRITE_INPLACE,
+ &ptr);
+ if (!src_bo)
+ goto fallback;
+
+ for (n = 0; n < nbox; n++) {
+ DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
+ __FUNCTION__,
+ box[n].x1, box[n].y1,
+ box[n].x2, box[n].y2,
+ src_dx, src_dy,
+ box[n].x1 - extents.x1,
+ box[n].y1 - extents.y1));
+ memcpy_xor(src, ptr, tmp.drawable.bitsPerPixel,
+ stride, src_bo->pitch,
+ box[n].x1 + src_dx,
+ box[n].y1 + src_dy,
+ box[n].x1 - extents.x1,
+ box[n].y1 - extents.y1,
+ box[n].x2 - box[n].x1,
+ box[n].y2 - box[n].y1,
+ and, or);
+ }
+
+ n = sna->render.copy_boxes(sna, GXcopy,
+ &tmp, src_bo, -extents.x1, -extents.y1,
+ dst, dst_bo, dst_dx, dst_dy,
+ box, nbox, 0);
+
+ kgem_bo_destroy(&sna->kgem, src_bo);
+
+ if (!n)
+ goto tile;
+ }
return;
}