src/video/SDL_stretch.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. generate_rowbytes
  2. DEFINE_COPY_ROW
  3. DEFINE_COPY_ROW
  4. SDL_SoftStretch

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
   4 
   5     This library is free software; you can redistribute it and/or
   6     modify it under the terms of the GNU Library General Public
   7     License as published by the Free Software Foundation; either
   8     version 2 of the License, or (at your option) any later version.
   9 
  10     This library is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13     Library General Public License for more details.
  14 
  15     You should have received a copy of the GNU Library General Public
  16     License along with this library; if not, write to the Free
  17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 
  19     Sam Lantinga
  20     slouken@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_stretch.c,v 1.1.2.10 2001/02/22 00:21:51 hercules Exp $";
  26 #endif
  27 
  28 /* This a stretch blit implementation based on ideas given to me by
  29    Tomasz Cejner - thanks! :)
  30 
  31    April 27, 2000 - Sam Lantinga
  32 */
  33 
  34 #include "SDL_error.h"
  35 #include "SDL_video.h"
  36 #include "SDL_blit.h"
  37 
  38 /* This isn't ready for general consumption yet - it should be folded
  39    into the general blitting mechanism.
  40 */
  41 
  42 #if (defined(WIN32) && !defined(_M_ALPHA) && !defined(_WIN32_WCE)) || \
  43     defined(i386) && defined(__GNUC__) && defined(USE_ASMBLIT)
  44 #define USE_ASM_STRETCH
  45 #endif
  46 
  47 #ifdef USE_ASM_STRETCH
  48 
  49 #if defined(WIN32) || defined(i386)
  50 #define PREFIX16        0x66
  51 #define STORE_BYTE      0xAA
  52 #define STORE_WORD      0xAB
  53 #define LOAD_BYTE       0xAC
  54 #define LOAD_WORD       0xAD
  55 #define RETURN          0xC3
  56 #else
  57 #error Need assembly opcodes for this architecture
  58 #endif
  59 
  60 #if defined(__ELF__) && defined(__GNUC__)
  61 extern unsigned char _copy_row[4096] __attribute__ ((alias ("copy_row")));
  62 #endif
  63 static unsigned char copy_row[4096];
  64 
  65 static int generate_rowbytes(int src_w, int dst_w, int bpp)
     /* [<][>][^][v][top][bottom][index][help] */
  66 {
  67         static struct {
  68                 int bpp;
  69                 int src_w;
  70                 int dst_w;
  71         } last;
  72 
  73         int i;
  74         int pos, inc;
  75         unsigned char *eip;
  76         unsigned char load, store;
  77 
  78         /* See if we need to regenerate the copy buffer */
  79         if ( (src_w == last.src_w) &&
  80              (dst_w == last.src_w) && (bpp == last.bpp) ) {
  81                 return(0);
  82         }
  83         last.bpp = bpp;
  84         last.src_w = src_w;
  85         last.dst_w = dst_w;
  86 
  87         switch (bpp) {
  88             case 1:
  89                 load = LOAD_BYTE;
  90                 store = STORE_BYTE;
  91                 break;
  92             case 2:
  93             case 4:
  94                 load = LOAD_WORD;
  95                 store = STORE_WORD;
  96                 break;
  97             default:
  98                 SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
  99                 return(-1);
 100         }
 101         pos = 0x10000;
 102         inc = (src_w << 16) / dst_w;
 103         eip = copy_row;
 104         for ( i=0; i<dst_w; ++i ) {
 105                 while ( pos >= 0x10000L ) {
 106                         if ( bpp == 2 ) {
 107                                 *eip++ = PREFIX16;
 108                         }
 109                         *eip++ = load;
 110                         pos -= 0x10000L;
 111                 }
 112                 if ( bpp == 2 ) {
 113                         *eip++ = PREFIX16;
 114                 }
 115                 *eip++ = store;
 116                 pos += inc;
 117         }
 118         *eip++ = RETURN;
 119 
 120         /* Verify that we didn't overflow (too late) */
 121         if ( eip > (copy_row+sizeof(copy_row)) ) {
 122                 SDL_SetError("Copy buffer overflow");
 123                 return(-1);
 124         }
 125         return(0);
 126 }
 127 
 128 #else
 129 
 130 #define DEFINE_COPY_ROW(name, type)                     \
     /* [<][>][^][v][top][bottom][index][help] */
 131 void name(type *src, int src_w, type *dst, int dst_w)   \
 132 {                                                       \
 133         int i;                                          \
 134         int pos, inc;                                   \
 135         type pixel = 0;                                 \
 136                                                         \
 137         pos = 0x10000;                                  \
 138         inc = (src_w << 16) / dst_w;                    \
 139         for ( i=dst_w; i>0; --i ) {                     \
 140                 while ( pos >= 0x10000L ) {             \
 141                         pixel = *src++;                 \
 142                         pos -= 0x10000L;                \
 143                 }                                       \
 144                 *dst++ = pixel;                         \
 145                 pos += inc;                             \
 146         }                                               \
 147 }
 148 DEFINE_COPY_ROW(copy_row1, Uint8)
     /* [<][>][^][v][top][bottom][index][help] */
 149 DEFINE_COPY_ROW(copy_row2, Uint16)
 150 DEFINE_COPY_ROW(copy_row4, Uint32)
 151 
 152 #endif /* USE_ASM_STRETCH */
 153 
 154 /* The ASM code doesn't handle 24-bpp stretch blits */
 155 void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w)
 156 {
 157         int i;
 158         int pos, inc;
 159         Uint8 pixel[3];
 160 
 161         pos = 0x10000;
 162         inc = (src_w << 16) / dst_w;
 163         for ( i=dst_w; i>0; --i ) {
 164                 while ( pos >= 0x10000L ) {
 165                         pixel[0] = *src++;
 166                         pixel[1] = *src++;
 167                         pixel[2] = *src++;
 168                         pos -= 0x10000L;
 169                 }
 170                 *dst++ = pixel[0];
 171                 *dst++ = pixel[1];
 172                 *dst++ = pixel[2];
 173                 pos += inc;
 174         }
 175 }
 176 
 177 /* Perform a stretch blit between two surfaces of the same format.
 178    NOTE:  This function is not safe to call from multiple threads!
 179 */
 180 int SDL_SoftStretch(SDL_Surface *src, SDL_Rect *srcrect,
     /* [<][>][^][v][top][bottom][index][help] */
 181                     SDL_Surface *dst, SDL_Rect *dstrect)
 182 {
 183         int pos, inc;
 184         int dst_width;
 185         int dst_maxrow;
 186         int src_row, dst_row;
 187         Uint8 *srcp = NULL;
 188         Uint8 *dstp;
 189         SDL_Rect full_src;
 190         SDL_Rect full_dst;
 191 #if defined(USE_ASM_STRETCH) && defined(__GNUC__)
 192         int u1, u2;
 193 #endif
 194         const int bpp = dst->format->BytesPerPixel;
 195 
 196         if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
 197                 SDL_SetError("Only works with same format surfaces");
 198                 return(-1);
 199         }
 200 
 201         /* Verify the blit rectangles */
 202         if ( srcrect ) {
 203                 if ( (srcrect->x < 0) || (srcrect->y < 0) ||
 204                      ((srcrect->x+srcrect->w) > src->w) ||
 205                      ((srcrect->y+srcrect->h) > src->h) ) {
 206                         SDL_SetError("Invalid source blit rectangle");
 207                         return(-1);
 208                 }
 209         } else {
 210                 full_src.x = 0;
 211                 full_src.y = 0;
 212                 full_src.w = src->w;
 213                 full_src.h = src->h;
 214                 srcrect = &full_src;
 215         }
 216         if ( dstrect ) {
 217                 if ( (dstrect->x < 0) || (dstrect->y < 0) ||
 218                      ((dstrect->x+dstrect->w) > dst->w) ||
 219                      ((dstrect->y+dstrect->h) > dst->h) ) {
 220                         SDL_SetError("Invalid destination blit rectangle");
 221                         return(-1);
 222                 }
 223         } else {
 224                 full_dst.x = 0;
 225                 full_dst.y = 0;
 226                 full_dst.w = dst->w;
 227                 full_dst.h = dst->h;
 228                 dstrect = &full_dst;
 229         }
 230 
 231         /* Set up the data... */
 232         pos = 0x10000;
 233         inc = (srcrect->h << 16) / dstrect->h;
 234         src_row = srcrect->y;
 235         dst_row = dstrect->y;
 236         dst_width = dstrect->w*bpp;
 237 
 238 #ifdef USE_ASM_STRETCH
 239         /* Write the opcodes for this stretch */
 240         if ( (bpp != 3) &&
 241              (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) {
 242                 return(-1);
 243         }
 244 #endif
 245 
 246         /* Perform the stretch blit */
 247         for ( dst_maxrow = dst_row+dstrect->h; dst_row<dst_maxrow; ++dst_row ) {
 248                 dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch)
 249                                             + (dstrect->x*bpp);
 250                 while ( pos >= 0x10000L ) {
 251                         srcp = (Uint8 *)src->pixels + (src_row*src->pitch)
 252                                                     + (srcrect->x*bpp);
 253                         ++src_row;
 254                         pos -= 0x10000L;
 255                 }
 256 #ifdef USE_ASM_STRETCH
 257                 switch (bpp) {
 258                     case 3:
 259                         copy_row3(srcp, srcrect->w, dstp, dstrect->w);
 260                         break;
 261                     default:
 262 #ifdef __GNUC__
 263                         __asm__ __volatile__ ("
 264                                 call _copy_row
 265                         "
 266                         : "=&D" (u1), "=&S" (u2)
 267                         : "0" (dstp), "1" (srcp)
 268                         : "memory" );
 269 #else
 270 #ifdef WIN32
 271                 { void *code = &copy_row;
 272                         __asm {
 273                                 push edi
 274                                 push esi
 275         
 276                                 mov edi, dstp
 277                                 mov esi, srcp
 278                                 call dword ptr code
 279 
 280                                 pop esi
 281                                 pop edi
 282                         }
 283                 }
 284 #else
 285 #error Need inline assembly for this compiler
 286 #endif
 287 #endif /* __GNUC__ */
 288                         break;
 289                 }
 290 #else
 291                 switch (bpp) {
 292                     case 1:
 293                         copy_row1(srcp, srcrect->w, dstp, dstrect->w);
 294                         break;
 295                     case 2:
 296                         copy_row2((Uint16 *)srcp, srcrect->w,
 297                                   (Uint16 *)dstp, dstrect->w);
 298                         break;
 299                     case 3:
 300                         copy_row3(srcp, srcrect->w, dstp, dstrect->w);
 301                         break;
 302                     case 4:
 303                         copy_row4((Uint32 *)srcp, srcrect->w,
 304                                   (Uint32 *)dstp, dstrect->w);
 305                         break;
 306                 }
 307 #endif
 308                 pos += inc;
 309         }
 310         return(0);
 311 }
 312 

/* [<][>][^][v][top][bottom][index][help] */