diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-06-14 16:09:38 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-06-14 16:48:52 +0100 |
commit | 0df7c488640d3590d2a88dc353b72167b6644eaa (patch) | |
tree | 753ee14042db22cbeca0956fb500f0b28417ad78 /src | |
parent | d5b273b20b7d917d08af120815c28b1618d3342c (diff) |
sna: Supporting overlapping copies for fallback blits
Reported-by: Zdenek Kabelac <zkabelac@redhat.com>
References: https://bugs.freedesktop.org/show_bug.cgi?id=50393
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src')
-rw-r--r-- | src/sna/blt.c | 170 | ||||
-rw-r--r-- | src/sna/sna.h | 10 | ||||
-rw-r--r-- | src/sna/sna_accel.c | 8 |
3 files changed, 182 insertions, 6 deletions
diff --git a/src/sna/blt.c b/src/sna/blt.c index 494b413f..99bdece2 100644 --- a/src/sna/blt.c +++ b/src/sna/blt.c @@ -217,6 +217,176 @@ memcpy_blt(const void *src, void *dst, int bpp, } void +memmove_blt(const void *src, void *dst, int bpp, + int32_t src_stride, int32_t dst_stride, + int16_t src_x, int16_t src_y, + int16_t dst_x, int16_t dst_y, + uint16_t width, uint16_t height) +{ + const uint8_t *src_bytes; + uint8_t *dst_bytes; + int byte_width; + + assert(src); + assert(dst); + assert(width && height); + assert(bpp >= 8); + + DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n", + __FUNCTION__, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride)); + + bpp /= 8; + + src_bytes = (const uint8_t *)src + src_stride * src_y + src_x * bpp; + dst_bytes = (uint8_t *)dst + dst_stride * dst_y + dst_x * bpp; + + byte_width = width * bpp; + if (byte_width == src_stride && byte_width == dst_stride) { + byte_width *= height; + height = 1; + } + + switch (byte_width) { + case 1: + do { + *dst_bytes = *src_bytes; + src_bytes += src_stride; + dst_bytes += dst_stride; + } while (--height); + break; + + case 2: + do { + *(uint16_t *)dst_bytes = *(const uint16_t *)src_bytes; + src_bytes += src_stride; + dst_bytes += dst_stride; + } while (--height); + break; + + case 4: + do { + *(uint32_t *)dst_bytes = *(const uint32_t *)src_bytes; + src_bytes += src_stride; + dst_bytes += dst_stride; + } while (--height); + break; + + case 8: + do { + *(uint64_t *)dst_bytes = *(const uint64_t *)src_bytes; + src_bytes += src_stride; + dst_bytes += dst_stride; + } while (--height); + break; + + default: + if (src_stride == dst_stride) { + if (dst_bytes < src_bytes + byte_width && + src_bytes < dst_bytes + byte_width) { + do { + memmove(dst_bytes, src_bytes, byte_width); + src_bytes += src_stride; + dst_bytes += src_stride; + } while (--height); + } else { + do { + memcpy(dst_bytes, src_bytes, byte_width); + src_bytes += src_stride; + dst_bytes += src_stride; + } while (--height); + } + } else do { + memmove(dst_bytes, src_bytes, byte_width); + src_bytes += src_stride; + dst_bytes += dst_stride; + } while (--height); + break; + } +} + +void +memmove_blt__box(const void *src, void *dst, + int bpp, int32_t stride, + const BoxRec *box) +{ + const uint8_t *src_bytes; + uint8_t *dst_bytes; + int width, height; + + assert(src); + assert(dst); + assert(bpp >= 8); + assert(box->x2 > box->x1); + assert(box->y2 > box->y1); + + DBG(("%s: box=(%d, %d), (%d, %d), pitch=%d, bpp=%d\n", + __FUNCTION__, box->x1, box->y1, box->x2, box->y2, stride, bpp)); + + bpp /= 8; + width = box->y1 * stride + box->x1 * bpp; + src_bytes = (const uint8_t *)src + width; + dst_bytes = (uint8_t *)dst + width; + + width = (box->x2 - box->x1) * bpp; + height = (box->y2 - box->y1); + if (width == stride) { + width *= height; + height = 1; + } + + switch (width) { + case 1: + do { + *dst_bytes = *src_bytes; + src_bytes += stride; + dst_bytes += stride; + } while (--height); + break; + + case 2: + do { + *(uint16_t *)dst_bytes = *(const uint16_t *)src_bytes; + src_bytes += stride; + dst_bytes += stride; + } while (--height); + break; + + case 4: + do { + *(uint32_t *)dst_bytes = *(const uint32_t *)src_bytes; + src_bytes += stride; + dst_bytes += stride; + } while (--height); + break; + + case 8: + do { + *(uint64_t *)dst_bytes = *(const uint64_t *)src_bytes; + src_bytes += stride; + dst_bytes += stride; + } while (--height); + break; + + default: + if (dst_bytes < src_bytes + width && + src_bytes < dst_bytes + width) { + do { + memmove(dst_bytes, src_bytes, width); + src_bytes += stride; + dst_bytes += stride; + } while (--height); + } else { + do { + memcpy(dst_bytes, src_bytes, width); + src_bytes += stride; + dst_bytes += stride; + } while (--height); + } + break; + } +} + +void memcpy_xor(const void *src, void *dst, int bpp, int32_t src_stride, int32_t dst_stride, int16_t src_x, int16_t src_y, diff --git a/src/sna/sna.h b/src/sna/sna.h index 634692ca..ce06e4d5 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -671,6 +671,16 @@ memcpy_blt(const void *src, void *dst, int bpp, int16_t src_x, int16_t src_y, int16_t dst_x, int16_t dst_y, uint16_t width, uint16_t height); +void +memmove_blt(const void *src, void *dst, int bpp, + int32_t src_stride, int32_t dst_stride, + int16_t src_x, int16_t src_y, + int16_t dst_x, int16_t dst_y, + uint16_t width, uint16_t height); +void +memmove_blt__box(const void *src, void *dst, + int bpp, int32_t stride, + const BoxRec *box); void memcpy_xor(const void *src, void *dst, int bpp, diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index 6c48db86..a44cdb15 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -3498,12 +3498,8 @@ fallback: dy * stride + dx * bpp / 8); do { - memcpy_blt(src_bits, dst_bits, bpp, - stride, stride, - box->x1, box->y1, - box->x1, box->y1, - box->x2 - box->x1, - box->y2 - box->y1); + memmove_blt__box(src_bits, dst_bits, + bpp, stride, box); box++; } while (--n); } else { |