src/video/SDL_surface.c
author Ryan C. Gordon
Sun, 17 Apr 2005 10:40:41 +0000
changeset 1052 68f607298ca9
parent 1017 c2f2370ac1e5
child 1155 91569ec25acd
permissions -rw-r--r--
Some work on using accelerated alpha blits with hardware surfaces.

From Stephane Marchesin's fork, don't know who originally wrote it.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2004 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@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 #include <stdio.h>
    29 #include <stdlib.h>
    30 #include <string.h>
    31 
    32 #include "SDL_error.h"
    33 #include "SDL_video.h"
    34 #include "SDL_sysvideo.h"
    35 #include "SDL_cursor_c.h"
    36 #include "SDL_blit.h"
    37 #include "SDL_RLEaccel_c.h"
    38 #include "SDL_pixels_c.h"
    39 #include "SDL_memops.h"
    40 #include "SDL_leaks.h"
    41 
    42 /* Public routines */
    43 /*
    44  * Create an empty RGB surface of the appropriate depth
    45  */
    46 SDL_Surface * SDL_CreateRGBSurface (Uint32 flags,
    47 			int width, int height, int depth,
    48 			Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    49 {
    50 	SDL_VideoDevice *video = current_video;
    51 	SDL_VideoDevice *this  = current_video;
    52 	SDL_Surface *screen;
    53 	SDL_Surface *surface;
    54 
    55 	/* Make sure the size requested doesn't overflow our datatypes */
    56 	/* Next time I write a library like SDL, I'll use int for size. :) */
    57 	if ( width >= 16384 || height >= 65536 ) {
    58 		SDL_SetError("Width or height is too large");
    59 		return(NULL);
    60 	}
    61 
    62 	/* Check to see if we desire the surface in video memory */
    63 	if ( video ) {
    64 		screen = SDL_PublicSurface;
    65 	} else {
    66 		screen = NULL;
    67 	}
    68 	if ( screen && ((screen->flags&SDL_HWSURFACE) == SDL_HWSURFACE) ) {
    69 		if ( (flags&(SDL_SRCCOLORKEY|SDL_SRCALPHA)) != 0 ) {
    70 			flags |= SDL_HWSURFACE;
    71 		}
    72 		if ( (flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
    73 			if ( ! current_video->info.blit_hw_CC ) {
    74 				flags &= ~SDL_HWSURFACE;
    75 			}
    76 		}
    77 		if ( (flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
    78 			if ( ! current_video->info.blit_hw_A ) {
    79 				flags &= ~SDL_HWSURFACE;
    80 			}
    81 		}
    82 	} else {
    83 		flags &= ~SDL_HWSURFACE;
    84 	}
    85 
    86 	/* Allocate the surface */
    87 	surface = (SDL_Surface *)malloc(sizeof(*surface));
    88 	if ( surface == NULL ) {
    89 		SDL_OutOfMemory();
    90 		return(NULL);
    91 	}
    92 	surface->flags = SDL_SWSURFACE;
    93 	if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
    94 		if ((Amask) && (video->displayformatalphapixel))
    95 		{
    96 			depth = video->displayformatalphapixel->BitsPerPixel;
    97 			Rmask = video->displayformatalphapixel->Rmask;
    98 			Gmask = video->displayformatalphapixel->Gmask;
    99 			Bmask = video->displayformatalphapixel->Bmask;
   100 			Amask = video->displayformatalphapixel->Amask;
   101 		}
   102 		else
   103 		{
   104 			depth = screen->format->BitsPerPixel;
   105 			Rmask = screen->format->Rmask;
   106 			Gmask = screen->format->Gmask;
   107 			Bmask = screen->format->Bmask;
   108 			Amask = screen->format->Amask;
   109 		}
   110 	}
   111 	surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
   112 	if ( surface->format == NULL ) {
   113 		free(surface);
   114 		return(NULL);
   115 	}
   116 	if ( Amask ) {
   117 		surface->flags |= SDL_SRCALPHA;
   118 	}
   119 	surface->w = width;
   120 	surface->h = height;
   121 	surface->pitch = SDL_CalculatePitch(surface);
   122 	surface->pixels = NULL;
   123 	surface->offset = 0;
   124 	surface->hwdata = NULL;
   125 	surface->locked = 0;
   126 	surface->map = NULL;
   127 	surface->unused1 = 0;
   128 	SDL_SetClipRect(surface, NULL);
   129 	SDL_FormatChanged(surface);
   130 
   131 	/* Get the pixels */
   132 	if ( ((flags&SDL_HWSURFACE) == SDL_SWSURFACE) || 
   133 				(video->AllocHWSurface(this, surface) < 0) ) {
   134 		if ( surface->w && surface->h ) {
   135 			surface->pixels = malloc(surface->h*surface->pitch);
   136 			if ( surface->pixels == NULL ) {
   137 				SDL_FreeSurface(surface);
   138 				SDL_OutOfMemory();
   139 				return(NULL);
   140 			}
   141 			/* This is important for bitmaps */
   142 			memset(surface->pixels, 0, surface->h*surface->pitch);
   143 		}
   144 	}
   145 
   146 	/* Allocate an empty mapping */
   147 	surface->map = SDL_AllocBlitMap();
   148 	if ( surface->map == NULL ) {
   149 		SDL_FreeSurface(surface);
   150 		return(NULL);
   151 	}
   152 
   153 	/* The surface is ready to go */
   154 	surface->refcount = 1;
   155 #ifdef CHECK_LEAKS
   156 	++surfaces_allocated;
   157 #endif
   158 	return(surface);
   159 }
   160 /*
   161  * Create an RGB surface from an existing memory buffer
   162  */
   163 SDL_Surface * SDL_CreateRGBSurfaceFrom (void *pixels,
   164 			int width, int height, int depth, int pitch,
   165 			Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
   166 {
   167 	SDL_Surface *surface;
   168 
   169 	surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, depth,
   170 	                               Rmask, Gmask, Bmask, Amask);
   171 	if ( surface != NULL ) {
   172 		surface->flags |= SDL_PREALLOC;
   173 		surface->pixels = pixels;
   174 		surface->w = width;
   175 		surface->h = height;
   176 		surface->pitch = pitch;
   177 		SDL_SetClipRect(surface, NULL);
   178 	}
   179 	return(surface);
   180 }
   181 /*
   182  * Set the color key in a blittable surface
   183  */
   184 int SDL_SetColorKey (SDL_Surface *surface, Uint32 flag, Uint32 key)
   185 {
   186 	/* Sanity check the flag as it gets passed in */
   187 	if ( flag & SDL_SRCCOLORKEY ) {
   188 		if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
   189 			flag = (SDL_SRCCOLORKEY | SDL_RLEACCELOK);
   190 		} else {
   191 			flag = SDL_SRCCOLORKEY;
   192 		}
   193 	} else {
   194 		flag = 0;
   195 	}
   196 
   197 	/* Optimize away operations that don't change anything */
   198 	if ( (flag == (surface->flags & (SDL_SRCCOLORKEY|SDL_RLEACCELOK))) &&
   199 	     (key == surface->format->colorkey) ) {
   200 		return(0);
   201 	}
   202 
   203 	/* UnRLE surfaces before we change the colorkey */
   204 	if ( surface->flags & SDL_RLEACCEL ) {
   205 	        SDL_UnRLESurface(surface, 1);
   206 	}
   207 
   208 	if ( flag ) {
   209 		SDL_VideoDevice *video = current_video;
   210 		SDL_VideoDevice *this  = current_video;
   211 
   212 
   213 		surface->flags |= SDL_SRCCOLORKEY;
   214 		surface->format->colorkey = key;
   215 		if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
   216 			if ( (video->SetHWColorKey == NULL) ||
   217 			     (video->SetHWColorKey(this, surface, key) < 0) ) {
   218 				surface->flags &= ~SDL_HWACCEL;
   219 			}
   220 		}
   221 		if ( flag & SDL_RLEACCELOK ) {
   222 			surface->flags |= SDL_RLEACCELOK;
   223 		} else {
   224 			surface->flags &= ~SDL_RLEACCELOK;
   225 		}
   226 	} else {
   227 		surface->flags &= ~(SDL_SRCCOLORKEY|SDL_RLEACCELOK);
   228 		surface->format->colorkey = 0;
   229 	}
   230 	SDL_InvalidateMap(surface->map);
   231 	return(0);
   232 }
   233 /* This function sets the alpha channel of a surface */
   234 int SDL_SetAlpha (SDL_Surface *surface, Uint32 flag, Uint8 value)
   235 {
   236 	Uint32 oldflags = surface->flags;
   237 	Uint32 oldalpha = surface->format->alpha;
   238 
   239 	/* Sanity check the flag as it gets passed in */
   240 	if ( flag & SDL_SRCALPHA ) {
   241 		if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
   242 			flag = (SDL_SRCALPHA | SDL_RLEACCELOK);
   243 		} else {
   244 			flag = SDL_SRCALPHA;
   245 		}
   246 	} else {
   247 		flag = 0;
   248 	}
   249 
   250 	/* Optimize away operations that don't change anything */
   251 	if ( (flag == (surface->flags & (SDL_SRCALPHA|SDL_RLEACCELOK))) &&
   252 	     (!flag || value == oldalpha) ) {
   253 		return(0);
   254 	}
   255 
   256 	if(!(flag & SDL_RLEACCELOK) && (surface->flags & SDL_RLEACCEL))
   257 		SDL_UnRLESurface(surface, 1);
   258 
   259 	if ( flag ) {
   260 		SDL_VideoDevice *video = current_video;
   261 		SDL_VideoDevice *this  = current_video;
   262 
   263 		surface->flags |= SDL_SRCALPHA;
   264 		surface->format->alpha = value;
   265 		if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
   266 			if ( (video->SetHWAlpha == NULL) ||
   267 			     (video->SetHWAlpha(this, surface, value) < 0) ) {
   268 				surface->flags &= ~SDL_HWACCEL;
   269 			}
   270 		}
   271 		if ( flag & SDL_RLEACCELOK ) {
   272 		        surface->flags |= SDL_RLEACCELOK;
   273 		} else {
   274 		        surface->flags &= ~SDL_RLEACCELOK;
   275 		}
   276 	} else {
   277 		surface->flags &= ~SDL_SRCALPHA;
   278 		surface->format->alpha = SDL_ALPHA_OPAQUE;
   279 	}
   280 	/*
   281 	 * The representation for software surfaces is independent of
   282 	 * per-surface alpha, so no need to invalidate the blit mapping
   283 	 * if just the alpha value was changed. (If either is 255, we still
   284 	 * need to invalidate.)
   285 	 */
   286 	if((surface->flags & SDL_HWACCEL) == SDL_HWACCEL
   287 	   || oldflags != surface->flags
   288 	   || (((oldalpha + 1) ^ (value + 1)) & 0x100))
   289 		SDL_InvalidateMap(surface->map);
   290 	return(0);
   291 }
   292 int SDL_SetAlphaChannel(SDL_Surface *surface, Uint8 value)
   293 {
   294 	int row, col;
   295 	int offset;
   296 	Uint8 *buf;
   297 
   298 	if ( (surface->format->Amask != 0xFF000000) &&
   299 	     (surface->format->Amask != 0x000000FF) ) {
   300 		SDL_SetError("Unsupported surface alpha mask format");
   301 		return -1;
   302 	}
   303 
   304 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   305 	if ( surface->format->Amask == 0xFF000000 ) {
   306 			offset = 3;
   307 	} else {
   308 			offset = 0;
   309 	}
   310 #else
   311 	if ( surface->format->Amask == 0xFF000000 ) {
   312 			offset = 0;
   313 	} else {
   314 			offset = 3;
   315 	}
   316 #endif /* Byte ordering */
   317 
   318 	/* Quickly set the alpha channel of an RGBA or ARGB surface */
   319 	if ( SDL_MUSTLOCK(surface) ) {
   320 		if ( SDL_LockSurface(surface) < 0 ) {
   321 			return -1;
   322 		}
   323 	}
   324 	row = surface->h;
   325 	while (row--) {
   326 		col = surface->w;
   327 		buf = (Uint8 *)surface->pixels + row * surface->pitch + offset;
   328 		while(col--) {
   329 			*buf = value;
   330 			buf += 4;
   331 		}
   332 	}
   333 	if ( SDL_MUSTLOCK(surface) ) {
   334 		SDL_UnlockSurface(surface);
   335 	}
   336 	return 0;
   337 }
   338 
   339 /*
   340  * A function to calculate the intersection of two rectangles:
   341  * return true if the rectangles intersect, false otherwise
   342  */
   343 static __inline__
   344 SDL_bool SDL_IntersectRect(const SDL_Rect *A, const SDL_Rect *B, SDL_Rect *intersection)
   345 {
   346 	int Amin, Amax, Bmin, Bmax;
   347 
   348 	/* Horizontal intersection */
   349 	Amin = A->x;
   350 	Amax = Amin + A->w;
   351 	Bmin = B->x;
   352 	Bmax = Bmin + B->w;
   353 	if(Bmin > Amin)
   354 	        Amin = Bmin;
   355 	intersection->x = Amin;
   356 	if(Bmax < Amax)
   357 	        Amax = Bmax;
   358 	intersection->w = Amax - Amin > 0 ? Amax - Amin : 0;
   359 
   360 	/* Vertical intersection */
   361 	Amin = A->y;
   362 	Amax = Amin + A->h;
   363 	Bmin = B->y;
   364 	Bmax = Bmin + B->h;
   365 	if(Bmin > Amin)
   366 	        Amin = Bmin;
   367 	intersection->y = Amin;
   368 	if(Bmax < Amax)
   369 	        Amax = Bmax;
   370 	intersection->h = Amax - Amin > 0 ? Amax - Amin : 0;
   371 
   372 	return (intersection->w && intersection->h);
   373 }
   374 /*
   375  * Set the clipping rectangle for a blittable surface
   376  */
   377 SDL_bool SDL_SetClipRect(SDL_Surface *surface, const SDL_Rect *rect)
   378 {
   379 	SDL_Rect full_rect;
   380 
   381 	/* Don't do anything if there's no surface to act on */
   382 	if ( ! surface ) {
   383 		return SDL_FALSE;
   384 	}
   385 
   386 	/* Set up the full surface rectangle */
   387 	full_rect.x = 0;
   388 	full_rect.y = 0;
   389 	full_rect.w = surface->w;
   390 	full_rect.h = surface->h;
   391 
   392 	/* Set the clipping rectangle */
   393 	if ( ! rect ) {
   394 		surface->clip_rect = full_rect;
   395 		return 1;
   396 	}
   397 	return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   398 }
   399 void SDL_GetClipRect(SDL_Surface *surface, SDL_Rect *rect)
   400 {
   401 	if ( surface && rect ) {
   402 		*rect = surface->clip_rect;
   403 	}
   404 }
   405 /* 
   406  * Set up a blit between two surfaces -- split into three parts:
   407  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
   408  * verification.  The lower part is a pointer to a low level
   409  * accelerated blitting function.
   410  *
   411  * These parts are separated out and each used internally by this 
   412  * library in the optimimum places.  They are exported so that if
   413  * you know exactly what you are doing, you can optimize your code
   414  * by calling the one(s) you need.
   415  */
   416 int SDL_LowerBlit (SDL_Surface *src, SDL_Rect *srcrect,
   417 				SDL_Surface *dst, SDL_Rect *dstrect)
   418 {
   419 	SDL_blit do_blit;
   420 	SDL_Rect hw_srcrect;
   421 	SDL_Rect hw_dstrect;
   422 
   423 	/* Check to make sure the blit mapping is valid */
   424 	if ( (src->map->dst != dst) ||
   425              (src->map->dst->format_version != src->map->format_version) ) {
   426 		if ( SDL_MapSurface(src, dst) < 0 ) {
   427 			return(-1);
   428 		}
   429 	}
   430 
   431 	/* Figure out which blitter to use */
   432 	if ( (src->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
   433 		if ( src == SDL_VideoSurface ) {
   434 			hw_srcrect = *srcrect;
   435 			hw_srcrect.x += current_video->offset_x;
   436 			hw_srcrect.y += current_video->offset_y;
   437 			srcrect = &hw_srcrect;
   438 		}
   439 		if ( dst == SDL_VideoSurface ) {
   440 			hw_dstrect = *dstrect;
   441 			hw_dstrect.x += current_video->offset_x;
   442 			hw_dstrect.y += current_video->offset_y;
   443 			dstrect = &hw_dstrect;
   444 		}
   445 		do_blit = src->map->hw_blit;
   446 	} else {
   447 		do_blit = src->map->sw_blit;
   448 	}
   449 	return(do_blit(src, srcrect, dst, dstrect));
   450 }
   451 
   452 
   453 int SDL_UpperBlit (SDL_Surface *src, SDL_Rect *srcrect,
   454 		   SDL_Surface *dst, SDL_Rect *dstrect)
   455 {
   456         SDL_Rect fulldst;
   457 	int srcx, srcy, w, h;
   458 
   459 	/* Make sure the surfaces aren't locked */
   460 	if ( ! src || ! dst ) {
   461 		SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   462 		return(-1);
   463 	}
   464 	if ( src->locked || dst->locked ) {
   465 		SDL_SetError("Surfaces must not be locked during blit");
   466 		return(-1);
   467 	}
   468 
   469 	/* If the destination rectangle is NULL, use the entire dest surface */
   470 	if ( dstrect == NULL ) {
   471 	        fulldst.x = fulldst.y = 0;
   472 		dstrect = &fulldst;
   473 	}
   474 
   475 	/* clip the source rectangle to the source surface */
   476 	if(srcrect) {
   477 	        int maxw, maxh;
   478 	
   479 		srcx = srcrect->x;
   480 		w = srcrect->w;
   481 		if(srcx < 0) {
   482 		        w += srcx;
   483 			dstrect->x -= srcx;
   484 			srcx = 0;
   485 		}
   486 		maxw = src->w - srcx;
   487 		if(maxw < w)
   488 			w = maxw;
   489 
   490 		srcy = srcrect->y;
   491 		h = srcrect->h;
   492 		if(srcy < 0) {
   493 		        h += srcy;
   494 			dstrect->y -= srcy;
   495 			srcy = 0;
   496 		}
   497 		maxh = src->h - srcy;
   498 		if(maxh < h)
   499 			h = maxh;
   500 	    
   501 	} else {
   502 	        srcx = srcy = 0;
   503 		w = src->w;
   504 		h = src->h;
   505 	}
   506 
   507 	/* clip the destination rectangle against the clip rectangle */
   508 	{
   509 	        SDL_Rect *clip = &dst->clip_rect;
   510 		int dx, dy;
   511 
   512 		dx = clip->x - dstrect->x;
   513 		if(dx > 0) {
   514 			w -= dx;
   515 			dstrect->x += dx;
   516 			srcx += dx;
   517 		}
   518 		dx = dstrect->x + w - clip->x - clip->w;
   519 		if(dx > 0)
   520 			w -= dx;
   521 
   522 		dy = clip->y - dstrect->y;
   523 		if(dy > 0) {
   524 			h -= dy;
   525 			dstrect->y += dy;
   526 			srcy += dy;
   527 		}
   528 		dy = dstrect->y + h - clip->y - clip->h;
   529 		if(dy > 0)
   530 			h -= dy;
   531 	}
   532 
   533 	if(w > 0 && h > 0) {
   534 	        SDL_Rect sr;
   535 	        sr.x = srcx;
   536 		sr.y = srcy;
   537 		sr.w = dstrect->w = w;
   538 		sr.h = dstrect->h = h;
   539 		return SDL_LowerBlit(src, &sr, dst, dstrect);
   540 	}
   541 	dstrect->w = dstrect->h = 0;
   542 	return 0;
   543 }
   544 
   545 static int SDL_FillRect1(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
   546 {
   547 	/* FIXME: We have to worry about packing order.. *sigh* */
   548 	SDL_SetError("1-bpp rect fill not yet implemented");
   549 	return -1;
   550 }
   551 
   552 static int SDL_FillRect4(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
   553 {
   554 	/* FIXME: We have to worry about packing order.. *sigh* */
   555 	SDL_SetError("4-bpp rect fill not yet implemented");
   556 	return -1;
   557 }
   558 
   559 /* 
   560  * This function performs a fast fill of the given rectangle with 'color'
   561  */
   562 int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
   563 {
   564 	SDL_VideoDevice *video = current_video;
   565 	SDL_VideoDevice *this  = current_video;
   566 	int x, y;
   567 	Uint8 *row;
   568 
   569 	/* This function doesn't work on surfaces < 8 bpp */
   570 	if ( dst->format->BitsPerPixel < 8 ) {
   571 		switch(dst->format->BitsPerPixel) {
   572 		    case 1:
   573 			return SDL_FillRect1(dst, dstrect, color);
   574 			break;
   575 		    case 4:
   576 			return SDL_FillRect4(dst, dstrect, color);
   577 			break;
   578 		    default:
   579 			SDL_SetError("Fill rect on unsupported surface format");
   580 			return(-1);
   581 			break;
   582 		}
   583 	}
   584 
   585 	/* If 'dstrect' == NULL, then fill the whole surface */
   586 	if ( dstrect ) {
   587 		/* Perform clipping */
   588 		if ( !SDL_IntersectRect(dstrect, &dst->clip_rect, dstrect) ) {
   589 			return(0);
   590 		}
   591 	} else {
   592 		dstrect = &dst->clip_rect;
   593 	}
   594 
   595 	/* Check for hardware acceleration */
   596 	if ( ((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) &&
   597 					video->info.blit_fill ) {
   598 		SDL_Rect hw_rect;
   599 		if ( dst == SDL_VideoSurface ) {
   600 			hw_rect = *dstrect;
   601 			hw_rect.x += current_video->offset_x;
   602 			hw_rect.y += current_video->offset_y;
   603 			dstrect = &hw_rect;
   604 		}
   605 		return(video->FillHWRect(this, dst, dstrect, color));
   606 	}
   607 
   608 	/* Perform software fill */
   609 	if ( SDL_LockSurface(dst) != 0 ) {
   610 		return(-1);
   611 	}
   612 	row = (Uint8 *)dst->pixels+dstrect->y*dst->pitch+
   613 			dstrect->x*dst->format->BytesPerPixel;
   614 	if ( dst->format->palette || (color == 0) ) {
   615 		x = dstrect->w*dst->format->BytesPerPixel;
   616 		if ( !color && !((long)row&3) && !(x&3) && !(dst->pitch&3) ) {
   617 			int n = x >> 2;
   618 			for ( y=dstrect->h; y; --y ) {
   619 				SDL_memset4(row, 0, n);
   620 				row += dst->pitch;
   621 			}
   622 		} else {
   623 #ifdef __powerpc__
   624 			/*
   625 			 * memset() on PPC (both glibc and codewarrior) uses
   626 			 * the dcbz (Data Cache Block Zero) instruction, which
   627 			 * causes an alignment exception if the destination is
   628 			 * uncachable, so only use it on software surfaces
   629 			 */
   630 			if((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) {
   631 				if(dstrect->w >= 8) {
   632 					/*
   633 					 * 64-bit stores are probably most
   634 					 * efficient to uncached video memory
   635 					 */
   636 					double fill;
   637 					memset(&fill, color, (sizeof fill));
   638 					for(y = dstrect->h; y; y--) {
   639 						Uint8 *d = row;
   640 						unsigned n = x;
   641 						unsigned nn;
   642 						Uint8 c = color;
   643 						double f = fill;
   644 						while((unsigned long)d
   645 						      & (sizeof(double) - 1)) {
   646 							*d++ = c;
   647 							n--;
   648 						}
   649 						nn = n / (sizeof(double) * 4);
   650 						while(nn) {
   651 							((double *)d)[0] = f;
   652 							((double *)d)[1] = f;
   653 							((double *)d)[2] = f;
   654 							((double *)d)[3] = f;
   655 							d += 4*sizeof(double);
   656 							nn--;
   657 						}
   658 						n &= ~(sizeof(double) * 4 - 1);
   659 						nn = n / sizeof(double);
   660 						while(nn) {
   661 							*(double *)d = f;
   662 							d += sizeof(double);
   663 							nn--;
   664 						}
   665 						n &= ~(sizeof(double) - 1);
   666 						while(n) {
   667 							*d++ = c;
   668 							n--;
   669 						}
   670 						row += dst->pitch;
   671 					}
   672 				} else {
   673 					/* narrow boxes */
   674 					for(y = dstrect->h; y; y--) {
   675 						Uint8 *d = row;
   676 						Uint8 c = color;
   677 						int n = x;
   678 						while(n) {
   679 							*d++ = c;
   680 							n--;
   681 						}
   682 						row += dst->pitch;
   683 					}
   684 				}
   685 			} else
   686 #endif /* __powerpc__ */
   687 			{
   688 				for(y = dstrect->h; y; y--) {
   689 					memset(row, color, x);
   690 					row += dst->pitch;
   691 				}
   692 			}
   693 		}
   694 	} else {
   695 		switch (dst->format->BytesPerPixel) {
   696 		    case 2:
   697 			for ( y=dstrect->h; y; --y ) {
   698 				Uint16 *pixels = (Uint16 *)row;
   699 				Uint16 c = color;
   700 				Uint32 cc = (Uint32)c << 16 | c;
   701 				int n = dstrect->w;
   702 				if((unsigned long)pixels & 3) {
   703 					*pixels++ = c;
   704 					n--;
   705 				}
   706 				if(n >> 1)
   707 					SDL_memset4(pixels, cc, n >> 1);
   708 				if(n & 1)
   709 					pixels[n - 1] = c;
   710 				row += dst->pitch;
   711 			}
   712 			break;
   713 
   714 		    case 3:
   715 			if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
   716 				color <<= 8;
   717 			for ( y=dstrect->h; y; --y ) {
   718 				Uint8 *pixels = row;
   719 				for ( x=dstrect->w; x; --x ) {
   720 					memcpy(pixels, &color, 3);
   721 					pixels += 3;
   722 				}
   723 				row += dst->pitch;
   724 			}
   725 			break;
   726 
   727 		    case 4:
   728 			for(y = dstrect->h; y; --y) {
   729 				SDL_memset4(row, color, dstrect->w);
   730 				row += dst->pitch;
   731 			}
   732 			break;
   733 		}
   734 	}
   735 	SDL_UnlockSurface(dst);
   736 
   737 	/* We're done! */
   738 	return(0);
   739 }
   740 
   741 /*
   742  * Lock a surface to directly access the pixels
   743  */
   744 int SDL_LockSurface (SDL_Surface *surface)
   745 {
   746 	if ( ! surface->locked ) {
   747 		/* Perform the lock */
   748 		if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
   749 			SDL_VideoDevice *video = current_video;
   750 			SDL_VideoDevice *this  = current_video;
   751 			if ( video->LockHWSurface(this, surface) < 0 ) {
   752 				return(-1);
   753 			}
   754 		}
   755 		if ( surface->flags & SDL_RLEACCEL ) {
   756 			SDL_UnRLESurface(surface, 1);
   757 			surface->flags |= SDL_RLEACCEL;	/* save accel'd state */
   758 		}
   759 		/* This needs to be done here in case pixels changes value */
   760 		surface->pixels = (Uint8 *)surface->pixels + surface->offset;
   761 	}
   762 
   763 	/* Increment the surface lock count, for recursive locks */
   764 	++surface->locked;
   765 
   766 	/* Ready to go.. */
   767 	return(0);
   768 }
   769 /*
   770  * Unlock a previously locked surface
   771  */
   772 void SDL_UnlockSurface (SDL_Surface *surface)
   773 {
   774 	/* Only perform an unlock if we are locked */
   775 	if ( ! surface->locked || (--surface->locked > 0) ) {
   776 		return;
   777 	}
   778 
   779 	/* Perform the unlock */
   780 	surface->pixels = (Uint8 *)surface->pixels - surface->offset;
   781 
   782 	/* Unlock hardware or accelerated surfaces */
   783 	if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
   784 		SDL_VideoDevice *video = current_video;
   785 		SDL_VideoDevice *this  = current_video;
   786 		video->UnlockHWSurface(this, surface);
   787 	} else {
   788 		/* Update RLE encoded surface with new data */
   789 		if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
   790 		        surface->flags &= ~SDL_RLEACCEL; /* stop lying */
   791 			SDL_RLESurface(surface);
   792 		}
   793 	}
   794 }
   795 
   796 /* 
   797  * Convert a surface into the specified pixel format.
   798  */
   799 SDL_Surface * SDL_ConvertSurface (SDL_Surface *surface,
   800 					SDL_PixelFormat *format, Uint32 flags)
   801 {
   802 	SDL_Surface *convert;
   803 	Uint32 colorkey = 0;
   804 	Uint8 alpha = 0;
   805 	Uint32 surface_flags;
   806 	SDL_Rect bounds;
   807 
   808 	/* Check for empty destination palette! (results in empty image) */
   809 	if ( format->palette != NULL ) {
   810 		int i;
   811 		for ( i=0; i<format->palette->ncolors; ++i ) {
   812 			if ( (format->palette->colors[i].r != 0) ||
   813 			     (format->palette->colors[i].g != 0) ||
   814 			     (format->palette->colors[i].b != 0) )
   815 				break;
   816 		}
   817 		if ( i == format->palette->ncolors ) {
   818 			SDL_SetError("Empty destination palette");
   819 			return(NULL);
   820 		}
   821 	}
   822 
   823 	/* Only create hw surfaces with alpha channel if hw alpha blits
   824 	   are supported */
   825 	if(format->Amask != 0 && (flags & SDL_HWSURFACE)) {
   826 		const SDL_VideoInfo *vi = SDL_GetVideoInfo();
   827 		if(!vi || !vi->blit_hw_A)
   828 			flags &= ~SDL_HWSURFACE;
   829 	}
   830 
   831 	/* Create a new surface with the desired format */
   832 	convert = SDL_CreateRGBSurface(flags,
   833 				surface->w, surface->h, format->BitsPerPixel,
   834 		format->Rmask, format->Gmask, format->Bmask, format->Amask);
   835 	if ( convert == NULL ) {
   836 		return(NULL);
   837 	}
   838 
   839 	/* Copy the palette if any */
   840 	if ( format->palette && convert->format->palette ) {
   841 		memcpy(convert->format->palette->colors,
   842 				format->palette->colors,
   843 				format->palette->ncolors*sizeof(SDL_Color));
   844 		convert->format->palette->ncolors = format->palette->ncolors;
   845 	}
   846 
   847 	/* Save the original surface color key and alpha */
   848 	surface_flags = surface->flags;
   849 	if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
   850 		/* Convert colourkeyed surfaces to RGBA if requested */
   851 		if((flags & SDL_SRCCOLORKEY) != SDL_SRCCOLORKEY
   852 		   && format->Amask) {
   853 			surface_flags &= ~SDL_SRCCOLORKEY;
   854 		} else {
   855 			colorkey = surface->format->colorkey;
   856 			SDL_SetColorKey(surface, 0, 0);
   857 		}
   858 	}
   859 	if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
   860 		/* Copy over the alpha channel to RGBA if requested */
   861 		if ( format->Amask ) {
   862 			surface->flags &= ~SDL_SRCALPHA;
   863 		} else {
   864 			alpha = surface->format->alpha;
   865 			SDL_SetAlpha(surface, 0, 0);
   866 		}
   867 	}
   868 
   869 	/* Copy over the image data */
   870 	bounds.x = 0;
   871 	bounds.y = 0;
   872 	bounds.w = surface->w;
   873 	bounds.h = surface->h;
   874 	SDL_LowerBlit(surface, &bounds, convert, &bounds);
   875 
   876 	/* Clean up the original surface, and update converted surface */
   877 	if ( convert != NULL ) {
   878 		SDL_SetClipRect(convert, &surface->clip_rect);
   879 	}
   880 	if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
   881 		Uint32 cflags = surface_flags&(SDL_SRCCOLORKEY|SDL_RLEACCELOK);
   882 		if ( convert != NULL ) {
   883 			Uint8 keyR, keyG, keyB;
   884 
   885 			SDL_GetRGB(colorkey,surface->format,&keyR,&keyG,&keyB);
   886 			SDL_SetColorKey(convert, cflags|(flags&SDL_RLEACCELOK),
   887 				SDL_MapRGB(convert->format, keyR, keyG, keyB));
   888 		}
   889 		SDL_SetColorKey(surface, cflags, colorkey);
   890 	}
   891 	if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
   892 		Uint32 aflags = surface_flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
   893 		if ( convert != NULL ) {
   894 		        SDL_SetAlpha(convert, aflags|(flags&SDL_RLEACCELOK),
   895 				alpha);
   896 		}
   897 		if ( format->Amask ) {
   898 			surface->flags |= SDL_SRCALPHA;
   899 		} else {
   900 			SDL_SetAlpha(surface, aflags, alpha);
   901 		}
   902 	}
   903 
   904 	/* We're ready to go! */
   905 	return(convert);
   906 }
   907 
   908 /*
   909  * Free a surface created by the above function.
   910  */
   911 void SDL_FreeSurface (SDL_Surface *surface)
   912 {
   913 	/* Free anything that's not NULL, and not the screen surface */
   914 	if ((surface == NULL) ||
   915 	    (current_video &&
   916 	    ((surface == SDL_ShadowSurface)||(surface == SDL_VideoSurface)))) {
   917 		return;
   918 	}
   919 	if ( --surface->refcount > 0 ) {
   920 		return;
   921 	}
   922 	while ( surface->locked > 0 ) {
   923 		SDL_UnlockSurface(surface);
   924 	}
   925 	if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
   926 	        SDL_UnRLESurface(surface, 0);
   927 	}
   928 	if ( surface->format ) {
   929 		SDL_FreeFormat(surface->format);
   930 		surface->format = NULL;
   931 	}
   932 	if ( surface->map != NULL ) {
   933 		SDL_FreeBlitMap(surface->map);
   934 		surface->map = NULL;
   935 	}
   936 	if ( surface->hwdata ) {
   937 		SDL_VideoDevice *video = current_video;
   938 		SDL_VideoDevice *this  = current_video;
   939 		video->FreeHWSurface(this, surface);
   940 	}
   941 	if ( surface->pixels &&
   942 	     ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC) ) {
   943 		free(surface->pixels);
   944 	}
   945 	free(surface);
   946 #ifdef CHECK_LEAKS
   947 	--surfaces_allocated;
   948 #endif
   949 }