From 6803a1c9a5e7752f3ade25be3e2b0c6dc5b5a308 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 18 Oct 2009 17:49:40 +0000 Subject: [PATCH] Merged improvements to SDL_SoftStretch() from SDL 1.2 --- configure.in | 9 +++ include/SDL_config.h.in | 1 + src/video/SDL_stretch.c | 128 ++++++++++++++++++++++++---------------- 3 files changed, 87 insertions(+), 51 deletions(-) diff --git a/configure.in b/configure.in index 591e835c9..7cd5c1dde 100644 --- a/configure.in +++ b/configure.in @@ -204,6 +204,15 @@ if test x$enable_libc = xyes; then if test x$ac_cv_func_strtod = xyes; then AC_DEFINE(HAVE_STRTOD) fi + AC_CHECK_FUNC(mprotect, + AC_TRY_COMPILE([ + #include + #include + ],[ + ],[ + AC_DEFINE(HAVE_MPROTECT) + ]), + ) AC_CHECK_FUNCS(malloc calloc realloc free getenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp sscanf snprintf vsnprintf sigaction setjmp nanosleep) AC_CHECK_LIB(m, pow, [LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm"]) diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index f0856b9dc..804cccc72 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -151,6 +151,7 @@ #undef HAVE_NANOSLEEP #undef HAVE_CLOCK_GETTIME #undef HAVE_GETPAGESIZE +#undef HAVE_MPROTECT #else /* We may need some replacement for stdarg.h here */ diff --git a/src/video/SDL_stretch.c b/src/video/SDL_stretch.c index e1160dc0a..78f3b1175 100644 --- a/src/video/SDL_stretch.c +++ b/src/video/SDL_stretch.c @@ -42,6 +42,16 @@ #ifdef USE_ASM_STRETCH +#ifdef HAVE_MPROTECT +#include +#include +#endif +#ifdef __GNUC__ +#define PAGE_ALIGNED __attribute__((__aligned__(4096))) +#else +#define PAGE_ALIGNED +#endif + #if defined(_M_IX86) || defined(i386) #define PREFIX16 0x66 #define STORE_BYTE 0xAA @@ -53,7 +63,7 @@ #error Need assembly opcodes for this architecture #endif -static unsigned char copy_row[4096]; +static unsigned char copy_row[4096] PAGE_ALIGNED; static int generate_rowbytes(int src_w, int dst_w, int bpp) @@ -63,6 +73,7 @@ generate_rowbytes(int src_w, int dst_w, int bpp) int bpp; int src_w; int dst_w; + int status; } last; int i; @@ -72,11 +83,12 @@ generate_rowbytes(int src_w, int dst_w, int bpp) /* See if we need to regenerate the copy buffer */ if ((src_w == last.src_w) && (dst_w == last.dst_w) && (bpp == last.bpp)) { - return (0); + return (last.status); } last.bpp = bpp; last.src_w = src_w; last.dst_w = dst_w; + last.status = -1; switch (bpp) { case 1: @@ -92,6 +104,13 @@ generate_rowbytes(int src_w, int dst_w, int bpp) SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp); return (-1); } +#ifdef HAVE_MPROTECT + /* Make the code writeable */ + if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_WRITE) < 0) { + SDL_SetError("Couldn't make copy buffer writeable"); + return (-1); + } +#endif pos = 0x10000; inc = (src_w << 16) / dst_w; eip = copy_row; @@ -111,47 +130,55 @@ generate_rowbytes(int src_w, int dst_w, int bpp) } *eip++ = RETURN; - /* Verify that we didn't overflow (too late) */ + /* Verify that we didn't overflow (too late!!!) */ if (eip > (copy_row + sizeof(copy_row))) { SDL_SetError("Copy buffer overflow"); return (-1); } +#ifdef HAVE_MPROTECT + /* Make the code executable but not writeable */ + if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_EXEC) < 0) { + SDL_SetError("Couldn't make copy buffer executable"); + return (-1); + } +#endif + last.status = 0; return (0); } -#else +#endif /* USE_ASM_STRETCH */ -#define DEFINE_COPY_ROW(name, type) \ -void name(type *src, int src_w, type *dst, int dst_w) \ -{ \ - int i; \ - int pos, inc; \ - type pixel = 0; \ - \ - pos = 0x10000; \ - inc = (src_w << 16) / dst_w; \ - for ( i=dst_w; i>0; --i ) { \ - while ( pos >= 0x10000L ) { \ - pixel = *src++; \ - pos -= 0x10000L; \ - } \ - *dst++ = pixel; \ - pos += inc; \ - } \ +#define DEFINE_COPY_ROW(name, type) \ +void name(type *src, int src_w, type *dst, int dst_w) \ +{ \ + int i; \ + int pos, inc; \ + type pixel = 0; \ + \ + pos = 0x10000; \ + inc = (src_w << 16) / dst_w; \ + for ( i=dst_w; i>0; --i ) { \ + while ( pos >= 0x10000L ) { \ + pixel = *src++; \ + pos -= 0x10000L; \ + } \ + *dst++ = pixel; \ + pos += inc; \ + } \ } /* *INDENT-OFF* */ DEFINE_COPY_ROW(copy_row1, Uint8) DEFINE_COPY_ROW(copy_row2, Uint16) DEFINE_COPY_ROW(copy_row4, Uint32) /* *INDENT-ON* */ -#endif /* USE_ASM_STRETCH */ + /* The ASM code doesn't handle 24-bpp stretch blits */ void copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w) { int i; int pos, inc; - Uint8 pixel[3]; + Uint8 pixel[3] = { 0, 0, 0 }; pos = 0x10000; inc = (src_w << 16) / dst_w; @@ -186,9 +213,12 @@ SDL_SoftStretch(SDL_Surface * src, const SDL_Rect * srcrect, Uint8 *dstp; SDL_Rect full_src; SDL_Rect full_dst; -#if defined(USE_ASM_STRETCH) && defined(__GNUC__) +#ifdef USE_ASM_STRETCH + SDL_bool use_asm = SDL_TRUE; +#ifdef __GNUC__ int u1, u2; #endif +#endif /* USE_ASM_STRETCH */ const int bpp = dst->format->BytesPerPixel; if (src->format->BitsPerPixel != dst->format->BitsPerPixel) { @@ -257,8 +287,8 @@ SDL_SoftStretch(SDL_Surface * src, const SDL_Rect * srcrect, #ifdef USE_ASM_STRETCH /* Write the opcodes for this stretch */ - if ((bpp != 3) && (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) { - return (-1); + if ((bpp == 3) || (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) { + use_asm = SDL_FALSE; } #endif @@ -273,13 +303,11 @@ SDL_SoftStretch(SDL_Surface * src, const SDL_Rect * srcrect, pos -= 0x10000L; } #ifdef USE_ASM_STRETCH - switch (bpp) { - case 3: - copy_row3(srcp, srcrect->w, dstp, dstrect->w); - break; - default: + if (use_asm) { #ifdef __GNUC__ - __asm__ __volatile__("call *%4": "=&D"(u1), "=&S"(u2): "0"(dstp), "1"(srcp), "r"(copy_row):"memory"); + __asm__ __volatile__("call *%4":"=&D"(u1), "=&S"(u2) + :"0"(dstp), "1"(srcp), "r"(copy_row) + :"memory"); #elif defined(_MSC_VER) || defined(__WATCOMC__) /* *INDENT-OFF* */ { @@ -298,26 +326,24 @@ SDL_SoftStretch(SDL_Surface * src, const SDL_Rect * srcrect, #else #error Need inline assembly for this compiler #endif - break; - } -#else - switch (bpp) { - case 1: - copy_row1(srcp, srcrect->w, dstp, dstrect->w); - break; - case 2: - copy_row2((Uint16 *) srcp, srcrect->w, - (Uint16 *) dstp, dstrect->w); - break; - case 3: - copy_row3(srcp, srcrect->w, dstp, dstrect->w); - break; - case 4: - copy_row4((Uint32 *) srcp, srcrect->w, - (Uint32 *) dstp, dstrect->w); - break; - } + } else #endif + switch (bpp) { + case 1: + copy_row1(srcp, srcrect->w, dstp, dstrect->w); + break; + case 2: + copy_row2((Uint16 *) srcp, srcrect->w, + (Uint16 *) dstp, dstrect->w); + break; + case 3: + copy_row3(srcp, srcrect->w, dstp, dstrect->w); + break; + case 4: + copy_row4((Uint32 *) srcp, srcrect->w, + (Uint32 *) dstp, dstrect->w); + break; + } pos += inc; }