Merged improvements to SDL_SoftStretch() from SDL 1.2
authorSam Lantinga <slouken@libsdl.org>
Sun, 18 Oct 2009 17:49:40 +0000
changeset 3405 d5f2dd33f4eb
parent 3404 c9dcc73f6a36
child 3406 8ae607392409
Merged improvements to SDL_SoftStretch() from SDL 1.2
configure.in
include/SDL_config.h.in
src/video/SDL_stretch.c
--- a/configure.in	Sun Oct 18 16:14:35 2009 +0000
+++ b/configure.in	Sun Oct 18 17:49:40 2009 +0000
@@ -204,6 +204,15 @@
     if test x$ac_cv_func_strtod = xyes; then
         AC_DEFINE(HAVE_STRTOD)
     fi
+    AC_CHECK_FUNC(mprotect,
+        AC_TRY_COMPILE([
+          #include <sys/types.h>
+          #include <sys/mman.h>
+        ],[
+        ],[
+        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"])
--- a/include/SDL_config.h.in	Sun Oct 18 16:14:35 2009 +0000
+++ b/include/SDL_config.h.in	Sun Oct 18 17:49:40 2009 +0000
@@ -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 */
--- a/src/video/SDL_stretch.c	Sun Oct 18 16:14:35 2009 +0000
+++ b/src/video/SDL_stretch.c	Sun Oct 18 17:49:40 2009 +0000
@@ -42,6 +42,16 @@
 
 #ifdef USE_ASM_STRETCH
 
+#ifdef HAVE_MPROTECT
+#include <sys/types.h>
+#include <sys/mman.h>
+#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 @@
         int bpp;
         int src_w;
         int dst_w;
+        int status;
     } last;
 
     int i;
@@ -72,11 +83,12 @@
 
     /* 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 @@
         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 @@
     }
     *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 @@
     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 @@
 
 #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 @@
             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 @@
 #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;
     }