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