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>
This commit is contained in:
parent
6e2cee27c3
commit
1d74b2e07d
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue