summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-06-14 16:09:38 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-06-14 16:48:52 +0100
commit0df7c488640d3590d2a88dc353b72167b6644eaa (patch)
tree753ee14042db22cbeca0956fb500f0b28417ad78 /src
parentd5b273b20b7d917d08af120815c28b1618d3342c (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.c170
-rw-r--r--src/sna/sna.h10
-rw-r--r--src/sna/sna_accel.c8
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 {