sna: Decompose self-copy into overlapping/non-overlapping regions
authorChris Wilson <chris@chris-wilson.co.uk>
Tue, 24 Jun 2014 07:58:51 +0000 (08:58 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 24 Jun 2014 09:55:02 +0000 (10:55 +0100)
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>
src/sna/gen6_render.c
src/sna/gen7_render.c
src/sna/gen8_render.c
src/sna/sna_render.c
src/sna/sna_render.h
src/sna/sna_render_inline.h

index 6ef26c8..fe0426e 100644 (file)
@@ -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);
        }
 
index ce153e5..a588254 100644 (file)
@@ -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);
        }
 
index 53bac81..365e8f6 100644 (file)
@@ -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);
        }
 
index e8060b4..b455f42 100644 (file)
@@ -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(&region, 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, &region);
+       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, &region, &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;
+}
index 52bb44e..0637ceb 100644 (file)
@@ -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
index 3750117..d51730e 100644 (file)
@@ -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 */