146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/*
246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    SDL - Simple DirectMedia Layer
346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Copyright (C) 1997-2006 Sam Lantinga
446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    This library is free software; you can redistribute it and/or
646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    modify it under the terms of the GNU Lesser General Public
746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    License as published by the Free Software Foundation; either
846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    version 2.1 of the License, or (at your option) any later version.
946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    This library is distributed in the hope that it will be useful,
1146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    but WITHOUT ANY WARRANTY; without even the implied warranty of
1246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Lesser General Public License for more details.
1446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    You should have received a copy of the GNU Lesser General Public
1646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    License along with this library; if not, write to the Free Software
1746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
1846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Sam Lantinga
2046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    slouken@libsdl.org
2146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/
2246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_config.h"
2346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_video.h"
2546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_sysvideo.h"
2646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_blit.h"
2746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_RLEaccel_c.h"
2846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_pixels_c.h"
2946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && SDL_ASSEMBLY_ROUTINES
3146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define MMX_ASMBLIT
3246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if (__GNUC__ > 2)  /* SSE instructions aren't in GCC 2. */
3346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define SSE_ASMBLIT
3446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
3546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
3646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if defined(MMX_ASMBLIT)
3846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_cpuinfo.h"
3946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "mmx.h"
4046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
4146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
4246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* The general purpose software blit routine */
4346be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int SDL_SoftBlit(SDL_Surface *src, SDL_Rect *srcrect,
4446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_Surface *dst, SDL_Rect *dstrect)
4546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
4646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int okay;
4746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int src_locked;
4846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int dst_locked;
4946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
5046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Everything is okay at the beginning...  */
5146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	okay = 1;
5246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
5346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Lock the destination if it's in hardware */
5446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	dst_locked = 0;
5546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( SDL_MUSTLOCK(dst) ) {
5646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( SDL_LockSurface(dst) < 0 ) {
5746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			okay = 0;
5846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		} else {
5946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			dst_locked = 1;
6046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
6146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
6246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Lock the source if it's in hardware */
6346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	src_locked = 0;
6446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( SDL_MUSTLOCK(src) ) {
6546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( SDL_LockSurface(src) < 0 ) {
6646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			okay = 0;
6746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		} else {
6846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			src_locked = 1;
6946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
7046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
7146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
7246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Set up source and destination buffer pointers, and BLIT! */
7346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( okay  && srcrect->w && srcrect->h ) {
7446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_BlitInfo info;
7546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_loblit RunBlit;
7646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
7746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Set up the blit information */
7846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.s_pixels = (Uint8 *)src->pixels +
7946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				(Uint16)srcrect->y*src->pitch +
8046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				(Uint16)srcrect->x*src->format->BytesPerPixel;
8146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.s_width = srcrect->w;
8246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.s_height = srcrect->h;
8346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.s_skip=src->pitch-info.s_width*src->format->BytesPerPixel;
8446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.d_pixels = (Uint8 *)dst->pixels +
8546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				(Uint16)dstrect->y*dst->pitch +
8646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				(Uint16)dstrect->x*dst->format->BytesPerPixel;
8746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.d_width = dstrect->w;
8846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.d_height = dstrect->h;
8946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.d_skip=dst->pitch-info.d_width*dst->format->BytesPerPixel;
9046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.aux_data = src->map->sw_data->aux_data;
9146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.src = src->format;
9246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.table = src->map->table;
9346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		info.dst = dst->format;
9446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		RunBlit = src->map->sw_data->blit;
9546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
9646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Run the actual software blit */
9746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		RunBlit(&info);
9846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
9946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
10046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* We need to unlock the surfaces if they're locked */
10146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( dst_locked ) {
10246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_UnlockSurface(dst);
10346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
10446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( src_locked ) {
10546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_UnlockSurface(src);
10646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
10746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Blit is done! */
10846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return(okay ? 0 : -1);
10946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
11046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
11146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef MMX_ASMBLIT
11246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic __inline__ void SDL_memcpyMMX(Uint8 *to, const Uint8 *from, int len)
11346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
11446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int i;
11546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
11646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	for(i=0; i<len/8; i++) {
11746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		__asm__ __volatile__ (
11846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		"	movq (%0), %%mm0\n"
11946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		"	movq %%mm0, (%1)\n"
12046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		: : "r" (from), "r" (to) : "memory");
12146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		from+=8;
12246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		to+=8;
12346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
12446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if (len&7)
12546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_memcpy(to, from, len&7);
12646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
12746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
12846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef SSE_ASMBLIT
12946be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic __inline__ void SDL_memcpySSE(Uint8 *to, const Uint8 *from, int len)
13046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
13146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int i;
13246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
13346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	__asm__ __volatile__ (
13446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	"	prefetchnta (%0)\n"
13546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	"	prefetchnta 64(%0)\n"
13646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	"	prefetchnta 128(%0)\n"
13746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	"	prefetchnta 192(%0)\n"
13846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	: : "r" (from) );
13946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
14046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	for(i=0; i<len/8; i++) {
14146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		__asm__ __volatile__ (
14246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		"	prefetchnta 256(%0)\n"
14346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		"	movq (%0), %%mm0\n"
14446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		"	movntq %%mm0, (%1)\n"
14546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		: : "r" (from), "r" (to) : "memory");
14646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		from+=8;
14746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		to+=8;
14846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
14946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if (len&7)
15046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_memcpy(to, from, len&7);
15146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
15246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
15346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
15446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
15546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void SDL_BlitCopy(SDL_BlitInfo *info)
15646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
15746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint8 *src, *dst;
15846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int w, h;
15946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int srcskip, dstskip;
16046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
16146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	w = info->d_width*info->dst->BytesPerPixel;
16246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	h = info->d_height;
16346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	src = info->s_pixels;
16446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	dst = info->d_pixels;
16546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	srcskip = w+info->s_skip;
16646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	dstskip = w+info->d_skip;
16746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
16846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef SSE_ASMBLIT
16946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if(SDL_HasSSE())
17046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	{
17146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		while ( h-- ) {
17246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_memcpySSE(dst, src, w);
17346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			src += srcskip;
17446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			dst += dstskip;
17546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
17646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		__asm__ __volatile__ (
17746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		"	emms\n"
17846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		::);
17946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
18046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	else
18146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
18246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef MMX_ASMBLIT
18346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if(SDL_HasMMX())
18446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	{
18546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		while ( h-- ) {
18646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_memcpyMMX(dst, src, w);
18746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			src += srcskip;
18846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			dst += dstskip;
18946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
19046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		__asm__ __volatile__ (
19146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		"	emms\n"
19246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		::);
19346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
19446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	else
19546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
19646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	while ( h-- ) {
19746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_memcpy(dst, src, w);
19846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		src += srcskip;
19946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		dst += dstskip;
20046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
20146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
20246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
20346be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void SDL_BlitCopyOverlap(SDL_BlitInfo *info)
20446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
20546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint8 *src, *dst;
20646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int w, h;
20746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int srcskip, dstskip;
20846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
20946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	w = info->d_width*info->dst->BytesPerPixel;
21046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	h = info->d_height;
21146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	src = info->s_pixels;
21246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	dst = info->d_pixels;
21346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	srcskip = w+info->s_skip;
21446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	dstskip = w+info->d_skip;
21546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( dst < src ) {
21646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		while ( h-- ) {
21746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_memcpy(dst, src, w);
21846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			src += srcskip;
21946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			dst += dstskip;
22046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
22146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	} else {
22246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		src += ((h-1) * srcskip);
22346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		dst += ((h-1) * dstskip);
22446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		while ( h-- ) {
22546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_revcpy(dst, src, w);
22646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			src -= srcskip;
22746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			dst -= dstskip;
22846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
22946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
23046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
23146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
23246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Figure out which of many blit routines to set up on a surface */
23346be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_CalculateBlit(SDL_Surface *surface)
23446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
23546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int blit_index;
23646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
23746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Clean everything out to start */
23846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
23946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_UnRLESurface(surface, 1);
24046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
24146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	surface->map->sw_blit = NULL;
24246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
24346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Figure out if an accelerated hardware blit is possible */
24446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	surface->flags &= ~SDL_HWACCEL;
24546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( surface->map->identity ) {
24646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		int hw_blit_ok;
24746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
24846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
24946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			/* We only support accelerated blitting to hardware */
25046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( surface->map->dst->flags & SDL_HWSURFACE ) {
25146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				hw_blit_ok = current_video->info.blit_hw;
25246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			} else {
25346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				hw_blit_ok = 0;
25446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
25546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if (hw_blit_ok && (surface->flags & SDL_SRCCOLORKEY)) {
25646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				hw_blit_ok = current_video->info.blit_hw_CC;
25746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
25846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( hw_blit_ok && (surface->flags & SDL_SRCALPHA) ) {
25946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				hw_blit_ok = current_video->info.blit_hw_A;
26046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
26146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		} else {
26246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			/* We only support accelerated blitting to hardware */
26346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( surface->map->dst->flags & SDL_HWSURFACE ) {
26446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				hw_blit_ok = current_video->info.blit_sw;
26546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			} else {
26646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				hw_blit_ok = 0;
26746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
26846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if (hw_blit_ok && (surface->flags & SDL_SRCCOLORKEY)) {
26946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				hw_blit_ok = current_video->info.blit_sw_CC;
27046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
27146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( hw_blit_ok && (surface->flags & SDL_SRCALPHA) ) {
27246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				hw_blit_ok = current_video->info.blit_sw_A;
27346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
27446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
27546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( hw_blit_ok ) {
27646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_VideoDevice *video = current_video;
27746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_VideoDevice *this  = current_video;
27846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			video->CheckHWBlit(this, surface, surface->map->dst);
27946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
28046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
28146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
28246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* if an alpha pixel format is specified, we can accelerate alpha blits */
28346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if (((surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )&&(current_video->displayformatalphapixel))
28446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	{
28546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( (surface->flags & SDL_SRCALPHA) )
28646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( current_video->info.blit_hw_A ) {
28746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_VideoDevice *video = current_video;
28846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_VideoDevice *this  = current_video;
28946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				video->CheckHWBlit(this, surface, surface->map->dst);
29046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
29146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
29246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
29346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Get the blit function index, based on surface mode */
29446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* { 0 = nothing, 1 = colorkey, 2 = alpha, 3 = colorkey+alpha } */
29546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	blit_index = 0;
29646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	blit_index |= (!!(surface->flags & SDL_SRCCOLORKEY))      << 0;
29746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( surface->flags & SDL_SRCALPHA
29846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	     && (surface->format->alpha != SDL_ALPHA_OPAQUE
29946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		 || surface->format->Amask) ) {
30046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	        blit_index |= 2;
30146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
30246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
30346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Check for special "identity" case -- copy blit */
30446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( surface->map->identity && blit_index == 0 ) {
30546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	        surface->map->sw_data->blit = SDL_BlitCopy;
30646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
30746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Handle overlapping blits on the same surface */
30846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( surface == surface->map->dst ) {
30946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		        surface->map->sw_data->blit = SDL_BlitCopyOverlap;
31046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
31146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	} else {
31246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( surface->format->BitsPerPixel < 8 ) {
31346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			surface->map->sw_data->blit =
31446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    SDL_CalculateBlit0(surface, blit_index);
31546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		} else {
31646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			switch ( surface->format->BytesPerPixel ) {
31746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    case 1:
31846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				surface->map->sw_data->blit =
31946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				    SDL_CalculateBlit1(surface, blit_index);
32046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				break;
32146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    case 2:
32246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    case 3:
32346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    case 4:
32446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				surface->map->sw_data->blit =
32546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				    SDL_CalculateBlitN(surface, blit_index);
32646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				break;
32746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    default:
32846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				surface->map->sw_data->blit = NULL;
32946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				break;
33046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
33146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
33246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
33346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Make sure we have a blit function */
33446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( surface->map->sw_data->blit == NULL ) {
33546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_InvalidateMap(surface->map);
33646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Blit combination not supported");
33746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return(-1);
33846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
33946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
34046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Choose software blitting function */
34146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if(surface->flags & SDL_RLEACCELOK
34246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	   && (surface->flags & SDL_HWACCEL) != SDL_HWACCEL) {
34346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
34446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	        if(surface->map->identity
34546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		   && (blit_index == 1
34646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		       || (blit_index == 3 && !surface->format->Amask))) {
34746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		        if ( SDL_RLESurface(surface) == 0 )
34846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			        surface->map->sw_blit = SDL_RLEBlit;
34946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		} else if(blit_index == 2 && surface->format->Amask) {
35046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		        if ( SDL_RLESurface(surface) == 0 )
35146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			        surface->map->sw_blit = SDL_RLEAlphaBlit;
35246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
35346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
35446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
35546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( surface->map->sw_blit == NULL ) {
35646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		surface->map->sw_blit = SDL_SoftBlit;
35746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
35846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return(0);
35946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
36046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
361