src/video/SDL_blit.h
author Sam Lantinga
Mon, 08 Dec 2008 00:27:32 +0000
changeset 2859 99210400e8b9
parent 2853 6258fa7cd300
child 2898 e40448bc7727
permissions -rw-r--r--
Updated copyright date
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 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     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #ifndef _SDL_blit_h
    25 #define _SDL_blit_h
    26 
    27 #ifdef __MMX__
    28 #include <mmintrin.h>
    29 #endif
    30 #ifdef __3dNOW__
    31 #include <mm3dnow.h>
    32 #endif
    33 #ifdef __SSE__
    34 #include <xmmintrin.h>
    35 #endif
    36 #ifdef __SSE2__
    37 #include <emmintrin.h>
    38 #endif
    39 
    40 #include "SDL_cpuinfo.h"
    41 #include "SDL_endian.h"
    42 
    43 /* SDL blit copy flags */
    44 #define SDL_COPY_MODULATE_COLOR     0x00000001
    45 #define SDL_COPY_MODULATE_ALPHA     0x00000002
    46 #define SDL_COPY_MASK               0x00000010
    47 #define SDL_COPY_BLEND              0x00000020
    48 #define SDL_COPY_ADD                0x00000040
    49 #define SDL_COPY_MOD                0x00000080
    50 #define SDL_COPY_COLORKEY           0x00000100
    51 #define SDL_COPY_NEAREST            0x00000200
    52 #define SDL_COPY_RLE_DESIRED        0x00001000
    53 #define SDL_COPY_RLE_COLORKEY       0x00002000
    54 #define SDL_COPY_RLE_ALPHAKEY       0x00004000
    55 #define SDL_COPY_RLE_MASK           (SDL_COPY_RLE_DESIRED|SDL_COPY_RLE_COLORKEY|SDL_COPY_RLE_ALPHAKEY)
    56 
    57 /* SDL blit CPU flags */
    58 #define SDL_CPU_ANY                 0x00000000
    59 #define SDL_CPU_MMX                 0x00000001
    60 #define SDL_CPU_3DNOW               0x00000002
    61 #define SDL_CPU_SSE                 0x00000004
    62 #define SDL_CPU_SSE2                0x00000008
    63 #define SDL_CPU_ALTIVEC_PREFETCH    0x00000010
    64 #define SDL_CPU_ALTIVEC_NOPREFETCH  0x00000020
    65 
    66 typedef struct
    67 {
    68     Uint8 *src;
    69     int src_w, src_h;
    70     int src_pitch;
    71     int src_skip;
    72     Uint8 *dst;
    73     int dst_w, dst_h;
    74     int dst_pitch;
    75     int dst_skip;
    76     SDL_PixelFormat *src_fmt;
    77     SDL_PixelFormat *dst_fmt;
    78     Uint8 *table;
    79     int flags;
    80     Uint32 colorkey;
    81     Uint8 r, g, b, a;
    82 } SDL_BlitInfo;
    83 
    84 typedef void (SDLCALL * SDL_BlitFunc) (SDL_BlitInfo * info);
    85 
    86 typedef struct
    87 {
    88     Uint32 src_format;
    89     Uint32 dst_format;
    90     int flags;
    91     int cpu;
    92     SDL_BlitFunc func;
    93 } SDL_BlitFuncEntry;
    94 
    95 /* Blit mapping definition */
    96 typedef struct SDL_BlitMap
    97 {
    98     SDL_Surface *dst;
    99     int identity;
   100     SDL_blit blit;
   101     void *data;
   102     SDL_BlitInfo info;
   103 
   104     /* the version count matches the destination; mismatch indicates
   105        an invalid mapping */
   106     unsigned int format_version;
   107 } SDL_BlitMap;
   108 
   109 /* Functions found in SDL_blit.c */
   110 extern int SDL_CalculateBlit(SDL_Surface * surface);
   111 
   112 /* Functions found in SDL_blit_*.c */
   113 extern SDL_BlitFunc SDL_CalculateBlit0(SDL_Surface * surface);
   114 extern SDL_BlitFunc SDL_CalculateBlit1(SDL_Surface * surface);
   115 extern SDL_BlitFunc SDL_CalculateBlitN(SDL_Surface * surface);
   116 extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface * surface);
   117 
   118 /*
   119  * Useful macros for blitting routines
   120  */
   121 
   122 #if defined(__GNUC__)
   123 #define DECLARE_ALIGNED(t,v,a)  t __attribute__((aligned(a))) v
   124 #elif defined(_MSC_VER)
   125 #define DECLARE_ALIGNED(t,v,a)  __declspec(align(a)) t v
   126 #else
   127 #define DECLARE_ALIGNED(t,v,a)  t v
   128 #endif
   129 
   130 #define FORMAT_EQUAL(A, B)						\
   131     ((A)->BitsPerPixel == (B)->BitsPerPixel				\
   132      && ((A)->Rmask == (B)->Rmask) && ((A)->Amask == (B)->Amask))
   133 
   134 /* Load pixel of the specified format from a buffer and get its R-G-B values */
   135 /* FIXME: rescale values to 0..255 here? */
   136 #define RGB_FROM_PIXEL(Pixel, fmt, r, g, b)				\
   137 {									\
   138 	r = (((Pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss); 		\
   139 	g = (((Pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss); 		\
   140 	b = (((Pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss); 		\
   141 }
   142 #define RGB_FROM_RGB565(Pixel, r, g, b)					\
   143 {									\
   144 	r = (((Pixel&0xF800)>>11)<<3);		 			\
   145 	g = (((Pixel&0x07E0)>>5)<<2); 					\
   146 	b = ((Pixel&0x001F)<<3); 					\
   147 }
   148 #define RGB_FROM_RGB555(Pixel, r, g, b)					\
   149 {									\
   150 	r = (((Pixel&0x7C00)>>10)<<3);		 			\
   151 	g = (((Pixel&0x03E0)>>5)<<3); 					\
   152 	b = ((Pixel&0x001F)<<3); 					\
   153 }
   154 #define RGB_FROM_RGB888(Pixel, r, g, b)					\
   155 {									\
   156 	r = ((Pixel&0xFF0000)>>16);		 			\
   157 	g = ((Pixel&0xFF00)>>8);		 			\
   158 	b = (Pixel&0xFF);			 			\
   159 }
   160 #define RETRIEVE_RGB_PIXEL(buf, bpp, Pixel)				   \
   161 do {									   \
   162 	switch (bpp) {							   \
   163 		case 2:							   \
   164 			Pixel = *((Uint16 *)(buf));			   \
   165 		break;							   \
   166 									   \
   167 		case 3: {						   \
   168 		        Uint8 *B = (Uint8 *)(buf);			   \
   169 			if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
   170 			        Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \
   171 			} else {					   \
   172 			        Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \
   173 			}						   \
   174 		}							   \
   175 		break;							   \
   176 									   \
   177 		case 4:							   \
   178 			Pixel = *((Uint32 *)(buf));			   \
   179 		break;							   \
   180 									   \
   181 		default:						   \
   182 		        Pixel; /* stop gcc complaints */		   \
   183 		break;							   \
   184 	}								   \
   185 } while (0)
   186 
   187 #define DISEMBLE_RGB(buf, bpp, fmt, Pixel, r, g, b)			   \
   188 do {									   \
   189 	switch (bpp) {							   \
   190 		case 2:							   \
   191 			Pixel = *((Uint16 *)(buf));			   \
   192 			RGB_FROM_PIXEL(Pixel, fmt, r, g, b);		   \
   193 		break;							   \
   194 									   \
   195 		case 3:	{						   \
   196                         if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
   197 			        r = *((buf)+fmt->Rshift/8);		   \
   198 				g = *((buf)+fmt->Gshift/8);		   \
   199 				b = *((buf)+fmt->Bshift/8);		   \
   200 			} else {					   \
   201 			        r = *((buf)+2-fmt->Rshift/8);		   \
   202 				g = *((buf)+2-fmt->Gshift/8);		   \
   203 				b = *((buf)+2-fmt->Bshift/8);		   \
   204 			}						   \
   205 		}							   \
   206 		break;							   \
   207 									   \
   208 		case 4:							   \
   209 			Pixel = *((Uint32 *)(buf));			   \
   210 			RGB_FROM_PIXEL(Pixel, fmt, r, g, b);		   \
   211 		break;							   \
   212 									   \
   213 		default:						   \
   214 		        Pixel; /* stop gcc complaints */		   \
   215 		break;							   \
   216 	}								   \
   217 } while (0)
   218 
   219 /* Assemble R-G-B values into a specified pixel format and store them */
   220 #define PIXEL_FROM_RGB(Pixel, fmt, r, g, b)				\
   221 {									\
   222 	Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|				\
   223 		((g>>fmt->Gloss)<<fmt->Gshift)|				\
   224 		((b>>fmt->Bloss)<<fmt->Bshift);				\
   225 }
   226 #define RGB565_FROM_RGB(Pixel, r, g, b)					\
   227 {									\
   228 	Pixel = ((r>>3)<<11)|((g>>2)<<5)|(b>>3);			\
   229 }
   230 #define RGB555_FROM_RGB(Pixel, r, g, b)					\
   231 {									\
   232 	Pixel = ((r>>3)<<10)|((g>>3)<<5)|(b>>3);			\
   233 }
   234 #define RGB888_FROM_RGB(Pixel, r, g, b)					\
   235 {									\
   236 	Pixel = (r<<16)|(g<<8)|b;					\
   237 }
   238 #define ASSEMBLE_RGB(buf, bpp, fmt, r, g, b) 				\
   239 {									\
   240 	switch (bpp) {							\
   241 		case 2: {						\
   242 			Uint16 Pixel;					\
   243 									\
   244 			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
   245 			*((Uint16 *)(buf)) = Pixel;			\
   246 		}							\
   247 		break;							\
   248 									\
   249 		case 3: {						\
   250                         if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
   251 			        *((buf)+fmt->Rshift/8) = r;		\
   252 				*((buf)+fmt->Gshift/8) = g;		\
   253 				*((buf)+fmt->Bshift/8) = b;		\
   254 			} else {					\
   255 			        *((buf)+2-fmt->Rshift/8) = r;		\
   256 				*((buf)+2-fmt->Gshift/8) = g;		\
   257 				*((buf)+2-fmt->Bshift/8) = b;		\
   258 			}						\
   259 		}							\
   260 		break;							\
   261 									\
   262 		case 4: {						\
   263 			Uint32 Pixel;					\
   264 									\
   265 			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
   266 			*((Uint32 *)(buf)) = Pixel;			\
   267 		}							\
   268 		break;							\
   269 	}								\
   270 }
   271 #define ASSEMBLE_RGB_AMASK(buf, bpp, fmt, r, g, b, Amask)		\
   272 {									\
   273 	switch (bpp) {							\
   274 		case 2: {						\
   275 			Uint16 *bufp;					\
   276 			Uint16 Pixel;					\
   277 									\
   278 			bufp = (Uint16 *)buf;				\
   279 			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
   280 			*bufp = Pixel | (*bufp & Amask);		\
   281 		}							\
   282 		break;							\
   283 									\
   284 		case 3: {						\
   285                         if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
   286 			        *((buf)+fmt->Rshift/8) = r;		\
   287 				*((buf)+fmt->Gshift/8) = g;		\
   288 				*((buf)+fmt->Bshift/8) = b;		\
   289 			} else {					\
   290 			        *((buf)+2-fmt->Rshift/8) = r;		\
   291 				*((buf)+2-fmt->Gshift/8) = g;		\
   292 				*((buf)+2-fmt->Bshift/8) = b;		\
   293 			}						\
   294 		}							\
   295 		break;							\
   296 									\
   297 		case 4: {						\
   298 			Uint32 *bufp;					\
   299 			Uint32 Pixel;					\
   300 									\
   301 			bufp = (Uint32 *)buf;				\
   302 			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
   303 			*bufp = Pixel | (*bufp & Amask);		\
   304 		}							\
   305 		break;							\
   306 	}								\
   307 }
   308 
   309 /* FIXME: Should we rescale alpha into 0..255 here? */
   310 #define RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a)				\
   311 {									\
   312 	r = ((Pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss; 		\
   313 	g = ((Pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss; 		\
   314 	b = ((Pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss; 		\
   315 	a = ((Pixel&fmt->Amask)>>fmt->Ashift)<<fmt->Aloss;	 	\
   316 }
   317 #define RGBA_FROM_8888(Pixel, fmt, r, g, b, a)	\
   318 {						\
   319 	r = (Pixel&fmt->Rmask)>>fmt->Rshift;	\
   320 	g = (Pixel&fmt->Gmask)>>fmt->Gshift;	\
   321 	b = (Pixel&fmt->Bmask)>>fmt->Bshift;	\
   322 	a = (Pixel&fmt->Amask)>>fmt->Ashift;	\
   323 }
   324 #define RGBA_FROM_RGBA8888(Pixel, r, g, b, a)				\
   325 {									\
   326 	r = (Pixel>>24);						\
   327 	g = ((Pixel>>16)&0xFF);						\
   328 	b = ((Pixel>>8)&0xFF);						\
   329 	a = (Pixel&0xFF);						\
   330 }
   331 #define RGBA_FROM_ARGB8888(Pixel, r, g, b, a)				\
   332 {									\
   333 	r = ((Pixel>>16)&0xFF);						\
   334 	g = ((Pixel>>8)&0xFF);						\
   335 	b = (Pixel&0xFF);						\
   336 	a = (Pixel>>24);						\
   337 }
   338 #define RGBA_FROM_ABGR8888(Pixel, r, g, b, a)				\
   339 {									\
   340 	r = (Pixel&0xFF);						\
   341 	g = ((Pixel>>8)&0xFF);						\
   342 	b = ((Pixel>>16)&0xFF);						\
   343 	a = (Pixel>>24);						\
   344 }
   345 #define DISEMBLE_RGBA(buf, bpp, fmt, Pixel, r, g, b, a)			   \
   346 do {									   \
   347 	switch (bpp) {							   \
   348 		case 2:							   \
   349 			Pixel = *((Uint16 *)(buf));			   \
   350 			RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a);	   \
   351 		break;							   \
   352 									   \
   353 		case 3:	{						   \
   354                         if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
   355 			        r = *((buf)+fmt->Rshift/8);		   \
   356 				g = *((buf)+fmt->Gshift/8);		   \
   357 				b = *((buf)+fmt->Bshift/8);		   \
   358 			} else {					   \
   359 			        r = *((buf)+2-fmt->Rshift/8);		   \
   360 				g = *((buf)+2-fmt->Gshift/8);		   \
   361 				b = *((buf)+2-fmt->Bshift/8);		   \
   362 			}						   \
   363 			a = 0xFF;					   \
   364 		}							   \
   365 		break;							   \
   366 									   \
   367 		case 4:							   \
   368 			Pixel = *((Uint32 *)(buf));			   \
   369 			RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a);	   \
   370 		break;							   \
   371 									   \
   372 		default:						   \
   373 		        Pixel; /* stop gcc complaints */		   \
   374 		break;							   \
   375 	}								   \
   376 } while (0)
   377 
   378 /* FIXME: this isn't correct, especially for Alpha (maximum != 255) */
   379 #define PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a)				\
   380 {									\
   381 	Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|				\
   382 		((g>>fmt->Gloss)<<fmt->Gshift)|				\
   383 		((b>>fmt->Bloss)<<fmt->Bshift)|				\
   384 		((a>>fmt->Aloss)<<fmt->Ashift);				\
   385 }
   386 #define ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a)			\
   387 {									\
   388 	switch (bpp) {							\
   389 		case 2: {						\
   390 			Uint16 Pixel;					\
   391 									\
   392 			PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a);	\
   393 			*((Uint16 *)(buf)) = Pixel;			\
   394 		}							\
   395 		break;							\
   396 									\
   397 		case 3: {						\
   398                         if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
   399 			        *((buf)+fmt->Rshift/8) = r;		\
   400 				*((buf)+fmt->Gshift/8) = g;		\
   401 				*((buf)+fmt->Bshift/8) = b;		\
   402 			} else {					\
   403 			        *((buf)+2-fmt->Rshift/8) = r;		\
   404 				*((buf)+2-fmt->Gshift/8) = g;		\
   405 				*((buf)+2-fmt->Bshift/8) = b;		\
   406 			}						\
   407 		}							\
   408 		break;							\
   409 									\
   410 		case 4: {						\
   411 			Uint32 Pixel;					\
   412 									\
   413 			PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a);	\
   414 			*((Uint32 *)(buf)) = Pixel;			\
   415 		}							\
   416 		break;							\
   417 	}								\
   418 }
   419 
   420 /* Blend the RGB values of two Pixels based on a source alpha value */
   421 #define ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB)	\
   422 do {						\
   423 	dR = (((sR-dR)*(A))>>8)+dR;		\
   424 	dG = (((sG-dG)*(A))>>8)+dG;		\
   425 	dB = (((sB-dB)*(A))>>8)+dB;		\
   426 } while(0)
   427 
   428 /* Blend the RGB values of two Pixels based on a source alpha value */
   429 #define ACCURATE_ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB)	\
   430 do {						\
   431     unsigned tR, tG, tB, tA; \
   432     tA = 255 - sA; \
   433     tR = 1 + (sR * sA) + (dR * tA); \
   434     dR = (tR + (tR >> 8)) >> 8; \
   435     tG = 1 + (sG * sA) + (dG * tA); \
   436     dG = (tG + (tG >> 8)) >> 8; \
   437     tB = 1 + (sB * sA) + (dB * tA); \
   438     dB = (tB + (tB >> 8)) >> 8; \
   439 } while(0)
   440 
   441 
   442 /* This is a very useful loop for optimizing blitters */
   443 #if defined(_MSC_VER) && (_MSC_VER == 1300)
   444 /* There's a bug in the Visual C++ 7 optimizer when compiling this code */
   445 #else
   446 #define USE_DUFFS_LOOP
   447 #endif
   448 #ifdef USE_DUFFS_LOOP
   449 
   450 /* 8-times unrolled loop */
   451 #define DUFFS_LOOP8(pixel_copy_increment, width)			\
   452 { int n = (width+7)/8;							\
   453 	switch (width & 7) {						\
   454 	case 0: do {	pixel_copy_increment;				\
   455 	case 7:		pixel_copy_increment;				\
   456 	case 6:		pixel_copy_increment;				\
   457 	case 5:		pixel_copy_increment;				\
   458 	case 4:		pixel_copy_increment;				\
   459 	case 3:		pixel_copy_increment;				\
   460 	case 2:		pixel_copy_increment;				\
   461 	case 1:		pixel_copy_increment;				\
   462 		} while ( --n > 0 );					\
   463 	}								\
   464 }
   465 
   466 /* 4-times unrolled loop */
   467 #define DUFFS_LOOP4(pixel_copy_increment, width)			\
   468 { int n = (width+3)/4;							\
   469 	switch (width & 3) {						\
   470 	case 0: do {	pixel_copy_increment;				\
   471 	case 3:		pixel_copy_increment;				\
   472 	case 2:		pixel_copy_increment;				\
   473 	case 1:		pixel_copy_increment;				\
   474 		} while ( --n > 0 );					\
   475 	}								\
   476 }
   477 
   478 /* 2 - times unrolled loop */
   479 #define DUFFS_LOOP_DOUBLE2(pixel_copy_increment,			\
   480 				double_pixel_copy_increment, width)	\
   481 { int n, w = width;							\
   482 	if( w & 1 ) {							\
   483 	    pixel_copy_increment;					\
   484 	    w--;							\
   485 	}								\
   486 	if ( w > 0 )	{						\
   487 	    n = ( w + 2) / 4;						\
   488 	    switch( w & 2 ) {						\
   489 	    case 0: do {	double_pixel_copy_increment;		\
   490 	    case 2:		double_pixel_copy_increment;		\
   491 		    } while ( --n > 0 );					\
   492 	    }								\
   493 	}								\
   494 }
   495 
   496 /* 2 - times unrolled loop 4 pixels */
   497 #define DUFFS_LOOP_QUATRO2(pixel_copy_increment,			\
   498 				double_pixel_copy_increment,		\
   499 				quatro_pixel_copy_increment, width)	\
   500 { int n, w = width;								\
   501         if(w & 1) {							\
   502 	  pixel_copy_increment;						\
   503 	  w--;								\
   504 	}								\
   505 	if(w & 2) {							\
   506 	  double_pixel_copy_increment;					\
   507 	  w -= 2;							\
   508 	}								\
   509 	if ( w > 0 ) {							\
   510 	    n = ( w + 7 ) / 8;						\
   511 	    switch( w & 4 ) {						\
   512 	    case 0: do {	quatro_pixel_copy_increment;		\
   513 	    case 4:		quatro_pixel_copy_increment;		\
   514 		    } while ( --n > 0 );					\
   515 	    }								\
   516 	}								\
   517 }
   518 
   519 /* Use the 8-times version of the loop by default */
   520 #define DUFFS_LOOP(pixel_copy_increment, width)				\
   521 	DUFFS_LOOP8(pixel_copy_increment, width)
   522 
   523 #else
   524 
   525 /* Don't use Duff's device to unroll loops */
   526 #define DUFFS_LOOP_DOUBLE2(pixel_copy_increment,			\
   527 			 double_pixel_copy_increment, width)		\
   528 { int n = width;								\
   529     if( n & 1 ) {							\
   530 	pixel_copy_increment;						\
   531 	n--;								\
   532     }									\
   533     n=n>>1;								\
   534     for(; n > 0; --n) {   						\
   535 	double_pixel_copy_increment;					\
   536     }									\
   537 }
   538 
   539 /* Don't use Duff's device to unroll loops */
   540 #define DUFFS_LOOP_QUATRO2(pixel_copy_increment,			\
   541 				double_pixel_copy_increment,		\
   542 				quatro_pixel_copy_increment, width)	\
   543 { int n = width;								\
   544         if(n & 1) {							\
   545 	  pixel_copy_increment;						\
   546 	  n--;								\
   547 	}								\
   548 	if(n & 2) {							\
   549 	  double_pixel_copy_increment;					\
   550 	  n -= 2;							\
   551 	}								\
   552 	n=n>>2;								\
   553 	for(; n > 0; --n) {   						\
   554 	  quatro_pixel_copy_increment;					\
   555         }								\
   556 }
   557 
   558 /* Don't use Duff's device to unroll loops */
   559 #define DUFFS_LOOP(pixel_copy_increment, width)				\
   560 { int n;								\
   561 	for ( n=width; n > 0; --n ) {					\
   562 		pixel_copy_increment;					\
   563 	}								\
   564 }
   565 #define DUFFS_LOOP8(pixel_copy_increment, width)			\
   566 	DUFFS_LOOP(pixel_copy_increment, width)
   567 #define DUFFS_LOOP4(pixel_copy_increment, width)			\
   568 	DUFFS_LOOP(pixel_copy_increment, width)
   569 
   570 #endif /* USE_DUFFS_LOOP */
   571 
   572 /* Prevent Visual C++ 6.0 from printing out stupid warnings */
   573 #if defined(_MSC_VER) && (_MSC_VER >= 600)
   574 #pragma warning(disable: 4550)
   575 #endif
   576 
   577 #endif /* _SDL_blit_h */
   578 /* vi: set ts=4 sw=4 expandtab: */