diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-02-03 19:30:24 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-02-04 15:19:05 +0000 |
commit | 93a0b10f163ee79b6a6a7ea46b0a33b622b1f86e (patch) | |
tree | 5df1eef31085d3461ea4f0cbc1771215c340eec9 /src/sna/sna_tiling.c | |
parent | 4774c6b8331831e0c9f3b24f5f6e1b6ea399f628 (diff) |
sna: Apply redirection for the render copy into large pixmaps
If the pixmap is larger than the pipeline, but the operation extents fit
within the pipeline, we may be able to create a proxy target to
transform the operation into one that fits within the constraints of the
render pipeline.
This fixes the infinite recursion hit with partially displayed extremely
large images.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/sna/sna_tiling.c')
-rw-r--r-- | src/sna/sna_tiling.c | 130 |
1 files changed, 126 insertions, 4 deletions
diff --git a/src/sna/sna_tiling.c b/src/sna/sna_tiling.c index 702192a2..00e111ce 100644 --- a/src/sna/sna_tiling.c +++ b/src/sna/sna_tiling.c @@ -421,10 +421,10 @@ done: return ret; } -Bool sna_tiling_copy_boxes(struct sna *sna, uint8_t alu, - struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, - struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, - int bpp, const BoxRec *box, int nbox) +Bool sna_tiling_blt_copy_boxes(struct sna *sna, uint8_t alu, + struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, + struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, + int bpp, const BoxRec *box, int nbox) { RegionRec region, tile, this; struct kgem_bo *bo; @@ -516,3 +516,125 @@ done: pixman_region_fini(®ion); return ret; } + +static Bool +box_intersect(BoxPtr a, const BoxRec *b) +{ + if (a->x1 < b->x1) + a->x1 = b->x1; + if (a->x2 > b->x2) + a->x2 = b->x2; + if (a->y1 < b->y1) + a->y1 = b->y1; + if (a->y2 > b->y2) + a->y2 = b->y2; + + return a->x1 < a->x2 && a->y1 < a->y2; +} + +Bool +sna_tiling_copy_boxes(struct sna *sna, uint8_t alu, + PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, + PixmapPtr dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, + const BoxRec *box, int n) +{ + BoxRec extents, tile, stack[64], *clipped, *c; + PixmapRec p; + int i, step; + Bool ret = FALSE; + + extents = box[0]; + for (i = 1; i < n; i++) { + if (extents.x1 < box[i].x1) + extents.x1 = box[i].x1; + if (extents.y1 < box[i].y1) + extents.y1 = box[i].y1; + + if (extents.x2 > box[i].x2) + extents.x2 = box[i].x2; + if (extents.y2 > box[i].y2) + extents.y2 = box[i].y2; + } + + step = sna->render.max_3d_size - 4096 / dst->drawable.bitsPerPixel; + while (step * step * 4 > sna->kgem.max_upload_tile_size) + step /= 2; + + DBG(("%s: tiling copy, using %dx%d tiles\n", + __FUNCTION__, step, step)); + + if (n > ARRAY_SIZE(stack)) { + clipped = malloc(sizeof(BoxRec) * n); + if (clipped == NULL) + goto tiled_error; + } else + clipped = stack; + + p.drawable.depth = src->drawable.depth; + p.drawable.bitsPerPixel = src->drawable.bitsPerPixel; + p.devPrivate.ptr = NULL; + + 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; + + for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) { + struct kgem_bo *tmp_bo; + + tile.x2 = tile.x1 + step; + if (tile.x2 > extents.x2) + tile.x2 = extents.x2; + + p.drawable.width = tile.x2 - tile.x1; + p.drawable.height = tile.y2 - tile.y1; + + tmp_bo = kgem_create_2d(&sna->kgem, + p.drawable.width, + p.drawable.height, + p.drawable.bitsPerPixel, + I915_TILING_X, 0); + if (!tmp_bo) + goto tiled_error; + + c = clipped; + for (i = 0; i < n; i++) { + *c = box[i]; + 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)); + c++; + } + + if (c == clipped || + (sna->render.copy_boxes(sna, GXcopy, + src, src_bo, src_dx, src_dy, + &p, tmp_bo, -tile.x1, -tile.y1, + clipped, c - clipped) && + sna->render.copy_boxes(sna, alu, + &p, tmp_bo, -tile.x1, -tile.y1, + dst, dst_bo, dst_dx, dst_dy, + clipped, c - clipped))) + i = 1; + + kgem_bo_destroy(&sna->kgem, tmp_bo); + + if (!i) + goto tiled_error; + } + } + + ret = TRUE; +tiled_error: + if (clipped != stack) + free(clipped); + + return ret; +} |