Fixed bug #1090 (SDL_BlitCopyOverlap() assumes memcpy() operates in order)

Even if we're blitting between two different surfaces their pixels might still overlap, because of SDL_CreateRGBSurfaceFrom(), so always use SDL_BlitCopy() and check for overlap in that function.

When handling overlapping surfaces, don't assume that memcpy() iterates forward, instead use memmove() correctly, and provide a fallback implementation of SDL_memmove() that handles the different cases.

Fixed a bug with SDL_memset() not completely filling lengths that aren't a multiple of 4.
Optimized SDL_memcpy() a bit using the same technique as SDL_memset().
This commit is contained in:
Sam Lantinga 2011-02-16 15:25:10 -08:00
parent dc23c42ea9
commit d2b922f555
5 changed files with 76 additions and 111 deletions

View file

@ -96,6 +96,7 @@ SDL_memcpyMMX(Uint8 * dst, const Uint8 * src, int len)
void
SDL_BlitCopy(SDL_BlitInfo * info)
{
SDL_bool overlap;
Uint8 *src, *dst;
int w, h;
int srcskip, dstskip;
@ -107,6 +108,21 @@ SDL_BlitCopy(SDL_BlitInfo * info)
srcskip = info->src_pitch;
dstskip = info->dst_pitch;
/* Properly handle overlapping blits */
if (src < dst) {
overlap = (dst < (src + h*srcskip));
} else {
overlap = (src < (dst + h*dstskip));
}
if (overlap) {
while (h--) {
SDL_memmove(dst, src, w);
src += srcskip;
dst += dstskip;
}
return;
}
#ifdef __SSE__
if (SDL_HasSSE() &&
!((uintptr_t) src & 15) && !(srcskip & 15) &&
@ -141,29 +157,4 @@ SDL_BlitCopy(SDL_BlitInfo * info)
}
}
void
SDL_BlitCopyOverlap(SDL_BlitInfo * info)
{
Uint8 *src, *dst;
int w, h;
int skip;
w = info->dst_w * info->dst_fmt->BytesPerPixel;
h = info->dst_h;
src = info->src;
dst = info->dst;
skip = info->src_pitch;
if ((dst < src) || (dst >= (src + h * skip))) {
SDL_BlitCopy(info);
} else {
src += ((h - 1) * skip);
dst += ((h - 1) * skip);
while (h--) {
SDL_revcpy(dst, src, w);
src -= skip;
dst -= skip;
}
}
}
/* vi: set ts=4 sw=4 expandtab: */