src/video/SDL_blit.h
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Mar 2011 01:34:38 -0800
changeset 5439 3a778c6c0269
parent 5426 7a3982c50af8
child 5440 810b064d41fe
permissions -rw-r--r--
Removed the NDS hack for ARGB1555 surfaces, since it's a general problem; added full color expansion for 16 bpp packed pixels.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 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 #include "SDL_cpuinfo.h"
    28 #include "SDL_endian.h"
    29 #include "SDL_surface.h"
    30 
    31 /* Table to do pixel byte expansion */
    32 extern Uint8* SDL_expand_byte[9];
    33 
    34 /* SDL blit copy flags */
    35 #define SDL_COPY_MODULATE_COLOR     0x00000001
    36 #define SDL_COPY_MODULATE_ALPHA     0x00000002
    37 #define SDL_COPY_BLEND              0x00000010
    38 #define SDL_COPY_ADD                0x00000020
    39 #define SDL_COPY_MOD                0x00000040
    40 #define SDL_COPY_COLORKEY           0x00000100
    41 #define SDL_COPY_NEAREST            0x00000200
    42 #define SDL_COPY_RLE_DESIRED        0x00001000
    43 #define SDL_COPY_RLE_COLORKEY       0x00002000
    44 #define SDL_COPY_RLE_ALPHAKEY       0x00004000
    45 #define SDL_COPY_RLE_MASK           (SDL_COPY_RLE_DESIRED|SDL_COPY_RLE_COLORKEY|SDL_COPY_RLE_ALPHAKEY)
    46 
    47 /* SDL blit CPU flags */
    48 #define SDL_CPU_ANY                 0x00000000
    49 #define SDL_CPU_MMX                 0x00000001
    50 #define SDL_CPU_3DNOW               0x00000002
    51 #define SDL_CPU_SSE                 0x00000004
    52 #define SDL_CPU_SSE2                0x00000008
    53 #define SDL_CPU_ALTIVEC_PREFETCH    0x00000010
    54 #define SDL_CPU_ALTIVEC_NOPREFETCH  0x00000020
    55 
    56 typedef struct
    57 {
    58     Uint8 *src;
    59     int src_w, src_h;
    60     int src_pitch;
    61     int src_skip;
    62     Uint8 *dst;
    63     int dst_w, dst_h;
    64     int dst_pitch;
    65     int dst_skip;
    66     SDL_PixelFormat *src_fmt;
    67     SDL_PixelFormat *dst_fmt;
    68     Uint8 *table;
    69     int flags;
    70     Uint32 colorkey;
    71     Uint8 r, g, b, a;
    72 } SDL_BlitInfo;
    73 
    74 typedef void (SDLCALL * SDL_BlitFunc) (SDL_BlitInfo * info);
    75 
    76 typedef struct
    77 {
    78     Uint32 src_format;
    79     Uint32 dst_format;
    80     int flags;
    81     int cpu;
    82     SDL_BlitFunc func;
    83 } SDL_BlitFuncEntry;
    84 
    85 /* Blit mapping definition */
    86 typedef struct SDL_BlitMap
    87 {
    88     SDL_Surface *dst;
    89     int identity;
    90     SDL_blit blit;
    91     void *data;
    92     SDL_BlitInfo info;
    93 
    94     /* the version count matches the destination; mismatch indicates
    95        an invalid mapping */
    96     Uint32 palette_version;
    97 } SDL_BlitMap;
    98 
    99 /* Functions found in SDL_blit.c */
   100 extern int SDL_CalculateBlit(SDL_Surface * surface);
   101 
   102 /* Functions found in SDL_blit_*.c */
   103 extern SDL_BlitFunc SDL_CalculateBlit0(SDL_Surface * surface);
   104 extern SDL_BlitFunc SDL_CalculateBlit1(SDL_Surface * surface);
   105 extern SDL_BlitFunc SDL_CalculateBlitN(SDL_Surface * surface);
   106 extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface * surface);
   107 
   108 /*
   109  * Useful macros for blitting routines
   110  */
   111 
   112 #if defined(__GNUC__)
   113 #define DECLARE_ALIGNED(t,v,a)  t __attribute__((aligned(a))) v
   114 #elif defined(_MSC_VER)
   115 #define DECLARE_ALIGNED(t,v,a)  __declspec(align(a)) t v
   116 #else
   117 #define DECLARE_ALIGNED(t,v,a)  t v
   118 #endif
   119 
   120 /* Load pixel of the specified format from a buffer and get its R-G-B values */
   121 #define RGB_FROM_PIXEL(Pixel, fmt, r, g, b)				\
   122 {									\
   123 	r = SDL_expand_byte[fmt->Rloss][((Pixel&fmt->Rmask)>>fmt->Rshift)]; \
   124 	g = SDL_expand_byte[fmt->Gloss][((Pixel&fmt->Gmask)>>fmt->Gshift)]; \
   125 	b = SDL_expand_byte[fmt->Bloss][((Pixel&fmt->Bmask)>>fmt->Bshift)]; \
   126 }
   127 #define RGB_FROM_RGB565(Pixel, r, g, b)					\
   128 {									\
   129 	r = SDL_expand_byte[3][((Pixel&0xF800)>>11)];		 			\
   130 	g = SDL_expand_byte[2][((Pixel&0x07E0)>>5)]; 					\
   131 	b = SDL_expand_byte[3][(Pixel&0x001F)]; 					\
   132 }
   133 #define RGB_FROM_RGB555(Pixel, r, g, b)					\
   134 {									\
   135 	r = SDL_expand_byte[3][((Pixel&0x7C00)>>10)];		 			\
   136 	g = SDL_expand_byte[3][((Pixel&0x03E0)>>5)]; 					\
   137 	b = SDL_expand_byte[3][(Pixel&0x001F)]; 					\
   138 }
   139 #define RGB_FROM_RGB888(Pixel, r, g, b)					\
   140 {									\
   141 	r = ((Pixel&0xFF0000)>>16);		 			\
   142 	g = ((Pixel&0xFF00)>>8);		 			\
   143 	b = (Pixel&0xFF);			 			\
   144 }
   145 #define RETRIEVE_RGB_PIXEL(buf, bpp, Pixel)				   \
   146 do {									   \
   147 	switch (bpp) {							   \
   148 		case 2:							   \
   149 			Pixel = *((Uint16 *)(buf));			   \
   150 		break;							   \
   151 									   \
   152 		case 3: {						   \
   153 		        Uint8 *B = (Uint8 *)(buf);			   \
   154 			if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
   155 			        Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \
   156 			} else {					   \
   157 			        Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \
   158 			}						   \
   159 		}							   \
   160 		break;							   \
   161 									   \
   162 		case 4:							   \
   163 			Pixel = *((Uint32 *)(buf));			   \
   164 		break;							   \
   165 									   \
   166 		default:						   \
   167 		        Pixel = 0; /* stop gcc complaints */		   \
   168 		break;							   \
   169 	}								   \
   170 } while (0)
   171 
   172 #define DISEMBLE_RGB(buf, bpp, fmt, Pixel, r, g, b)			   \
   173 do {									   \
   174 	switch (bpp) {							   \
   175 		case 2:							   \
   176 			Pixel = *((Uint16 *)(buf));			   \
   177 			RGB_FROM_PIXEL(Pixel, fmt, r, g, b);		   \
   178 		break;							   \
   179 									   \
   180 		case 3:	{						   \
   181             Pixel = 0;                  \
   182                         if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
   183 			        r = *((buf)+fmt->Rshift/8);		   \
   184 				g = *((buf)+fmt->Gshift/8);		   \
   185 				b = *((buf)+fmt->Bshift/8);		   \
   186 			} else {					   \
   187 			        r = *((buf)+2-fmt->Rshift/8);		   \
   188 				g = *((buf)+2-fmt->Gshift/8);		   \
   189 				b = *((buf)+2-fmt->Bshift/8);		   \
   190 			}						   \
   191 		}							   \
   192 		break;							   \
   193 									   \
   194 		case 4:							   \
   195 			Pixel = *((Uint32 *)(buf));			   \
   196 			RGB_FROM_PIXEL(Pixel, fmt, r, g, b);		   \
   197 		break;							   \
   198 									   \
   199 		default:						   \
   200                 /* stop gcc complaints */		   \
   201 		        Pixel = 0;              \
   202                 r = g = b = 0;          \
   203 		break;							   \
   204 	}								   \
   205 } while (0)
   206 
   207 /* Assemble R-G-B values into a specified pixel format and store them */
   208 #define PIXEL_FROM_RGB(Pixel, fmt, r, g, b)				\
   209 {									\
   210 	Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|				\
   211 		((g>>fmt->Gloss)<<fmt->Gshift)|				\
   212 		((b>>fmt->Bloss)<<fmt->Bshift)|
   213         fmt->Amask;				\
   214 }
   215 #define RGB565_FROM_RGB(Pixel, r, g, b)					\
   216 {									\
   217 	Pixel = ((r>>3)<<11)|((g>>2)<<5)|(b>>3);			\
   218 }
   219 #define RGB555_FROM_RGB(Pixel, r, g, b)					\
   220 {									\
   221 	Pixel = ((r>>3)<<10)|((g>>3)<<5)|(b>>3);			\
   222 }
   223 #define RGB888_FROM_RGB(Pixel, r, g, b)					\
   224 {									\
   225 	Pixel = (r<<16)|(g<<8)|b;					\
   226 }
   227 #define ARGB8888_FROM_RGBA(Pixel, r, g, b, a)				\
   228 {									\
   229 	Pixel = (a<<24)|(r<<16)|(g<<8)|b;				\
   230 }
   231 #define RGBA8888_FROM_RGBA(Pixel, r, g, b, a)				\
   232 {									\
   233 	Pixel = (r<<24)|(g<<16)|(b<<8)|a;				\
   234 }
   235 #define ABGR8888_FROM_RGBA(Pixel, r, g, b, a)				\
   236 {									\
   237 	Pixel = (a<<24)|(b<<16)|(g<<8)|r;				\
   238 }
   239 #define BGRA8888_FROM_RGBA(Pixel, r, g, b, a)				\
   240 {									\
   241 	Pixel = (b<<24)|(g<<16)|(r<<8)|a;				\
   242 }
   243 #define ASSEMBLE_RGB(buf, bpp, fmt, r, g, b) 				\
   244 {									\
   245 	switch (bpp) {							\
   246 		case 2: {						\
   247 			Uint16 Pixel;					\
   248 									\
   249 			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
   250 			*((Uint16 *)(buf)) = Pixel;		\
   251 		}							\
   252 		break;							\
   253 									\
   254 		case 3: {						\
   255                         if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
   256 			        *((buf)+fmt->Rshift/8) = r;		\
   257 				*((buf)+fmt->Gshift/8) = g;		\
   258 				*((buf)+fmt->Bshift/8) = b;		\
   259 			} else {					\
   260 			        *((buf)+2-fmt->Rshift/8) = r;		\
   261 				*((buf)+2-fmt->Gshift/8) = g;		\
   262 				*((buf)+2-fmt->Bshift/8) = b;		\
   263 			}						\
   264 		}							\
   265 		break;							\
   266 									\
   267 		case 4: {						\
   268 			Uint32 Pixel;					\
   269 									\
   270 			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
   271 			*((Uint32 *)(buf)) = Pixel;			\
   272 		}							\
   273 		break;							\
   274 	}								\
   275 }
   276 
   277 /* FIXME: Should we rescale alpha into 0..255 here? */
   278 #define RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a)				\
   279 {									\
   280 	r = SDL_expand_byte[fmt->Rloss][((Pixel&fmt->Rmask)>>fmt->Rshift)]; \
   281 	g = SDL_expand_byte[fmt->Gloss][((Pixel&fmt->Gmask)>>fmt->Gshift)]; \
   282 	b = SDL_expand_byte[fmt->Bloss][((Pixel&fmt->Bmask)>>fmt->Bshift)]; \
   283 	a = SDL_expand_byte[fmt->Aloss][((Pixel&fmt->Amask)>>fmt->Ashift)]; \
   284 }
   285 #define RGBA_FROM_8888(Pixel, fmt, r, g, b, a)	\
   286 {						\
   287 	r = (Pixel&fmt->Rmask)>>fmt->Rshift;	\
   288 	g = (Pixel&fmt->Gmask)>>fmt->Gshift;	\
   289 	b = (Pixel&fmt->Bmask)>>fmt->Bshift;	\
   290 	a = (Pixel&fmt->Amask)>>fmt->Ashift;	\
   291 }
   292 #define RGBA_FROM_RGBA8888(Pixel, r, g, b, a)				\
   293 {									\
   294 	r = (Pixel>>24);						\
   295 	g = ((Pixel>>16)&0xFF);						\
   296 	b = ((Pixel>>8)&0xFF);						\
   297 	a = (Pixel&0xFF);						\
   298 }
   299 #define RGBA_FROM_ARGB8888(Pixel, r, g, b, a)				\
   300 {									\
   301 	r = ((Pixel>>16)&0xFF);						\
   302 	g = ((Pixel>>8)&0xFF);						\
   303 	b = (Pixel&0xFF);						\
   304 	a = (Pixel>>24);						\
   305 }
   306 #define RGBA_FROM_ABGR8888(Pixel, r, g, b, a)				\
   307 {									\
   308 	r = (Pixel&0xFF);						\
   309 	g = ((Pixel>>8)&0xFF);						\
   310 	b = ((Pixel>>16)&0xFF);						\
   311 	a = (Pixel>>24);						\
   312 }
   313 #define RGBA_FROM_BGRA8888(Pixel, r, g, b, a)				\
   314 {									\
   315 	r = ((Pixel>>8)&0xFF);						\
   316 	g = ((Pixel>>16)&0xFF);						\
   317 	b = (Pixel>>24);						\
   318 	a = (Pixel&0xFF);						\
   319 }
   320 #define DISEMBLE_RGBA(buf, bpp, fmt, Pixel, r, g, b, a)			   \
   321 do {									   \
   322 	switch (bpp) {							   \
   323 		case 2:							   \
   324 			Pixel = *((Uint16 *)(buf));			   \
   325 			RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a);	   \
   326 		break;							   \
   327 									   \
   328 		case 3:	{						   \
   329             Pixel = 0; \
   330                         if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
   331 			        r = *((buf)+fmt->Rshift/8);		   \
   332 				g = *((buf)+fmt->Gshift/8);		   \
   333 				b = *((buf)+fmt->Bshift/8);		   \
   334 			} else {					   \
   335 			        r = *((buf)+2-fmt->Rshift/8);		   \
   336 				g = *((buf)+2-fmt->Gshift/8);		   \
   337 				b = *((buf)+2-fmt->Bshift/8);		   \
   338 			}						   \
   339 			a = 0xFF;					   \
   340 		}							   \
   341 		break;							   \
   342 									   \
   343 		case 4:							   \
   344 			Pixel = *((Uint32 *)(buf));			   \
   345 			RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a);	   \
   346 		break;							   \
   347 									   \
   348 		default:						   \
   349                 /* stop gcc complaints */		   \
   350 		        Pixel = 0;              \
   351                 r = g = b = a = 0;      \
   352 		break;							   \
   353 	}								   \
   354 } while (0)
   355 
   356 /* FIXME: this isn't correct, especially for Alpha (maximum != 255) */
   357 #define PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a)				\
   358 {									\
   359 	Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|				\
   360 		((g>>fmt->Gloss)<<fmt->Gshift)|				\
   361 		((b>>fmt->Bloss)<<fmt->Bshift)|				\
   362 		((a>>fmt->Aloss)<<fmt->Ashift);				\
   363 }
   364 #define ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a)			\
   365 {									\
   366 	switch (bpp) {							\
   367 		case 2: {						\
   368 			Uint16 Pixel;					\
   369 									\
   370 			PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a);	\
   371 			*((Uint16 *)(buf)) = Pixel;		\
   372 		}							\
   373 		break;							\
   374 									\
   375 		case 3: {						\
   376                         if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
   377 			        *((buf)+fmt->Rshift/8) = r;		\
   378 				*((buf)+fmt->Gshift/8) = g;		\
   379 				*((buf)+fmt->Bshift/8) = b;		\
   380 			} else {					\
   381 			        *((buf)+2-fmt->Rshift/8) = r;		\
   382 				*((buf)+2-fmt->Gshift/8) = g;		\
   383 				*((buf)+2-fmt->Bshift/8) = b;		\
   384 			}						\
   385 		}							\
   386 		break;							\
   387 									\
   388 		case 4: {						\
   389 			Uint32 Pixel;					\
   390 									\
   391 			PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a);	\
   392 			*((Uint32 *)(buf)) = Pixel;			\
   393 		}							\
   394 		break;							\
   395 	}								\
   396 }
   397 
   398 /* Blend the RGB values of two Pixels based on a source alpha value */
   399 #define ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB)	\
   400 do {						\
   401 	dR = ((((int)(sR-dR)*(int)A)/255)+dR);	\
   402 	dG = ((((int)(sG-dG)*(int)A)/255)+dG);	\
   403 	dB = ((((int)(sB-dB)*(int)A)/255)+dB);	\
   404 } while(0)
   405 
   406 
   407 /* This is a very useful loop for optimizing blitters */
   408 #if defined(_MSC_VER) && (_MSC_VER == 1300)
   409 /* There's a bug in the Visual C++ 7 optimizer when compiling this code */
   410 #else
   411 #define USE_DUFFS_LOOP
   412 #endif
   413 #ifdef USE_DUFFS_LOOP
   414 
   415 /* 8-times unrolled loop */
   416 #define DUFFS_LOOP8(pixel_copy_increment, width)			\
   417 { int n = (width+7)/8;							\
   418 	switch (width & 7) {						\
   419 	case 0: do {	pixel_copy_increment;				\
   420 	case 7:		pixel_copy_increment;				\
   421 	case 6:		pixel_copy_increment;				\
   422 	case 5:		pixel_copy_increment;				\
   423 	case 4:		pixel_copy_increment;				\
   424 	case 3:		pixel_copy_increment;				\
   425 	case 2:		pixel_copy_increment;				\
   426 	case 1:		pixel_copy_increment;				\
   427 		} while ( --n > 0 );					\
   428 	}								\
   429 }
   430 
   431 /* 4-times unrolled loop */
   432 #define DUFFS_LOOP4(pixel_copy_increment, width)			\
   433 { int n = (width+3)/4;							\
   434 	switch (width & 3) {						\
   435 	case 0: do {	pixel_copy_increment;				\
   436 	case 3:		pixel_copy_increment;				\
   437 	case 2:		pixel_copy_increment;				\
   438 	case 1:		pixel_copy_increment;				\
   439 		} while (--n > 0);					\
   440 	}								\
   441 }
   442 
   443 /* Use the 8-times version of the loop by default */
   444 #define DUFFS_LOOP(pixel_copy_increment, width)				\
   445 	DUFFS_LOOP8(pixel_copy_increment, width)
   446 
   447 /* Special version of Duff's device for even more optimization */
   448 #define DUFFS_LOOP_124(pixel_copy_increment1,				\
   449                        pixel_copy_increment2,				\
   450                        pixel_copy_increment4, width)			\
   451 { int n = width;							\
   452 	if (n & 1) {							\
   453 		pixel_copy_increment1; n -= 1;				\
   454 	}								\
   455 	if (n & 2) {							\
   456 		pixel_copy_increment2; n -= 2;				\
   457 	}								\
   458 	if (n) {							\
   459 		n = (n+7)/ 8;						\
   460 		switch (n & 4) {					\
   461 		case 0: do {	pixel_copy_increment4;			\
   462 		case 4:		pixel_copy_increment4;			\
   463 			} while (--n > 0);				\
   464 		}							\
   465 	}								\
   466 }
   467 
   468 #else
   469 
   470 /* Don't use Duff's device to unroll loops */
   471 #define DUFFS_LOOP(pixel_copy_increment, width)				\
   472 { int n;								\
   473 	for ( n=width; n > 0; --n ) {					\
   474 		pixel_copy_increment;					\
   475 	}								\
   476 }
   477 #define DUFFS_LOOP8(pixel_copy_increment, width)			\
   478 	DUFFS_LOOP(pixel_copy_increment, width)
   479 #define DUFFS_LOOP4(pixel_copy_increment, width)			\
   480 	DUFFS_LOOP(pixel_copy_increment, width)
   481 #define DUFFS_LOOP_124(pixel_copy_increment1,				\
   482                        pixel_copy_increment2,				\
   483                        pixel_copy_increment4, width)			\
   484 	DUFFS_LOOP(pixel_copy_increment1, width)
   485 
   486 #endif /* USE_DUFFS_LOOP */
   487 
   488 /* Prevent Visual C++ 6.0 from printing out stupid warnings */
   489 #if defined(_MSC_VER) && (_MSC_VER >= 600)
   490 #pragma warning(disable: 4550)
   491 #endif
   492 
   493 #endif /* _SDL_blit_h */
   494 
   495 /* vi: set ts=4 sw=4 expandtab: */