diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2014-06-24 08:58:51 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2014-06-24 10:55:02 +0100 |
commit | 1d74b2e07d125ad95b9db6c9c032e90faf2bfa60 (patch) | |
tree | 77d9bdd0aa0f8d8dd98fbb9a6c29d7b8b4410d87 | |
parent | 6e2cee27c379278b0321fd1db34ed80c439115a7 (diff) |
sna: Decompose self-copy into overlapping/non-overlapping regions
We only need to stage the copy for the overlapping portion of the
self-copy, for the rest we can do in a single pass.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/gen6_render.c | 48 | ||||
-rw-r--r-- | src/sna/gen7_render.c | 48 | ||||
-rw-r--r-- | src/sna/gen8_render.c | 48 | ||||
-rw-r--r-- | src/sna/sna_render.c | 150 | ||||
-rw-r--r-- | src/sna/sna_render.h | 6 | ||||
-rw-r--r-- | src/sna/sna_render_inline.h | 38 |
6 files changed, 208 insertions, 130 deletions
diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c index 6ef26c81..fe0426ef 100644 --- a/src/sna/gen6_render.c +++ b/src/sna/gen6_render.c @@ -2655,40 +2655,6 @@ static inline bool prefer_blt_copy(struct sna *sna, return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo); } -inline static void boxes_extents(const BoxRec *box, int n, BoxRec *extents) -{ - *extents = box[0]; - while (--n) { - box++; - - if (box->x1 < extents->x1) - extents->x1 = box->x1; - if (box->x2 > extents->x2) - extents->x2 = box->x2; - - if (box->y1 < extents->y1) - extents->y1 = box->y1; - if (box->y2 > extents->y2) - extents->y2 = box->y2; - } -} - -static inline bool -overlaps(struct sna *sna, - 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, - const BoxRec *box, int n, BoxRec *extents) -{ - if (src_bo != dst_bo) - return false; - - boxes_extents(box, n, extents); - return (extents->x2 + src_dx > extents->x1 + dst_dx && - extents->x1 + src_dx < extents->x2 + dst_dx && - extents->y2 + src_dy > extents->y1 + dst_dy && - extents->y1 + src_dy < extents->y2 + dst_dy); -} - static bool gen6_render_copy_boxes(struct sna *sna, uint8_t alu, PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, @@ -2704,7 +2670,7 @@ gen6_render_copy_boxes(struct sna *sna, uint8_t alu, overlaps(sna, src_bo, src_dx, src_dy, dst_bo, dst_dx, dst_dy, - box, n, &extents))); + box, n, flags, &extents))); if (prefer_blt_copy(sna, src_bo, dst_bo, flags) && sna_blt_compare_depth(&src->drawable, &dst->drawable) && @@ -2729,7 +2695,8 @@ fallback_blt: if (overlaps(sna, src_bo, src_dx, src_dy, dst_bo, dst_dx, dst_dy, - box, n, &extents)) { + box, n, flags, + &extents)) { bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1); if ((big || can_switch_to_blt(sna, dst_bo, flags)) && @@ -2743,9 +2710,14 @@ fallback_blt: if (big) goto fallback_blt; + assert(src_bo == dst_bo); + assert(src->drawable.depth == dst->drawable.depth); + assert(src->drawable.width == dst->drawable.width); + assert(src->drawable.height == dst->drawable.height); return sna_render_copy_boxes__overlap(sna, alu, - src, src_bo, src_dx, src_dy, - dst, dst_bo, dst_dx, dst_dy, + src, src_bo, + src_dx, src_dy, + dst_dx, dst_dy, box, n, &extents); } diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c index ce153e54..a5882543 100644 --- a/src/sna/gen7_render.c +++ b/src/sna/gen7_render.c @@ -2891,40 +2891,6 @@ prefer_blt_copy(struct sna *sna, return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo); } -inline static void boxes_extents(const BoxRec *box, int n, BoxRec *extents) -{ - *extents = box[0]; - while (--n) { - box++; - - if (box->x1 < extents->x1) - extents->x1 = box->x1; - if (box->x2 > extents->x2) - extents->x2 = box->x2; - - if (box->y1 < extents->y1) - extents->y1 = box->y1; - if (box->y2 > extents->y2) - extents->y2 = box->y2; - } -} - -static inline bool -overlaps(struct sna *sna, - 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, - const BoxRec *box, int n, BoxRec *extents) -{ - if (src_bo != dst_bo) - return false; - - boxes_extents(box, n, extents); - return (extents->x2 + src_dx > extents->x1 + dst_dx && - extents->x1 + src_dx < extents->x2 + dst_dx && - extents->y2 + src_dy > extents->y1 + dst_dy && - extents->y1 + src_dy < extents->y2 + dst_dy); -} - static bool gen7_render_copy_boxes(struct sna *sna, uint8_t alu, PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, @@ -2940,7 +2906,7 @@ gen7_render_copy_boxes(struct sna *sna, uint8_t alu, overlaps(sna, src_bo, src_dx, src_dy, dst_bo, dst_dx, dst_dy, - box, n, &extents))); + box, n, flags, &extents))); if (prefer_blt_copy(sna, src_bo, dst_bo, flags) && sna_blt_compare_depth(&src->drawable, &dst->drawable) && @@ -2966,7 +2932,8 @@ fallback_blt: if (overlaps(sna, src_bo, src_dx, src_dy, dst_bo, dst_dx, dst_dy, - box, n, &extents)) { + box, n, flags, + &extents)) { bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1); if ((big || can_switch_to_blt(sna, dst_bo, flags)) && @@ -2980,9 +2947,14 @@ fallback_blt: if (big) goto fallback_blt; + assert(src_bo == dst_bo); + assert(src->drawable.depth == dst->drawable.depth); + assert(src->drawable.width == dst->drawable.width); + assert(src->drawable.height == dst->drawable.height); return sna_render_copy_boxes__overlap(sna, alu, - src, src_bo, src_dx, src_dy, - dst, dst_bo, dst_dx, dst_dy, + src, src_bo, + src_dx, src_dy, + dst_dx, dst_dy, box, n, &extents); } diff --git a/src/sna/gen8_render.c b/src/sna/gen8_render.c index 53bac819..365e8f6e 100644 --- a/src/sna/gen8_render.c +++ b/src/sna/gen8_render.c @@ -2713,40 +2713,6 @@ prefer_blt_copy(struct sna *sna, return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo); } -inline static void boxes_extents(const BoxRec *box, int n, BoxRec *extents) -{ - *extents = box[0]; - while (--n) { - box++; - - if (box->x1 < extents->x1) - extents->x1 = box->x1; - if (box->x2 > extents->x2) - extents->x2 = box->x2; - - if (box->y1 < extents->y1) - extents->y1 = box->y1; - if (box->y2 > extents->y2) - extents->y2 = box->y2; - } -} - -static inline bool -overlaps(struct sna *sna, - 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, - const BoxRec *box, int n, BoxRec *extents) -{ - if (src_bo != dst_bo) - return false; - - boxes_extents(box, n, extents); - return (extents->x2 + src_dx > extents->x1 + dst_dx && - extents->x1 + src_dx < extents->x2 + dst_dx && - extents->y2 + src_dy > extents->y1 + dst_dy && - extents->y1 + src_dy < extents->y2 + dst_dy); -} - static bool gen8_render_copy_boxes(struct sna *sna, uint8_t alu, PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, @@ -2762,7 +2728,7 @@ gen8_render_copy_boxes(struct sna *sna, uint8_t alu, overlaps(sna, src_bo, src_dx, src_dy, dst_bo, dst_dx, dst_dy, - box, n, &extents))); + box, n, flags, &extents))); if (prefer_blt_copy(sna, src_bo, dst_bo, flags) && sna_blt_compare_depth(&src->drawable, &dst->drawable) && @@ -2790,7 +2756,8 @@ fallback_blt: if (overlaps(sna, src_bo, src_dx, src_dy, dst_bo, dst_dx, dst_dy, - box, n, &extents)) { + box, n, flags, + &extents)) { bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1); if ((big || can_switch_to_blt(sna, dst_bo, flags)) && @@ -2804,9 +2771,14 @@ fallback_blt: if (big) goto fallback_blt; + assert(src_bo == dst_bo); + assert(src->drawable.depth == dst->drawable.depth); + assert(src->drawable.width == dst->drawable.width); + assert(src->drawable.height == dst->drawable.height); return sna_render_copy_boxes__overlap(sna, alu, - src, src_bo, src_dx, src_dy, - dst, dst_bo, dst_dx, dst_dy, + src, src_bo, + src_dx, src_dy, + dst_dx, dst_dy, box, n, &extents); } diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c index e8060b41..b455f42b 100644 --- a/src/sna/sna_render.c +++ b/src/sna/sna_render.c @@ -2123,37 +2123,159 @@ sna_render_composite_redirect_done(struct sna *sna, } } -bool -sna_render_copy_boxes__overlap(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, const BoxRec *extents) +static bool +copy_overlap(struct sna *sna, uint8_t alu, + PixmapPtr pixmap, struct kgem_bo *bo, + int16_t src_dx, int16_t src_dy, + int16_t dst_dx, int16_t dst_dy, + const BoxRec *box, int n, const BoxRec *extents) { - ScreenPtr screen = dst->drawable.pScreen; - struct kgem_bo *bo; + ScreenPtr screen = pixmap->drawable.pScreen; + struct kgem_bo *tmp_bo; PixmapPtr tmp; bool ret = false; + if (n == 0) + return true; + + DBG(("%s: %d x %dx%d src=(%d, %d), dst=(%d, %d)\n", + __FUNCTION__, n, + extents->x2 - extents->x1, + extents->y2 - extents->y1, + src_dx, src_dy, + dst_dx, dst_dy)); + tmp = screen->CreatePixmap(screen, extents->x2 - extents->x1, extents->y2 - extents->y1, - dst->drawable.depth, + pixmap->drawable.depth, SNA_CREATE_SCRATCH); if (tmp == NULL) return false; - bo = __sna_pixmap_get_bo(tmp); - assert(bo); + tmp_bo = __sna_pixmap_get_bo(tmp); + assert(tmp_bo); ret = (sna->render.copy_boxes(sna, GXcopy, - src, src_bo, src_dx, src_dy, - tmp, bo, -extents->x1, -extents->y1, + pixmap, bo, src_dx, src_dy, + tmp, tmp_bo, -extents->x1, -extents->y1, box, n , 0) && sna->render.copy_boxes(sna, alu, - tmp, bo, -extents->x1, -extents->y1, - dst, dst_bo, dst_dx, dst_dy, + tmp, tmp_bo, -extents->x1, -extents->y1, + pixmap, bo, dst_dx, dst_dy, box, n , 0)); screen->DestroyPixmap(tmp); return ret; } +bool +sna_render_copy_boxes__overlap(struct sna *sna, uint8_t alu, + PixmapPtr pixmap, struct kgem_bo *bo, + int16_t src_dx, int16_t src_dy, + int16_t dst_dx, int16_t dst_dy, + const BoxRec *box, int n, const BoxRec *extents) +{ + bool ret = false; + RegionRec overlap, non_overlap; + pixman_region16_t region; + pixman_box16_t stack_boxes[64], *boxes = stack_boxes; + int num_boxes, i; + + DBG(("%s: pixmap=%ld, handle=%d, %d x [(%d, %d), (%d, %d)], dst=(%d, %d), src=(%d, %d)\n", + __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, + n, extents->x1, extents->y1, extents->x2, extents->y2, + src_dx, src_dy, dst_dx, dst_dy)); + + if ((dst_dx - src_dx < 4 && src_dx - dst_dx < 4) && + (dst_dy - src_dy < 4 && src_dy - dst_dy < 4)) + return copy_overlap(sna, alu, pixmap, bo, + src_dx, src_dy, + dst_dx, dst_dy, + box, n, extents); + + if (n > ARRAY_SIZE(stack_boxes)) { + boxes = malloc(sizeof(pixman_box16_t) * n); + if (boxes == NULL) + return copy_overlap(sna, alu, pixmap, bo, + src_dx, src_dy, + dst_dx, dst_dy, + box, n, extents); + } + + region.extents.x1 = extents->x1 + dst_dx; + region.extents.x2 = extents->x2 + dst_dx; + region.extents.y1 = extents->y1 + dst_dy; + region.extents.y2 = extents->x2 + dst_dy; + + for (i = num_boxes = 0; i < n; i++) { + boxes[num_boxes].x1 = box[i].x1 + dst_dx; + if (boxes[num_boxes].x1 < region.extents.x1) + boxes[num_boxes].x1 = region.extents.x1; + + boxes[num_boxes].y1 = box[i].y1 + dst_dy; + if (boxes[num_boxes].y1 < region.extents.y1) + boxes[num_boxes].y1 = region.extents.y1; + + boxes[num_boxes].x2 = box[i].x2 + dst_dy; + if (boxes[num_boxes].x2 > region.extents.x2) + boxes[num_boxes].x2 = region.extents.x2; + + boxes[num_boxes].y2 = box[i].y2 + dst_dy; + if (boxes[num_boxes].y2 > region.extents.y2) + boxes[num_boxes].y2 = region.extents.y2; + + if (boxes[num_boxes].x2 > boxes[num_boxes].x1 && + boxes[num_boxes].y2 > boxes[num_boxes].y1) + num_boxes++; + } + + if (num_boxes == 0) { + ret = true; + goto cleanup_boxes; + } + + if (!pixman_region_init_rects(®ion, boxes, num_boxes)) + goto cleanup_boxes; + + overlap.extents.x1 = extents->x1 + src_dx; + overlap.extents.x2 = extents->x2 + src_dx; + overlap.extents.y1 = extents->y1 + src_dy; + overlap.extents.y2 = extents->x2 + src_dy; + overlap.data = NULL; + + RegionIntersect(&overlap, &overlap, ®ion); + DBG(("%s: overlapping extents: (%d, %d), (%d, %d) x %d\n", + __FUNCTION__, + overlap.extents.x1, overlap.extents.y1, + overlap.extents.x2, overlap.extents.y2, + region_num_rects(&overlap))); + + RegionNull(&non_overlap); + RegionSubtract(&non_overlap, ®ion, &overlap); + DBG(("%s: non-overlapping extents: (%d, %d), (%d, %d) x %d\n", + __FUNCTION__, + non_overlap.extents.x1, non_overlap.extents.y1, + non_overlap.extents.x2, non_overlap.extents.y2, + region_num_rects(&non_overlap))); + + n = region_num_rects(&non_overlap); + box = region_rects(&non_overlap); + if (n && !sna->render.copy_boxes(sna, alu, + pixmap, bo, -dst_dx + src_dx, -dst_dy + src_dy, + pixmap, bo, 0, 0, + box, n , COPY_NO_OVERLAP)) + goto cleanup_boxes; + + n = region_num_rects(&overlap); + box = region_rects(&overlap); + ret = copy_overlap(sna, alu, pixmap, bo, + -dst_dx + src_dx, -dst_dy + src_dy, + 0, 0, + box, n, &overlap.extents); + +cleanup_boxes: + if (boxes != stack_boxes) + free(boxes); + + return ret; +} diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h index 52bb44e6..0637ceb2 100644 --- a/src/sna/sna_render.h +++ b/src/sna/sna_render.h @@ -285,6 +285,7 @@ struct sna_render { const BoxRec *box, int n, unsigned flags); #define COPY_LAST 0x1 #define COPY_SYNC 0x2 +#define COPY_NO_OVERLAP 0x4 bool (*copy)(struct sna *sna, uint8_t alu, PixmapPtr src, struct kgem_bo *src_bo, @@ -814,8 +815,9 @@ sna_render_composite_redirect_done(struct sna *sna, bool sna_render_copy_boxes__overlap(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, + PixmapPtr pixmap, struct kgem_bo *bo, + int16_t src_dx, int16_t src_dy, + int16_t dst_dx, int16_t dst_dy, const BoxRec *box, int n, const BoxRec *extents); bool diff --git a/src/sna/sna_render_inline.h b/src/sna/sna_render_inline.h index 3750117e..d51730ef 100644 --- a/src/sna/sna_render_inline.h +++ b/src/sna/sna_render_inline.h @@ -319,5 +319,43 @@ untransformed(PicturePtr p) return !p->transform || pixman_transform_is_int_translate(p->transform); } +inline static void +boxes_extents(const BoxRec *box, int n, BoxRec *extents) +{ + *extents = box[0]; + while (--n) { + box++; + + if (box->x1 < extents->x1) + extents->x1 = box->x1; + if (box->x2 > extents->x2) + extents->x2 = box->x2; + + if (box->y1 < extents->y1) + extents->y1 = box->y1; + if (box->y2 > extents->y2) + extents->y2 = box->y2; + } +} + +inline static bool +overlaps(struct sna *sna, + 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, + const BoxRec *box, int n, unsigned flags, + BoxRec *extents) +{ + if (src_bo != dst_bo) + return false; + + if (flags & COPY_NO_OVERLAP) + return false; + + boxes_extents(box, n, extents); + return (extents->x2 + src_dx > extents->x1 + dst_dx && + extents->x1 + src_dx < extents->x2 + dst_dx && + extents->y2 + src_dy > extents->y1 + dst_dy && + extents->y1 + src_dy < extents->y2 + dst_dy); +} #endif /* SNA_RENDER_INLINE_H */ |