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>
This commit is contained in:
Chris Wilson 2012-09-13 09:57:30 +01:00
parent 58a96f0f68
commit d87a56ed17
1 changed files with 157 additions and 48 deletions

View File

@ -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,66 +925,173 @@ fallback:
return;
}
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;
if (can_blt)
can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
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 (dst_bo->tiling == I915_TILING_Y || kgem->ring == KGEM_RENDER) {
if (!can_blt || kgem->ring == KGEM_RENDER ||
upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) {
PixmapRec tmp;
BoxRec extents;
/* XXX Composite? Not that we should ever reach here! */
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;
}
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;
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;
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) {
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;
}
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 fallback;
return;
}