Fixed bug #1090 (SDL_BlitCopyOverlap() assumes memcpy() operates in order)
authorSam Lantinga <slouken@libsdl.org>
Wed, 16 Feb 2011 15:25:10 -0800
changeset 5325b9c224e16859
parent 5324 cc606b34bd97
child 5326 4a4095fe12e3
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().
include/SDL_stdinc.h
src/stdlib/SDL_string.c
src/video/SDL_blit.c
src/video/SDL_blit_copy.c
src/video/SDL_blit_copy.h
     1.1 --- a/include/SDL_stdinc.h	Wed Feb 16 14:38:49 2011 -0800
     1.2 +++ b/include/SDL_stdinc.h	Wed Feb 16 15:25:10 2011 -0800
     1.3 @@ -352,8 +352,8 @@
     1.4  #endif
     1.5  
     1.6  /* We can count on memcpy existing on Mac OS X and being well-tuned. */
     1.7 -#if defined(__MACH__) && defined(__APPLE__)
     1.8 -#define SDL_memcpy(dst, src, len) memcpy(dst, src, len)
     1.9 +#if defined(__MACOSX__)
    1.10 +#define SDL_memcpy      memcpy
    1.11  #elif defined(__GNUC__) && defined(i386)
    1.12  #define SDL_memcpy(dst, src, len)					  \
    1.13  do {									  \
    1.14 @@ -385,8 +385,8 @@
    1.15  #endif
    1.16  
    1.17  /* We can count on memcpy existing on Mac OS X and being well-tuned. */
    1.18 -#if defined(__MACH__) && defined(__APPLE__)
    1.19 -#define SDL_memcpy4(dst, src, len) memcpy(dst, src, (len)*4)
    1.20 +#if defined(__MACOSX__)
    1.21 +#define SDL_memcpy4(dst, src, len)	SDL_memcpy((dst), (src), (len) << 2)
    1.22  #elif defined(__GNUC__) && defined(i386)
    1.23  #define SDL_memcpy4(dst, src, len)				\
    1.24  do {								\
    1.25 @@ -400,54 +400,14 @@
    1.26  } while(0)
    1.27  #endif
    1.28  #ifndef SDL_memcpy4
    1.29 -#define SDL_memcpy4(dst, src, len)	SDL_memcpy(dst, src, (len) << 2)
    1.30 -#endif
    1.31 -
    1.32 -#if defined(__GNUC__) && defined(i386)
    1.33 -#define SDL_revcpy(dst, src, len)			\
    1.34 -do {							\
    1.35 -	int u0, u1, u2;					\
    1.36 -	char *dstp = SDL_static_cast(char *, dst);			\
    1.37 -	char *srcp = SDL_static_cast(char *, src);			\
    1.38 -	int n = (len);					\
    1.39 -	if ( n >= 4 ) {					\
    1.40 -	__asm__ __volatile__ (				\
    1.41 -		"std\n\t"				\
    1.42 -		"rep ; movsl\n\t"			\
    1.43 -		"cld\n\t"				\
    1.44 -		: "=&c" (u0), "=&D" (u1), "=&S" (u2)	\
    1.45 -		: "0" (n >> 2),				\
    1.46 -		  "1" (dstp+(n-4)), "2" (srcp+(n-4))	\
    1.47 -		: "memory" );				\
    1.48 -	}						\
    1.49 -	switch (n & 3) {				\
    1.50 -		case 3: dstp[2] = srcp[2];		\
    1.51 -		case 2: dstp[1] = srcp[1];		\
    1.52 -		case 1: dstp[0] = srcp[0];		\
    1.53 -			break;				\
    1.54 -		default:				\
    1.55 -			break;				\
    1.56 -	}						\
    1.57 -} while(0)
    1.58 -#endif
    1.59 -#ifndef SDL_revcpy
    1.60 -extern DECLSPEC void *SDLCALL SDL_revcpy(void *dst, const void *src,
    1.61 -                                         size_t len);
    1.62 +#define SDL_memcpy4(dst, src, len)	SDL_memcpy((dst), (src), (len) << 2)
    1.63  #endif
    1.64  
    1.65  #ifdef HAVE_MEMMOVE
    1.66  #define SDL_memmove     memmove
    1.67 -#elif defined(HAVE_BCOPY)
    1.68 -#define SDL_memmove(d, s, n)	bcopy((s), (d), (n))
    1.69  #else
    1.70 -#define SDL_memmove(dst, src, len)			\
    1.71 -do {							\
    1.72 -	if ( dst < src ) {				\
    1.73 -		SDL_memcpy(dst, src, len);		\
    1.74 -	} else {					\
    1.75 -		SDL_revcpy(dst, src, len);		\
    1.76 -	}						\
    1.77 -} while(0)
    1.78 +extern DECLSPEC void *SDLCALL SDL_memmove(void *dst, const void *src,
    1.79 +                                          size_t len);
    1.80  #endif
    1.81  
    1.82  #ifdef HAVE_MEMCMP
     2.1 --- a/src/stdlib/SDL_string.c	Wed Feb 16 14:38:49 2011 -0800
     2.2 +++ b/src/stdlib/SDL_string.c	Wed Feb 16 15:25:10 2011 -0800
     2.3 @@ -265,31 +265,27 @@
     2.4  SDL_memset(void *dst, int c, size_t len)
     2.5  {
     2.6      size_t left = (len % 4);
     2.7 -    if (len >= 4) {
     2.8 -        Uint32 value = 0;
     2.9 -        Uint32 *dstp = (Uint32 *) dst;
    2.10 -        int i;
    2.11 -        for (i = 0; i < 4; ++i) {
    2.12 -            value <<= 8;
    2.13 -            value |= c;
    2.14 -        }
    2.15 -        len /= 4;
    2.16 -        while (len--) {
    2.17 -            *dstp++ = value;
    2.18 -        }
    2.19 +    Uint32 *dstp4;
    2.20 +    Uint8 *dstp1;
    2.21 +    Uint32 value4 = (c | (c << 8) | (c << 16) | (c << 24));
    2.22 +    Uint8 value1 = (Uint8) c;
    2.23 +
    2.24 +    dstp4 = (Uint32 *) dst;
    2.25 +    len /= 4;
    2.26 +    while (len--) {
    2.27 +        *dstp4++ = value4;
    2.28      }
    2.29 -    if (left > 0) {
    2.30 -        Uint8 value = (Uint8) c;
    2.31 -        Uint8 *dstp = (Uint8 *) dst;
    2.32 -        switch (left) {
    2.33 -        case 3:
    2.34 -            *dstp++ = value;
    2.35 -        case 2:
    2.36 -            *dstp++ = value;
    2.37 -        case 1:
    2.38 -            *dstp++ = value;
    2.39 -        }
    2.40 +
    2.41 +    dstp1 = (Uint8 *) dstp4;
    2.42 +    switch (left) {
    2.43 +    case 3:
    2.44 +        *dstp1++ = value1;
    2.45 +    case 2:
    2.46 +        *dstp1++ = value1;
    2.47 +    case 1:
    2.48 +        *dstp1++ = value1;
    2.49      }
    2.50 +
    2.51      return dst;
    2.52  }
    2.53  #endif
    2.54 @@ -298,25 +294,49 @@
    2.55  void *
    2.56  SDL_memcpy(void *dst, const void *src, size_t len)
    2.57  {
    2.58 -    char *srcp = (char *) src;
    2.59 -    char *dstp = (char *) dst;
    2.60 +    size_t left = (len % 4);
    2.61 +    Uint32 *srcp4, *dstp4;
    2.62 +    Uint8 *srcp1, *dstp1;
    2.63 +
    2.64 +    srcp4 = (Uint32 *) src;
    2.65 +    dstp4 = (Uint32 *) dst;
    2.66 +    len /= 4;
    2.67      while (len--) {
    2.68 -        *dstp++ = *srcp++;
    2.69 +        *dstp4++ = *srcp4++;
    2.70      }
    2.71 +
    2.72 +    srcp1 = (Uint8 *) srcp4;
    2.73 +    dstp1 = (Uint8 *) dstp4;
    2.74 +    switch (left) {
    2.75 +    case 3:
    2.76 +        *dstp1++ = *srcp1++;
    2.77 +    case 2:
    2.78 +        *dstp1++ = *srcp1++;
    2.79 +    case 1:
    2.80 +        *dstp1++ = *srcp1++;
    2.81 +    }
    2.82 +
    2.83      return dst;
    2.84  }
    2.85  #endif
    2.86  
    2.87 -#ifndef SDL_revcpy
    2.88 +#ifndef SDL_memmove
    2.89  void *
    2.90 -SDL_revcpy(void *dst, const void *src, size_t len)
    2.91 +SDL_memmove(void *dst, const void *src, size_t len)
    2.92  {
    2.93      char *srcp = (char *) src;
    2.94      char *dstp = (char *) dst;
    2.95 -    srcp += len - 1;
    2.96 -    dstp += len - 1;
    2.97 -    while (len--) {
    2.98 -        *dstp-- = *srcp--;
    2.99 +
   2.100 +    if (src < dst) {
   2.101 +        srcp += len - 1;
   2.102 +        dstp += len - 1;
   2.103 +        while (len--) {
   2.104 +            *dstp-- = *srcp--;
   2.105 +        }
   2.106 +    } else {
   2.107 +        while (len--) {
   2.108 +            *dstp++ = *srcp++;
   2.109 +        }
   2.110      }
   2.111      return dst;
   2.112  }
     3.1 --- a/src/video/SDL_blit.c	Wed Feb 16 14:38:49 2011 -0800
     3.2 +++ b/src/video/SDL_blit.c	Wed Feb 16 15:25:10 2011 -0800
     3.3 @@ -205,12 +205,7 @@
     3.4  
     3.5      /* Choose a standard blit function */
     3.6      if (map->identity && !(map->info.flags & ~SDL_COPY_RLE_DESIRED)) {
     3.7 -        /* Handle overlapping blits on the same surface */
     3.8 -        if (surface == dst) {
     3.9 -            blit = SDL_BlitCopyOverlap;
    3.10 -        } else {
    3.11 -            blit = SDL_BlitCopy;
    3.12 -        }
    3.13 +        blit = SDL_BlitCopy;
    3.14      } else if (surface->format->BitsPerPixel < 8) {
    3.15          blit = SDL_CalculateBlit0(surface);
    3.16      } else if (surface->format->BytesPerPixel == 1) {
     4.1 --- a/src/video/SDL_blit_copy.c	Wed Feb 16 14:38:49 2011 -0800
     4.2 +++ b/src/video/SDL_blit_copy.c	Wed Feb 16 15:25:10 2011 -0800
     4.3 @@ -96,6 +96,7 @@
     4.4  void
     4.5  SDL_BlitCopy(SDL_BlitInfo * info)
     4.6  {
     4.7 +    SDL_bool overlap;
     4.8      Uint8 *src, *dst;
     4.9      int w, h;
    4.10      int srcskip, dstskip;
    4.11 @@ -107,6 +108,21 @@
    4.12      srcskip = info->src_pitch;
    4.13      dstskip = info->dst_pitch;
    4.14  
    4.15 +    /* Properly handle overlapping blits */
    4.16 +    if (src < dst) {
    4.17 +        overlap = (dst < (src + h*srcskip));
    4.18 +    } else {
    4.19 +        overlap = (src < (dst + h*dstskip));
    4.20 +    }
    4.21 +    if (overlap) {
    4.22 +        while (h--) {
    4.23 +            SDL_memmove(dst, src, w);
    4.24 +            src += srcskip;
    4.25 +            dst += dstskip;
    4.26 +        }
    4.27 +        return;
    4.28 +    }
    4.29 +
    4.30  #ifdef __SSE__
    4.31      if (SDL_HasSSE() &&
    4.32          !((uintptr_t) src & 15) && !(srcskip & 15) &&
    4.33 @@ -141,29 +157,4 @@
    4.34      }
    4.35  }
    4.36  
    4.37 -void
    4.38 -SDL_BlitCopyOverlap(SDL_BlitInfo * info)
    4.39 -{
    4.40 -    Uint8 *src, *dst;
    4.41 -    int w, h;
    4.42 -    int skip;
    4.43 -
    4.44 -    w = info->dst_w * info->dst_fmt->BytesPerPixel;
    4.45 -    h = info->dst_h;
    4.46 -    src = info->src;
    4.47 -    dst = info->dst;
    4.48 -    skip = info->src_pitch;
    4.49 -    if ((dst < src) || (dst >= (src + h * skip))) {
    4.50 -        SDL_BlitCopy(info);
    4.51 -    } else {
    4.52 -        src += ((h - 1) * skip);
    4.53 -        dst += ((h - 1) * skip);
    4.54 -        while (h--) {
    4.55 -            SDL_revcpy(dst, src, w);
    4.56 -            src -= skip;
    4.57 -            dst -= skip;
    4.58 -        }
    4.59 -    }
    4.60 -}
    4.61 -
    4.62  /* vi: set ts=4 sw=4 expandtab: */
     5.1 --- a/src/video/SDL_blit_copy.h	Wed Feb 16 14:38:49 2011 -0800
     5.2 +++ b/src/video/SDL_blit_copy.h	Wed Feb 16 15:25:10 2011 -0800
     5.3 @@ -21,6 +21,5 @@
     5.4  */
     5.5  
     5.6  void SDL_BlitCopy(SDL_BlitInfo * info);
     5.7 -void SDL_BlitCopyOverlap(SDL_BlitInfo * info);
     5.8  
     5.9  /* vi: set ts=4 sw=4 expandtab: */