Home | History | Annotate | Download | only in video
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2006 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 (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 #include "SDL_video.h"
     25 #include "SDL_sysvideo.h"
     26 #include "SDL_blit.h"
     27 #include "SDL_RLEaccel_c.h"
     28 #include "SDL_pixels_c.h"
     29 
     30 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && SDL_ASSEMBLY_ROUTINES
     31 #define MMX_ASMBLIT
     32 #if (__GNUC__ > 2)  /* SSE instructions aren't in GCC 2. */
     33 #define SSE_ASMBLIT
     34 #endif
     35 #endif
     36 
     37 #if defined(MMX_ASMBLIT)
     38 #include "SDL_cpuinfo.h"
     39 #include "mmx.h"
     40 #endif
     41 
     42 /* The general purpose software blit routine */
     43 static int SDL_SoftBlit(SDL_Surface *src, SDL_Rect *srcrect,
     44 			SDL_Surface *dst, SDL_Rect *dstrect)
     45 {
     46 	int okay;
     47 	int src_locked;
     48 	int dst_locked;
     49 
     50 	/* Everything is okay at the beginning...  */
     51 	okay = 1;
     52 
     53 	/* Lock the destination if it's in hardware */
     54 	dst_locked = 0;
     55 	if ( SDL_MUSTLOCK(dst) ) {
     56 		if ( SDL_LockSurface(dst) < 0 ) {
     57 			okay = 0;
     58 		} else {
     59 			dst_locked = 1;
     60 		}
     61 	}
     62 	/* Lock the source if it's in hardware */
     63 	src_locked = 0;
     64 	if ( SDL_MUSTLOCK(src) ) {
     65 		if ( SDL_LockSurface(src) < 0 ) {
     66 			okay = 0;
     67 		} else {
     68 			src_locked = 1;
     69 		}
     70 	}
     71 
     72 	/* Set up source and destination buffer pointers, and BLIT! */
     73 	if ( okay  && srcrect->w && srcrect->h ) {
     74 		SDL_BlitInfo info;
     75 		SDL_loblit RunBlit;
     76 
     77 		/* Set up the blit information */
     78 		info.s_pixels = (Uint8 *)src->pixels +
     79 				(Uint16)srcrect->y*src->pitch +
     80 				(Uint16)srcrect->x*src->format->BytesPerPixel;
     81 		info.s_width = srcrect->w;
     82 		info.s_height = srcrect->h;
     83 		info.s_skip=src->pitch-info.s_width*src->format->BytesPerPixel;
     84 		info.d_pixels = (Uint8 *)dst->pixels +
     85 				(Uint16)dstrect->y*dst->pitch +
     86 				(Uint16)dstrect->x*dst->format->BytesPerPixel;
     87 		info.d_width = dstrect->w;
     88 		info.d_height = dstrect->h;
     89 		info.d_skip=dst->pitch-info.d_width*dst->format->BytesPerPixel;
     90 		info.aux_data = src->map->sw_data->aux_data;
     91 		info.src = src->format;
     92 		info.table = src->map->table;
     93 		info.dst = dst->format;
     94 		RunBlit = src->map->sw_data->blit;
     95 
     96 		/* Run the actual software blit */
     97 		RunBlit(&info);
     98 	}
     99 
    100 	/* We need to unlock the surfaces if they're locked */
    101 	if ( dst_locked ) {
    102 		SDL_UnlockSurface(dst);
    103 	}
    104 	if ( src_locked ) {
    105 		SDL_UnlockSurface(src);
    106 	}
    107 	/* Blit is done! */
    108 	return(okay ? 0 : -1);
    109 }
    110 
    111 #ifdef MMX_ASMBLIT
    112 static __inline__ void SDL_memcpyMMX(Uint8 *to, const Uint8 *from, int len)
    113 {
    114 	int i;
    115 
    116 	for(i=0; i<len/8; i++) {
    117 		__asm__ __volatile__ (
    118 		"	movq (%0), %%mm0\n"
    119 		"	movq %%mm0, (%1)\n"
    120 		: : "r" (from), "r" (to) : "memory");
    121 		from+=8;
    122 		to+=8;
    123 	}
    124 	if (len&7)
    125 		SDL_memcpy(to, from, len&7);
    126 }
    127 
    128 #ifdef SSE_ASMBLIT
    129 static __inline__ void SDL_memcpySSE(Uint8 *to, const Uint8 *from, int len)
    130 {
    131 	int i;
    132 
    133 	__asm__ __volatile__ (
    134 	"	prefetchnta (%0)\n"
    135 	"	prefetchnta 64(%0)\n"
    136 	"	prefetchnta 128(%0)\n"
    137 	"	prefetchnta 192(%0)\n"
    138 	: : "r" (from) );
    139 
    140 	for(i=0; i<len/8; i++) {
    141 		__asm__ __volatile__ (
    142 		"	prefetchnta 256(%0)\n"
    143 		"	movq (%0), %%mm0\n"
    144 		"	movntq %%mm0, (%1)\n"
    145 		: : "r" (from), "r" (to) : "memory");
    146 		from+=8;
    147 		to+=8;
    148 	}
    149 	if (len&7)
    150 		SDL_memcpy(to, from, len&7);
    151 }
    152 #endif
    153 #endif
    154 
    155 static void SDL_BlitCopy(SDL_BlitInfo *info)
    156 {
    157 	Uint8 *src, *dst;
    158 	int w, h;
    159 	int srcskip, dstskip;
    160 
    161 	w = info->d_width*info->dst->BytesPerPixel;
    162 	h = info->d_height;
    163 	src = info->s_pixels;
    164 	dst = info->d_pixels;
    165 	srcskip = w+info->s_skip;
    166 	dstskip = w+info->d_skip;
    167 
    168 #ifdef SSE_ASMBLIT
    169 	if(SDL_HasSSE())
    170 	{
    171 		while ( h-- ) {
    172 			SDL_memcpySSE(dst, src, w);
    173 			src += srcskip;
    174 			dst += dstskip;
    175 		}
    176 		__asm__ __volatile__ (
    177 		"	emms\n"
    178 		::);
    179 	}
    180 	else
    181 #endif
    182 #ifdef MMX_ASMBLIT
    183 	if(SDL_HasMMX())
    184 	{
    185 		while ( h-- ) {
    186 			SDL_memcpyMMX(dst, src, w);
    187 			src += srcskip;
    188 			dst += dstskip;
    189 		}
    190 		__asm__ __volatile__ (
    191 		"	emms\n"
    192 		::);
    193 	}
    194 	else
    195 #endif
    196 	while ( h-- ) {
    197 		SDL_memcpy(dst, src, w);
    198 		src += srcskip;
    199 		dst += dstskip;
    200 	}
    201 }
    202 
    203 static void SDL_BlitCopyOverlap(SDL_BlitInfo *info)
    204 {
    205 	Uint8 *src, *dst;
    206 	int w, h;
    207 	int srcskip, dstskip;
    208 
    209 	w = info->d_width*info->dst->BytesPerPixel;
    210 	h = info->d_height;
    211 	src = info->s_pixels;
    212 	dst = info->d_pixels;
    213 	srcskip = w+info->s_skip;
    214 	dstskip = w+info->d_skip;
    215 	if ( dst < src ) {
    216 		while ( h-- ) {
    217 			SDL_memcpy(dst, src, w);
    218 			src += srcskip;
    219 			dst += dstskip;
    220 		}
    221 	} else {
    222 		src += ((h-1) * srcskip);
    223 		dst += ((h-1) * dstskip);
    224 		while ( h-- ) {
    225 			SDL_revcpy(dst, src, w);
    226 			src -= srcskip;
    227 			dst -= dstskip;
    228 		}
    229 	}
    230 }
    231 
    232 /* Figure out which of many blit routines to set up on a surface */
    233 int SDL_CalculateBlit(SDL_Surface *surface)
    234 {
    235 	int blit_index;
    236 
    237 	/* Clean everything out to start */
    238 	if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
    239 		SDL_UnRLESurface(surface, 1);
    240 	}
    241 	surface->map->sw_blit = NULL;
    242 
    243 	/* Figure out if an accelerated hardware blit is possible */
    244 	surface->flags &= ~SDL_HWACCEL;
    245 	if ( surface->map->identity ) {
    246 		int hw_blit_ok;
    247 
    248 		if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
    249 			/* We only support accelerated blitting to hardware */
    250 			if ( surface->map->dst->flags & SDL_HWSURFACE ) {
    251 				hw_blit_ok = current_video->info.blit_hw;
    252 			} else {
    253 				hw_blit_ok = 0;
    254 			}
    255 			if (hw_blit_ok && (surface->flags & SDL_SRCCOLORKEY)) {
    256 				hw_blit_ok = current_video->info.blit_hw_CC;
    257 			}
    258 			if ( hw_blit_ok && (surface->flags & SDL_SRCALPHA) ) {
    259 				hw_blit_ok = current_video->info.blit_hw_A;
    260 			}
    261 		} else {
    262 			/* We only support accelerated blitting to hardware */
    263 			if ( surface->map->dst->flags & SDL_HWSURFACE ) {
    264 				hw_blit_ok = current_video->info.blit_sw;
    265 			} else {
    266 				hw_blit_ok = 0;
    267 			}
    268 			if (hw_blit_ok && (surface->flags & SDL_SRCCOLORKEY)) {
    269 				hw_blit_ok = current_video->info.blit_sw_CC;
    270 			}
    271 			if ( hw_blit_ok && (surface->flags & SDL_SRCALPHA) ) {
    272 				hw_blit_ok = current_video->info.blit_sw_A;
    273 			}
    274 		}
    275 		if ( hw_blit_ok ) {
    276 			SDL_VideoDevice *video = current_video;
    277 			SDL_VideoDevice *this  = current_video;
    278 			video->CheckHWBlit(this, surface, surface->map->dst);
    279 		}
    280 	}
    281 
    282 	/* if an alpha pixel format is specified, we can accelerate alpha blits */
    283 	if (((surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )&&(current_video->displayformatalphapixel))
    284 	{
    285 		if ( (surface->flags & SDL_SRCALPHA) )
    286 			if ( current_video->info.blit_hw_A ) {
    287 				SDL_VideoDevice *video = current_video;
    288 				SDL_VideoDevice *this  = current_video;
    289 				video->CheckHWBlit(this, surface, surface->map->dst);
    290 			}
    291 	}
    292 
    293 	/* Get the blit function index, based on surface mode */
    294 	/* { 0 = nothing, 1 = colorkey, 2 = alpha, 3 = colorkey+alpha } */
    295 	blit_index = 0;
    296 	blit_index |= (!!(surface->flags & SDL_SRCCOLORKEY))      << 0;
    297 	if ( surface->flags & SDL_SRCALPHA
    298 	     && (surface->format->alpha != SDL_ALPHA_OPAQUE
    299 		 || surface->format->Amask) ) {
    300 	        blit_index |= 2;
    301 	}
    302 
    303 	/* Check for special "identity" case -- copy blit */
    304 	if ( surface->map->identity && blit_index == 0 ) {
    305 	        surface->map->sw_data->blit = SDL_BlitCopy;
    306 
    307 		/* Handle overlapping blits on the same surface */
    308 		if ( surface == surface->map->dst ) {
    309 		        surface->map->sw_data->blit = SDL_BlitCopyOverlap;
    310 		}
    311 	} else {
    312 		if ( surface->format->BitsPerPixel < 8 ) {
    313 			surface->map->sw_data->blit =
    314 			    SDL_CalculateBlit0(surface, blit_index);
    315 		} else {
    316 			switch ( surface->format->BytesPerPixel ) {
    317 			    case 1:
    318 				surface->map->sw_data->blit =
    319 				    SDL_CalculateBlit1(surface, blit_index);
    320 				break;
    321 			    case 2:
    322 			    case 3:
    323 			    case 4:
    324 				surface->map->sw_data->blit =
    325 				    SDL_CalculateBlitN(surface, blit_index);
    326 				break;
    327 			    default:
    328 				surface->map->sw_data->blit = NULL;
    329 				break;
    330 			}
    331 		}
    332 	}
    333 	/* Make sure we have a blit function */
    334 	if ( surface->map->sw_data->blit == NULL ) {
    335 		SDL_InvalidateMap(surface->map);
    336 		SDL_SetError("Blit combination not supported");
    337 		return(-1);
    338 	}
    339 
    340 	/* Choose software blitting function */
    341 	if(surface->flags & SDL_RLEACCELOK
    342 	   && (surface->flags & SDL_HWACCEL) != SDL_HWACCEL) {
    343 
    344 	        if(surface->map->identity
    345 		   && (blit_index == 1
    346 		       || (blit_index == 3 && !surface->format->Amask))) {
    347 		        if ( SDL_RLESurface(surface) == 0 )
    348 			        surface->map->sw_blit = SDL_RLEBlit;
    349 		} else if(blit_index == 2 && surface->format->Amask) {
    350 		        if ( SDL_RLESurface(surface) == 0 )
    351 			        surface->map->sw_blit = SDL_RLEAlphaBlit;
    352 		}
    353 	}
    354 
    355 	if ( surface->map->sw_blit == NULL ) {
    356 		surface->map->sw_blit = SDL_SoftBlit;
    357 	}
    358 	return(0);
    359 }
    360 
    361