src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 16 Aug 2007 05:56:24 +0000
changeset 2249 5a58b57b6724
parent 2239 31835fd24b2b
child 2251 292bee385630
permissions -rw-r--r--
Added SSE and MMX optimization for SDL_FillRect()
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_video.h"
    25 #include "SDL_compat.h"
    26 #include "SDL_sysvideo.h"
    27 #include "SDL_blit.h"
    28 #include "SDL_RLEaccel_c.h"
    29 #include "SDL_pixels_c.h"
    30 #include "SDL_leaks.h"
    31 
    32 
    33 /* Public routines */
    34 /*
    35  * Create an empty RGB surface of the appropriate depth
    36  */
    37 SDL_Surface *
    38 SDL_CreateRGBSurface(Uint32 flags,
    39                      int width, int height, int depth,
    40                      Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    41 {
    42     SDL_Surface *surface;
    43 
    44     /* Allocate the surface */
    45     surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
    46     if (surface == NULL) {
    47         SDL_OutOfMemory();
    48         return NULL;
    49     }
    50 
    51     surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
    52     if (!surface->format) {
    53         SDL_FreeSurface(surface);
    54         return NULL;
    55     }
    56     if (Amask) {
    57         surface->flags |= SDL_SRCALPHA;
    58     }
    59     surface->w = width;
    60     surface->h = height;
    61     surface->pitch = SDL_CalculatePitch(surface);
    62     SDL_SetClipRect(surface, NULL);
    63 
    64     if (surface->format->BitsPerPixel <= 8) {
    65         SDL_Palette *palette =
    66             SDL_AllocPalette((1 << surface->format->BitsPerPixel));
    67         if (!palette) {
    68             SDL_FreeSurface(surface);
    69             return NULL;
    70         }
    71         if (Rmask || Bmask || Gmask) {
    72             const SDL_PixelFormat *format = surface->format;
    73 
    74             /* create palette according to masks */
    75             int i;
    76             int Rm = 0, Gm = 0, Bm = 0;
    77             int Rw = 0, Gw = 0, Bw = 0;
    78 
    79             if (Rmask) {
    80                 Rw = 8 - format->Rloss;
    81                 for (i = format->Rloss; i > 0; i -= Rw)
    82                     Rm |= 1 << i;
    83             }
    84             if (Gmask) {
    85                 Gw = 8 - format->Gloss;
    86                 for (i = format->Gloss; i > 0; i -= Gw)
    87                     Gm |= 1 << i;
    88             }
    89             if (Bmask) {
    90                 Bw = 8 - format->Bloss;
    91                 for (i = format->Bloss; i > 0; i -= Bw)
    92                     Bm |= 1 << i;
    93             }
    94             for (i = 0; i < palette->ncolors; ++i) {
    95                 int r, g, b;
    96                 r = (i & Rmask) >> format->Rshift;
    97                 r = (r << format->Rloss) | ((r * Rm) >> Rw);
    98                 palette->colors[i].r = r;
    99 
   100                 g = (i & Gmask) >> format->Gshift;
   101                 g = (g << format->Gloss) | ((g * Gm) >> Gw);
   102                 palette->colors[i].g = g;
   103 
   104                 b = (i & Bmask) >> format->Bshift;
   105                 b = (b << format->Bloss) | ((b * Bm) >> Bw);
   106                 palette->colors[i].b = b;
   107             }
   108         } else if (palette->ncolors == 2) {
   109             /* Create a black and white bitmap palette */
   110             palette->colors[0].r = 0xFF;
   111             palette->colors[0].g = 0xFF;
   112             palette->colors[0].b = 0xFF;
   113             palette->colors[1].r = 0x00;
   114             palette->colors[1].g = 0x00;
   115             palette->colors[1].b = 0x00;
   116         }
   117         SDL_SetSurfacePalette(surface, palette);
   118         SDL_FreePalette(palette);
   119     }
   120 
   121     /* Get the pixels */
   122     if (surface->w && surface->h) {
   123         surface->pixels = SDL_malloc(surface->h * surface->pitch);
   124         if (!surface->pixels) {
   125             SDL_FreeSurface(surface);
   126             SDL_OutOfMemory();
   127             return NULL;
   128         }
   129         /* This is important for bitmaps */
   130         SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
   131     }
   132 
   133     /* Allocate an empty mapping */
   134     surface->map = SDL_AllocBlitMap();
   135     if (!surface->map) {
   136         SDL_FreeSurface(surface);
   137         return NULL;
   138     }
   139     SDL_FormatChanged(surface);
   140 
   141     /* The surface is ready to go */
   142     surface->refcount = 1;
   143 #ifdef CHECK_LEAKS
   144     ++surfaces_allocated;
   145 #endif
   146     return surface;
   147 }
   148 
   149 /*
   150  * Create an RGB surface from an existing memory buffer
   151  */
   152 SDL_Surface *
   153 SDL_CreateRGBSurfaceFrom(void *pixels,
   154                          int width, int height, int depth, int pitch,
   155                          Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
   156                          Uint32 Amask)
   157 {
   158     SDL_Surface *surface;
   159 
   160     surface =
   161         SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
   162     if (surface != NULL) {
   163         surface->flags |= SDL_PREALLOC;
   164         surface->pixels = pixels;
   165         surface->w = width;
   166         surface->h = height;
   167         surface->pitch = pitch;
   168         SDL_SetClipRect(surface, NULL);
   169     }
   170     return surface;
   171 }
   172 
   173 static int
   174 SDL_SurfacePaletteChanged(void *userdata, SDL_Palette * palette)
   175 {
   176     SDL_Surface *surface = (SDL_Surface *) userdata;
   177 
   178     SDL_FormatChanged(surface);
   179 
   180     return 0;
   181 }
   182 
   183 int
   184 SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
   185 {
   186     if (!surface || !surface->format) {
   187         SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
   188         return -1;
   189     }
   190 
   191     if (palette && palette->ncolors != (1 << surface->format->BitsPerPixel)) {
   192         SDL_SetError
   193             ("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format");
   194         return -1;
   195     }
   196 
   197     if (surface->format->palette == palette) {
   198         return 0;
   199     }
   200 
   201     if (surface->format->palette) {
   202         SDL_DelPaletteWatch(surface->format->palette,
   203                             SDL_SurfacePaletteChanged, surface);
   204     }
   205 
   206     surface->format->palette = palette;
   207 
   208     if (surface->format->palette) {
   209         SDL_AddPaletteWatch(surface->format->palette,
   210                             SDL_SurfacePaletteChanged, surface);
   211     }
   212     return 0;
   213 }
   214 
   215 /*
   216  * Set the color key in a blittable surface
   217  */
   218 int
   219 SDL_SetColorKey(SDL_Surface * surface, Uint32 flag, Uint32 key)
   220 {
   221     /* Sanity check the flag as it gets passed in */
   222     if (flag & SDL_SRCCOLORKEY) {
   223         if (flag & (SDL_RLEACCEL | SDL_RLEACCELOK)) {
   224             flag = (SDL_SRCCOLORKEY | SDL_RLEACCELOK);
   225         } else {
   226             flag = SDL_SRCCOLORKEY;
   227         }
   228     } else {
   229         flag = 0;
   230     }
   231 
   232     /* Optimize away operations that don't change anything */
   233     if ((flag == (surface->flags & (SDL_SRCCOLORKEY | SDL_RLEACCELOK))) &&
   234         (key == surface->format->colorkey)) {
   235         return (0);
   236     }
   237 
   238     /* UnRLE surfaces before we change the colorkey */
   239     if (surface->flags & SDL_RLEACCEL) {
   240         SDL_UnRLESurface(surface, 1);
   241     }
   242 
   243     if (flag) {
   244         surface->flags |= SDL_SRCCOLORKEY;
   245         surface->format->colorkey = key;
   246         if (flag & SDL_RLEACCELOK) {
   247             surface->flags |= SDL_RLEACCELOK;
   248         } else {
   249             surface->flags &= ~SDL_RLEACCELOK;
   250         }
   251     } else {
   252         surface->flags &= ~(SDL_SRCCOLORKEY | SDL_RLEACCELOK);
   253         surface->format->colorkey = 0;
   254     }
   255     SDL_InvalidateMap(surface->map);
   256     return (0);
   257 }
   258 
   259 /* This function sets the alpha channel of a surface */
   260 int
   261 SDL_SetAlpha(SDL_Surface * surface, Uint32 flag, Uint8 value)
   262 {
   263     Uint32 oldflags = surface->flags;
   264     Uint32 oldalpha = surface->format->alpha;
   265 
   266     /* Sanity check the flag as it gets passed in */
   267     if (flag & SDL_SRCALPHA) {
   268         if (flag & (SDL_RLEACCEL | SDL_RLEACCELOK)) {
   269             flag = (SDL_SRCALPHA | SDL_RLEACCELOK);
   270         } else {
   271             flag = SDL_SRCALPHA;
   272         }
   273     } else {
   274         flag = 0;
   275     }
   276 
   277     /* Optimize away operations that don't change anything */
   278     if ((flag == (surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK))) &&
   279         (!flag || value == oldalpha)) {
   280         return (0);
   281     }
   282 
   283     if (!(flag & SDL_RLEACCELOK) && (surface->flags & SDL_RLEACCEL))
   284         SDL_UnRLESurface(surface, 1);
   285 
   286     if (flag) {
   287         surface->flags |= SDL_SRCALPHA;
   288         surface->format->alpha = value;
   289         if (flag & SDL_RLEACCELOK) {
   290             surface->flags |= SDL_RLEACCELOK;
   291         } else {
   292             surface->flags &= ~SDL_RLEACCELOK;
   293         }
   294     } else {
   295         surface->flags &= ~SDL_SRCALPHA;
   296         surface->format->alpha = SDL_ALPHA_OPAQUE;
   297     }
   298     /*
   299      * The representation for software surfaces is independent of
   300      * per-surface alpha, so no need to invalidate the blit mapping
   301      * if just the alpha value was changed. (If either is 255, we still
   302      * need to invalidate.)
   303      */
   304     if (oldflags != surface->flags
   305         || (((oldalpha + 1) ^ (value + 1)) & 0x100)) {
   306         SDL_InvalidateMap(surface->map);
   307     }
   308     return (0);
   309 }
   310 
   311 int
   312 SDL_SetAlphaChannel(SDL_Surface * surface, Uint8 value)
   313 {
   314     int row, col;
   315     int offset;
   316     Uint8 *buf;
   317 
   318     if ((surface->format->Amask != 0xFF000000) &&
   319         (surface->format->Amask != 0x000000FF)) {
   320         SDL_SetError("Unsupported surface alpha mask format");
   321         return -1;
   322     }
   323 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   324     if (surface->format->Amask == 0xFF000000) {
   325         offset = 3;
   326     } else {
   327         offset = 0;
   328     }
   329 #else
   330     if (surface->format->Amask == 0xFF000000) {
   331         offset = 0;
   332     } else {
   333         offset = 3;
   334     }
   335 #endif /* Byte ordering */
   336 
   337     /* Quickly set the alpha channel of an RGBA or ARGB surface */
   338     if (SDL_MUSTLOCK(surface)) {
   339         if (SDL_LockSurface(surface) < 0) {
   340             return -1;
   341         }
   342     }
   343     row = surface->h;
   344     while (row--) {
   345         col = surface->w;
   346         buf = (Uint8 *) surface->pixels + row * surface->pitch + offset;
   347         while (col--) {
   348             *buf = value;
   349             buf += 4;
   350         }
   351     }
   352     if (SDL_MUSTLOCK(surface)) {
   353         SDL_UnlockSurface(surface);
   354     }
   355     return 0;
   356 }
   357 
   358 /*
   359  * Set the clipping rectangle for a blittable surface
   360  */
   361 SDL_bool
   362 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
   363 {
   364     SDL_Rect full_rect;
   365 
   366     /* Don't do anything if there's no surface to act on */
   367     if (!surface) {
   368         return SDL_FALSE;
   369     }
   370 
   371     /* Set up the full surface rectangle */
   372     full_rect.x = 0;
   373     full_rect.y = 0;
   374     full_rect.w = surface->w;
   375     full_rect.h = surface->h;
   376 
   377     /* Set the clipping rectangle */
   378     if (!rect) {
   379         surface->clip_rect = full_rect;
   380         return 1;
   381     }
   382     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   383 }
   384 
   385 void
   386 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
   387 {
   388     if (surface && rect) {
   389         *rect = surface->clip_rect;
   390     }
   391 }
   392 
   393 /* 
   394  * Set up a blit between two surfaces -- split into three parts:
   395  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
   396  * verification.  The lower part is a pointer to a low level
   397  * accelerated blitting function.
   398  *
   399  * These parts are separated out and each used internally by this 
   400  * library in the optimimum places.  They are exported so that if
   401  * you know exactly what you are doing, you can optimize your code
   402  * by calling the one(s) you need.
   403  */
   404 int
   405 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
   406               SDL_Surface * dst, SDL_Rect * dstrect)
   407 {
   408     /* Check to make sure the blit mapping is valid */
   409     if ((src->map->dst != dst) ||
   410         (src->map->dst->format_version != src->map->format_version)) {
   411         if (SDL_MapSurface(src, dst) < 0) {
   412             return (-1);
   413         }
   414     }
   415     return (src->map->sw_blit(src, srcrect, dst, dstrect));
   416 }
   417 
   418 
   419 int
   420 SDL_UpperBlit(SDL_Surface * src, SDL_Rect * srcrect,
   421               SDL_Surface * dst, SDL_Rect * dstrect)
   422 {
   423     SDL_Rect fulldst;
   424     int srcx, srcy, w, h;
   425 
   426     /* Make sure the surfaces aren't locked */
   427     if (!src || !dst) {
   428         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   429         return (-1);
   430     }
   431     if (src->locked || dst->locked) {
   432         SDL_SetError("Surfaces must not be locked during blit");
   433         return (-1);
   434     }
   435 
   436     /* If the destination rectangle is NULL, use the entire dest surface */
   437     if (dstrect == NULL) {
   438         fulldst.x = fulldst.y = 0;
   439         dstrect = &fulldst;
   440     }
   441 
   442     /* clip the source rectangle to the source surface */
   443     if (srcrect) {
   444         int maxw, maxh;
   445 
   446         srcx = srcrect->x;
   447         w = srcrect->w;
   448         if (srcx < 0) {
   449             w += srcx;
   450             dstrect->x -= srcx;
   451             srcx = 0;
   452         }
   453         maxw = src->w - srcx;
   454         if (maxw < w)
   455             w = maxw;
   456 
   457         srcy = srcrect->y;
   458         h = srcrect->h;
   459         if (srcy < 0) {
   460             h += srcy;
   461             dstrect->y -= srcy;
   462             srcy = 0;
   463         }
   464         maxh = src->h - srcy;
   465         if (maxh < h)
   466             h = maxh;
   467 
   468     } else {
   469         srcx = srcy = 0;
   470         w = src->w;
   471         h = src->h;
   472     }
   473 
   474     /* clip the destination rectangle against the clip rectangle */
   475     {
   476         SDL_Rect *clip = &dst->clip_rect;
   477         int dx, dy;
   478 
   479         dx = clip->x - dstrect->x;
   480         if (dx > 0) {
   481             w -= dx;
   482             dstrect->x += dx;
   483             srcx += dx;
   484         }
   485         dx = dstrect->x + w - clip->x - clip->w;
   486         if (dx > 0)
   487             w -= dx;
   488 
   489         dy = clip->y - dstrect->y;
   490         if (dy > 0) {
   491             h -= dy;
   492             dstrect->y += dy;
   493             srcy += dy;
   494         }
   495         dy = dstrect->y + h - clip->y - clip->h;
   496         if (dy > 0)
   497             h -= dy;
   498     }
   499 
   500     if (w > 0 && h > 0) {
   501         SDL_Rect sr;
   502         sr.x = srcx;
   503         sr.y = srcy;
   504         sr.w = dstrect->w = w;
   505         sr.h = dstrect->h = h;
   506         return SDL_LowerBlit(src, &sr, dst, dstrect);
   507     }
   508     dstrect->w = dstrect->h = 0;
   509     return 0;
   510 }
   511 
   512 #ifdef __SSE__
   513 /* *INDENT-OFF* */
   514 
   515 #define SSE_BEGIN \
   516     DECLARE_ALIGNED(Uint32, cccc[4], 16); \
   517     cccc[0] = color; \
   518     cccc[1] = color; \
   519     cccc[2] = color; \
   520     cccc[3] = color; \
   521     __m128 c128 = *(__m128 *)cccc;
   522 
   523 #define SSE_WORK \
   524     for (i = n / 64; i--;) { \
   525         _mm_stream_ps((float *)(p+0), c128); \
   526         _mm_stream_ps((float *)(p+16), c128); \
   527         _mm_stream_ps((float *)(p+32), c128); \
   528         _mm_stream_ps((float *)(p+48), c128); \
   529         p += 64; \
   530     }
   531 
   532 #define SSE_END
   533 
   534 #define DEFINE_SSE_FILLRECT(bpp, type) \
   535 static void \
   536 SDL_FillRect##bpp##SSE(Uint8 *pixels, int pitch, Uint32 color, int w, int h) \
   537 { \
   538     SSE_BEGIN; \
   539  \
   540     while (h--) { \
   541         int i, n = w * bpp; \
   542         Uint8 *p = pixels; \
   543  \
   544         if (n > 15) { \
   545             int adjust = 16 - ((uintptr_t)p & 15); \
   546             if (adjust < 16) { \
   547                 n -= adjust; \
   548                 adjust /= bpp; \
   549                 while(adjust--) { \
   550                     *((type *)p) = (type)color; \
   551                     p += bpp; \
   552                 } \
   553             } \
   554             SSE_WORK; \
   555         } \
   556         if (n & 63) { \
   557             int remainder = (n & 63); \
   558             remainder /= bpp; \
   559             while(remainder--) { \
   560                 *((type *)p) = (type)color; \
   561                 p += bpp; \
   562             } \
   563         } \
   564         pixels += pitch; \
   565     } \
   566  \
   567     SSE_END; \
   568 }
   569 
   570 DEFINE_SSE_FILLRECT(1, Uint8)
   571 DEFINE_SSE_FILLRECT(2, Uint16)
   572 DEFINE_SSE_FILLRECT(4, Uint32)
   573 
   574 /* *INDENT-ON* */
   575 #endif /* __SSE__ */
   576 
   577 #ifdef __MMX__
   578 /* *INDENT-OFF* */
   579 
   580 #define MMX_BEGIN \
   581     __m64 c64 = _mm_set_pi32(color, color)
   582 
   583 #define MMX_WORK \
   584     for (i = n / 64; i--;) { \
   585         _mm_stream_pi((__m64 *)(p+0), c64); \
   586         _mm_stream_pi((__m64 *)(p+8), c64); \
   587         _mm_stream_pi((__m64 *)(p+16), c64); \
   588         _mm_stream_pi((__m64 *)(p+24), c64); \
   589         _mm_stream_pi((__m64 *)(p+32), c64); \
   590         _mm_stream_pi((__m64 *)(p+40), c64); \
   591         _mm_stream_pi((__m64 *)(p+48), c64); \
   592         _mm_stream_pi((__m64 *)(p+56), c64); \
   593         p += 64; \
   594     }
   595 
   596 #define MMX_END \
   597     _mm_empty()
   598 
   599 #define DEFINE_MMX_FILLRECT(bpp, type) \
   600 static void \
   601 SDL_FillRect##bpp##MMX(Uint8 *pixels, int pitch, Uint32 color, int w, int h) \
   602 { \
   603     MMX_BEGIN; \
   604  \
   605     while (h--) { \
   606         int i, n = w * bpp; \
   607         Uint8 *p = pixels; \
   608  \
   609         if (n > 7) { \
   610             int adjust = 8 - ((uintptr_t)p & 7); \
   611             if (adjust < 8) { \
   612                 n -= adjust; \
   613                 adjust /= bpp; \
   614                 while(adjust--) { \
   615                     *((type *)p) = (type)color; \
   616                     p += bpp; \
   617                 } \
   618             } \
   619             MMX_WORK; \
   620         } \
   621         if (n & 63) { \
   622             int remainder = (n & 63); \
   623             remainder /= bpp; \
   624             while(remainder--) { \
   625                 *((type *)p) = (type)color; \
   626                 p += bpp; \
   627             } \
   628         } \
   629         pixels += pitch; \
   630     } \
   631  \
   632     MMX_END; \
   633 }
   634 
   635 DEFINE_MMX_FILLRECT(1, Uint8)
   636 DEFINE_MMX_FILLRECT(2, Uint16)
   637 DEFINE_MMX_FILLRECT(4, Uint32)
   638 
   639 /* *INDENT-ON* */
   640 #endif /* __MMX__ */
   641 
   642 static void
   643 SDL_FillRect1(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   644 {
   645     while (h--) {
   646         int n = w;
   647         Uint8 *p = pixels;
   648 
   649         if (n > 3) {
   650             switch ((uintptr_t) p & 3) {
   651             case 1:
   652                 *p++ = (Uint8) color;
   653                 --n;
   654             case 2:
   655                 *p++ = (Uint8) color;
   656                 --n;
   657             case 3:
   658                 *p++ = (Uint8) color;
   659                 --n;
   660             }
   661             SDL_memset4(p, color, (n >> 2));
   662         }
   663         if (n & 3) {
   664             p += (n & ~3);
   665             switch (n & 3) {
   666             case 3:
   667                 *p++ = (Uint8) color;
   668             case 2:
   669                 *p++ = (Uint8) color;
   670             case 1:
   671                 *p++ = (Uint8) color;
   672             }
   673         }
   674         pixels += pitch;
   675     }
   676 }
   677 
   678 static void
   679 SDL_FillRect2(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   680 {
   681     while (h--) {
   682         int n = w;
   683         Uint16 *p = (Uint16 *) pixels;
   684 
   685         if (n > 1) {
   686             if ((uintptr_t) p & 2) {
   687                 *p++ = (Uint16) color;
   688                 --n;
   689             }
   690             SDL_memset4(p, color, (n >> 1));
   691         }
   692         if (n & 1) {
   693             p[n - 1] = (Uint16) color;
   694         }
   695         pixels += pitch;
   696     }
   697 }
   698 
   699 static void
   700 SDL_FillRect3(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   701 {
   702     Uint8 r = (Uint8) (color & 0xFF);
   703     Uint8 g = (Uint8) ((color >> 8) & 0xFF);
   704     Uint8 b = (Uint8) ((color >> 16) & 0xFF);
   705 
   706     while (h--) {
   707         int n = w;
   708         Uint8 *p = pixels;
   709 
   710         while (n--) {
   711             *p++ = r;
   712             *p++ = g;
   713             *p++ = b;
   714         }
   715         pixels += pitch;
   716     }
   717 }
   718 
   719 static void
   720 SDL_FillRect4(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   721 {
   722     while (h--) {
   723         SDL_memset4(pixels, color, w);
   724         pixels += pitch;
   725     }
   726 }
   727 
   728 /* 
   729  * This function performs a fast fill of the given rectangle with 'color'
   730  */
   731 int
   732 SDL_FillRect(SDL_Surface * dst, SDL_Rect * dstrect, Uint32 color)
   733 {
   734     Uint8 *pixels;
   735 
   736     /* This function doesn't work on surfaces < 8 bpp */
   737     if (dst->format->BitsPerPixel < 8) {
   738         SDL_SetError("Fill rect on unsupported surface format");
   739         return (-1);
   740     }
   741 
   742     /* If 'dstrect' == NULL, then fill the whole surface */
   743     if (dstrect) {
   744         /* Perform clipping */
   745         if (!SDL_IntersectRect(dstrect, &dst->clip_rect, dstrect)) {
   746             return (0);
   747         }
   748     } else {
   749         dstrect = &dst->clip_rect;
   750     }
   751 
   752     /* Perform software fill */
   753     if (SDL_LockSurface(dst) != 0) {
   754         return (-1);
   755     }
   756 
   757     pixels =
   758         (Uint8 *) dst->pixels + dstrect->y * dst->pitch +
   759         dstrect->x * dst->format->BytesPerPixel;
   760 
   761     switch (dst->format->BytesPerPixel) {
   762     case 1:
   763         {
   764             color |= (color << 8);
   765             color |= (color << 16);
   766 #ifdef __SSE__
   767             if (SDL_HasSSE()) {
   768                 SDL_FillRect1SSE(pixels, dst->pitch, color, dstrect->w,
   769                                  dstrect->h);
   770                 break;
   771             }
   772 #endif
   773 #ifdef __MMX__
   774             if (SDL_HasMMX()) {
   775                 SDL_FillRect1MMX(pixels, dst->pitch, color, dstrect->w,
   776                                  dstrect->h);
   777                 break;
   778             }
   779 #endif
   780             SDL_FillRect1(pixels, dst->pitch, color, dstrect->w, dstrect->h);
   781             break;
   782         }
   783 
   784     case 2:
   785         {
   786             color |= (color << 16);
   787 #ifdef __SSE__
   788             if (SDL_HasSSE()) {
   789                 SDL_FillRect2SSE(pixels, dst->pitch, color, dstrect->w,
   790                                  dstrect->h);
   791                 break;
   792             }
   793 #endif
   794 #ifdef __MMX__
   795             if (SDL_HasMMX()) {
   796                 SDL_FillRect2MMX(pixels, dst->pitch, color, dstrect->w,
   797                                  dstrect->h);
   798                 break;
   799             }
   800 #endif
   801             SDL_FillRect2(pixels, dst->pitch, color, dstrect->w, dstrect->h);
   802             break;
   803         }
   804 
   805     case 3:
   806         /* 24-bit RGB is a slow path, at least for now. */
   807         {
   808             SDL_FillRect3(pixels, dst->pitch, color, dstrect->w, dstrect->h);
   809             break;
   810         }
   811 
   812     case 4:
   813         {
   814 #ifdef __SSE__
   815             if (SDL_HasSSE()) {
   816                 SDL_FillRect4SSE(pixels, dst->pitch, color, dstrect->w,
   817                                  dstrect->h);
   818                 break;
   819             }
   820 #endif
   821 #ifdef __MMX__
   822             if (SDL_HasMMX()) {
   823                 SDL_FillRect4MMX(pixels, dst->pitch, color, dstrect->w,
   824                                  dstrect->h);
   825                 break;
   826             }
   827 #endif
   828             SDL_FillRect4(pixels, dst->pitch, color, dstrect->w, dstrect->h);
   829             break;
   830         }
   831     }
   832 
   833     SDL_UnlockSurface(dst);
   834 
   835     /* We're done! */
   836     return (0);
   837 }
   838 
   839 /*
   840  * Lock a surface to directly access the pixels
   841  */
   842 int
   843 SDL_LockSurface(SDL_Surface * surface)
   844 {
   845     if (!surface->locked) {
   846         /* Perform the lock */
   847         if (surface->flags & SDL_RLEACCEL) {
   848             SDL_UnRLESurface(surface, 1);
   849             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   850         }
   851     }
   852 
   853     /* Increment the surface lock count, for recursive locks */
   854     ++surface->locked;
   855 
   856     /* Ready to go.. */
   857     return (0);
   858 }
   859 
   860 /*
   861  * Unlock a previously locked surface
   862  */
   863 void
   864 SDL_UnlockSurface(SDL_Surface * surface)
   865 {
   866     /* Only perform an unlock if we are locked */
   867     if (!surface->locked || (--surface->locked > 0)) {
   868         return;
   869     }
   870 
   871     /* Update RLE encoded surface with new data */
   872     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   873         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   874         SDL_RLESurface(surface);
   875     }
   876 }
   877 
   878 /* 
   879  * Convert a surface into the specified pixel format.
   880  */
   881 SDL_Surface *
   882 SDL_ConvertSurface(SDL_Surface * surface,
   883                    SDL_PixelFormat * format, Uint32 flags)
   884 {
   885     SDL_Surface *convert;
   886     Uint32 colorkey = 0;
   887     Uint8 alpha = 0;
   888     Uint32 surface_flags;
   889     SDL_Rect bounds;
   890 
   891     /* Check for empty destination palette! (results in empty image) */
   892     if (format->palette != NULL) {
   893         int i;
   894         for (i = 0; i < format->palette->ncolors; ++i) {
   895             if ((format->palette->colors[i].r != 0xFF) ||
   896                 (format->palette->colors[i].g != 0xFF) ||
   897                 (format->palette->colors[i].b != 0xFF))
   898                 break;
   899         }
   900         if (i == format->palette->ncolors) {
   901             SDL_SetError("Empty destination palette");
   902             return (NULL);
   903         }
   904     }
   905 
   906     /* Create a new surface with the desired format */
   907     convert = SDL_CreateRGBSurface(flags,
   908                                    surface->w, surface->h,
   909                                    format->BitsPerPixel, format->Rmask,
   910                                    format->Gmask, format->Bmask,
   911                                    format->Amask);
   912     if (convert == NULL) {
   913         return (NULL);
   914     }
   915 
   916     /* Copy the palette if any */
   917     if (format->palette && convert->format->palette) {
   918         SDL_memcpy(convert->format->palette->colors,
   919                    format->palette->colors,
   920                    format->palette->ncolors * sizeof(SDL_Color));
   921         convert->format->palette->ncolors = format->palette->ncolors;
   922     }
   923 
   924     /* Save the original surface color key and alpha */
   925     surface_flags = surface->flags;
   926     if ((surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
   927         /* Convert colourkeyed surfaces to RGBA if requested */
   928         if ((flags & SDL_SRCCOLORKEY) != SDL_SRCCOLORKEY && format->Amask) {
   929             surface_flags &= ~SDL_SRCCOLORKEY;
   930         } else {
   931             colorkey = surface->format->colorkey;
   932             SDL_SetColorKey(surface, 0, 0);
   933         }
   934     }
   935     if ((surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
   936         /* Copy over the alpha channel to RGBA if requested */
   937         if (format->Amask) {
   938             surface->flags &= ~SDL_SRCALPHA;
   939         } else {
   940             alpha = surface->format->alpha;
   941             SDL_SetAlpha(surface, 0, 0);
   942         }
   943     }
   944 
   945     /* Copy over the image data */
   946     bounds.x = 0;
   947     bounds.y = 0;
   948     bounds.w = surface->w;
   949     bounds.h = surface->h;
   950     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   951 
   952     /* Clean up the original surface, and update converted surface */
   953     if (convert != NULL) {
   954         SDL_SetClipRect(convert, &surface->clip_rect);
   955     }
   956     if ((surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
   957         Uint32 cflags = surface_flags & (SDL_SRCCOLORKEY | SDL_RLEACCELOK);
   958         if (convert != NULL) {
   959             Uint8 keyR, keyG, keyB;
   960 
   961             SDL_GetRGB(colorkey, surface->format, &keyR, &keyG, &keyB);
   962             SDL_SetColorKey(convert, cflags | (flags & SDL_RLEACCELOK),
   963                             SDL_MapRGB(convert->format, keyR, keyG, keyB));
   964         }
   965         SDL_SetColorKey(surface, cflags, colorkey);
   966     }
   967     if ((surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
   968         Uint32 aflags = surface_flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
   969         if (convert != NULL) {
   970             SDL_SetAlpha(convert, aflags | (flags & SDL_RLEACCELOK), alpha);
   971         }
   972         if (format->Amask) {
   973             surface->flags |= SDL_SRCALPHA;
   974         } else {
   975             SDL_SetAlpha(surface, aflags, alpha);
   976         }
   977     }
   978 
   979     /* We're ready to go! */
   980     return (convert);
   981 }
   982 
   983 /*
   984  * Free a surface created by the above function.
   985  */
   986 void
   987 SDL_FreeSurface(SDL_Surface * surface)
   988 {
   989     if (surface == NULL) {
   990         return;
   991     }
   992     if (--surface->refcount > 0) {
   993         return;
   994     }
   995     while (surface->locked > 0) {
   996         SDL_UnlockSurface(surface);
   997     }
   998     if (surface->flags & SDL_RLEACCEL) {
   999         SDL_UnRLESurface(surface, 0);
  1000     }
  1001     if (surface->format) {
  1002         SDL_SetSurfacePalette(surface, NULL);
  1003         SDL_FreeFormat(surface->format);
  1004         surface->format = NULL;
  1005     }
  1006     if (surface->map != NULL) {
  1007         SDL_FreeBlitMap(surface->map);
  1008         surface->map = NULL;
  1009     }
  1010     if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
  1011         SDL_free(surface->pixels);
  1012     }
  1013     SDL_free(surface);
  1014 #ifdef CHECK_LEAKS
  1015     --surfaces_allocated;
  1016 #endif
  1017 }
  1018 
  1019 /* vi: set ts=4 sw=4 expandtab: */