diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/sna/sna_io.c | 199 |
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; } |