src/video/SDL_fillrect.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 24 Dec 2008 12:17:25 +0000
changeset 2913 ffae53de58f4
parent 2888 32e8bbba1e94
child 3012 7e30c2dc7783
permissions -rw-r--r--
Don't unlock a surface we didn't lock
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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_blit.h"
    26 
    27 
    28 #ifdef __SSE__
    29 /* *INDENT-OFF* */
    30 
    31 #ifdef _MSC_VER
    32 #define SSE_BEGIN \
    33     __m128 c128; \
    34     c128.m128_u32[0] = color; \
    35     c128.m128_u32[1] = color; \
    36     c128.m128_u32[2] = color; \
    37     c128.m128_u32[3] = color;
    38 #else
    39 #define SSE_BEGIN \
    40     DECLARE_ALIGNED(Uint32, cccc[4], 16); \
    41     cccc[0] = color; \
    42     cccc[1] = color; \
    43     cccc[2] = color; \
    44     cccc[3] = color; \
    45     __m128 c128 = *(__m128 *)cccc;
    46 #endif
    47 
    48 #define SSE_WORK \
    49     for (i = n / 64; i--;) { \
    50         _mm_stream_ps((float *)(p+0), c128); \
    51         _mm_stream_ps((float *)(p+16), c128); \
    52         _mm_stream_ps((float *)(p+32), c128); \
    53         _mm_stream_ps((float *)(p+48), c128); \
    54         p += 64; \
    55     }
    56 
    57 #define SSE_END
    58 
    59 #define DEFINE_SSE_FILLRECT(bpp, type) \
    60 static void \
    61 SDL_FillRect##bpp##SSE(Uint8 *pixels, int pitch, Uint32 color, int w, int h) \
    62 { \
    63     SSE_BEGIN; \
    64  \
    65     while (h--) { \
    66         int i, n = w * bpp; \
    67         Uint8 *p = pixels; \
    68  \
    69         if (n > 15) { \
    70             int adjust = 16 - ((uintptr_t)p & 15); \
    71             if (adjust < 16) { \
    72                 n -= adjust; \
    73                 adjust /= bpp; \
    74                 while (adjust--) { \
    75                     *((type *)p) = (type)color; \
    76                     p += bpp; \
    77                 } \
    78             } \
    79             SSE_WORK; \
    80         } \
    81         if (n & 63) { \
    82             int remainder = (n & 63); \
    83             remainder /= bpp; \
    84             while (remainder--) { \
    85                 *((type *)p) = (type)color; \
    86                 p += bpp; \
    87             } \
    88         } \
    89         pixels += pitch; \
    90     } \
    91  \
    92     SSE_END; \
    93 }
    94 
    95 DEFINE_SSE_FILLRECT(1, Uint8)
    96 DEFINE_SSE_FILLRECT(2, Uint16)
    97 DEFINE_SSE_FILLRECT(4, Uint32)
    98 
    99 /* *INDENT-ON* */
   100 #endif /* __SSE__ */
   101 
   102 #ifdef __MMX__
   103 /* *INDENT-OFF* */
   104 
   105 #define MMX_BEGIN \
   106     __m64 c64 = _mm_set_pi32(color, color)
   107 
   108 #define MMX_WORK \
   109     for (i = n / 64; i--;) { \
   110         _mm_stream_pi((__m64 *)(p+0), c64); \
   111         _mm_stream_pi((__m64 *)(p+8), c64); \
   112         _mm_stream_pi((__m64 *)(p+16), c64); \
   113         _mm_stream_pi((__m64 *)(p+24), c64); \
   114         _mm_stream_pi((__m64 *)(p+32), c64); \
   115         _mm_stream_pi((__m64 *)(p+40), c64); \
   116         _mm_stream_pi((__m64 *)(p+48), c64); \
   117         _mm_stream_pi((__m64 *)(p+56), c64); \
   118         p += 64; \
   119     }
   120 
   121 #define MMX_END \
   122     _mm_empty()
   123 
   124 #define DEFINE_MMX_FILLRECT(bpp, type) \
   125 static void \
   126 SDL_FillRect##bpp##MMX(Uint8 *pixels, int pitch, Uint32 color, int w, int h) \
   127 { \
   128     MMX_BEGIN; \
   129  \
   130     while (h--) { \
   131         int i, n = w * bpp; \
   132         Uint8 *p = pixels; \
   133  \
   134         if (n > 7) { \
   135             int adjust = 8 - ((uintptr_t)p & 7); \
   136             if (adjust < 8) { \
   137                 n -= adjust; \
   138                 adjust /= bpp; \
   139                 while (adjust--) { \
   140                     *((type *)p) = (type)color; \
   141                     p += bpp; \
   142                 } \
   143             } \
   144             MMX_WORK; \
   145         } \
   146         if (n & 63) { \
   147             int remainder = (n & 63); \
   148             remainder /= bpp; \
   149             while (remainder--) { \
   150                 *((type *)p) = (type)color; \
   151                 p += bpp; \
   152             } \
   153         } \
   154         pixels += pitch; \
   155     } \
   156  \
   157     MMX_END; \
   158 }
   159 
   160 DEFINE_MMX_FILLRECT(1, Uint8)
   161 DEFINE_MMX_FILLRECT(2, Uint16)
   162 DEFINE_MMX_FILLRECT(4, Uint32)
   163 
   164 /* *INDENT-ON* */
   165 #endif /* __MMX__ */
   166 
   167 static void
   168 SDL_FillRect1(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   169 {
   170     while (h--) {
   171         int n = w;
   172         Uint8 *p = pixels;
   173 
   174         if (n > 3) {
   175             switch ((uintptr_t) p & 3) {
   176             case 1:
   177                 *p++ = (Uint8) color;
   178                 --n;
   179             case 2:
   180                 *p++ = (Uint8) color;
   181                 --n;
   182             case 3:
   183                 *p++ = (Uint8) color;
   184                 --n;
   185             }
   186             SDL_memset4(p, color, (n >> 2));
   187         }
   188         if (n & 3) {
   189             p += (n & ~3);
   190             switch (n & 3) {
   191             case 3:
   192                 *p++ = (Uint8) color;
   193             case 2:
   194                 *p++ = (Uint8) color;
   195             case 1:
   196                 *p++ = (Uint8) color;
   197             }
   198         }
   199         pixels += pitch;
   200     }
   201 }
   202 
   203 static void
   204 SDL_FillRect2(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   205 {
   206     while (h--) {
   207         int n = w;
   208         Uint16 *p = (Uint16 *) pixels;
   209 
   210         if (n > 1) {
   211             if ((uintptr_t) p & 2) {
   212                 *p++ = (Uint16) color;
   213                 --n;
   214             }
   215             SDL_memset4(p, color, (n >> 1));
   216         }
   217         if (n & 1) {
   218             p[n - 1] = (Uint16) color;
   219         }
   220         pixels += pitch;
   221     }
   222 }
   223 
   224 static void
   225 SDL_FillRect3(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   226 {
   227     Uint8 r = (Uint8) ((color >> 16) & 0xFF);
   228     Uint8 g = (Uint8) ((color >> 8) & 0xFF);
   229     Uint8 b = (Uint8) (color & 0xFF);
   230 
   231     while (h--) {
   232         int n = w;
   233         Uint8 *p = pixels;
   234 
   235         while (n--) {
   236             *p++ = r;
   237             *p++ = g;
   238             *p++ = b;
   239         }
   240         pixels += pitch;
   241     }
   242 }
   243 
   244 static void
   245 SDL_FillRect4(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   246 {
   247     while (h--) {
   248         SDL_memset4(pixels, color, w);
   249         pixels += pitch;
   250     }
   251 }
   252 
   253 /* 
   254  * This function performs a fast fill of the given rectangle with 'color'
   255  */
   256 int
   257 SDL_FillRect(SDL_Surface * dst, SDL_Rect * dstrect, Uint32 color)
   258 {
   259     Uint8 *pixels;
   260 
   261     /* This function doesn't work on surfaces < 8 bpp */
   262     if (dst->format->BitsPerPixel < 8) {
   263         SDL_SetError("SDL_FillRect(): Unsupported surface format");
   264         return (-1);
   265     }
   266 
   267     /* If 'dstrect' == NULL, then fill the whole surface */
   268     if (dstrect) {
   269         /* Perform clipping */
   270         if (!SDL_IntersectRect(dstrect, &dst->clip_rect, dstrect)) {
   271             return (0);
   272         }
   273     } else {
   274         dstrect = &dst->clip_rect;
   275     }
   276 
   277     /* Perform software fill */
   278     if (!dst->pixels) {
   279         SDL_SetError("SDL_FillRect(): You must lock the surface");
   280         return (-1);
   281     }
   282 
   283     pixels =
   284         (Uint8 *) dst->pixels + dstrect->y * dst->pitch +
   285         dstrect->x * dst->format->BytesPerPixel;
   286 
   287     switch (dst->format->BytesPerPixel) {
   288     case 1:
   289         {
   290             color |= (color << 8);
   291             color |= (color << 16);
   292 #ifdef __SSE__
   293             if (SDL_HasSSE()) {
   294                 SDL_FillRect1SSE(pixels, dst->pitch, color, dstrect->w,
   295                                  dstrect->h);
   296                 break;
   297             }
   298 #endif
   299 #ifdef __MMX__
   300             if (SDL_HasMMX()) {
   301                 SDL_FillRect1MMX(pixels, dst->pitch, color, dstrect->w,
   302                                  dstrect->h);
   303                 break;
   304             }
   305 #endif
   306             SDL_FillRect1(pixels, dst->pitch, color, dstrect->w, dstrect->h);
   307             break;
   308         }
   309 
   310     case 2:
   311         {
   312             color |= (color << 16);
   313 #ifdef __SSE__
   314             if (SDL_HasSSE()) {
   315                 SDL_FillRect2SSE(pixels, dst->pitch, color, dstrect->w,
   316                                  dstrect->h);
   317                 break;
   318             }
   319 #endif
   320 #ifdef __MMX__
   321             if (SDL_HasMMX()) {
   322                 SDL_FillRect2MMX(pixels, dst->pitch, color, dstrect->w,
   323                                  dstrect->h);
   324                 break;
   325             }
   326 #endif
   327             SDL_FillRect2(pixels, dst->pitch, color, dstrect->w, dstrect->h);
   328             break;
   329         }
   330 
   331     case 3:
   332         /* 24-bit RGB is a slow path, at least for now. */
   333         {
   334             SDL_FillRect3(pixels, dst->pitch, color, dstrect->w, dstrect->h);
   335             break;
   336         }
   337 
   338     case 4:
   339         {
   340 #ifdef __SSE__
   341             if (SDL_HasSSE()) {
   342                 SDL_FillRect4SSE(pixels, dst->pitch, color, dstrect->w,
   343                                  dstrect->h);
   344                 break;
   345             }
   346 #endif
   347 #ifdef __MMX__
   348             if (SDL_HasMMX()) {
   349                 SDL_FillRect4MMX(pixels, dst->pitch, color, dstrect->w,
   350                                  dstrect->h);
   351                 break;
   352             }
   353 #endif
   354             SDL_FillRect4(pixels, dst->pitch, color, dstrect->w, dstrect->h);
   355             break;
   356         }
   357     }
   358 
   359     /* We're done! */
   360     return (0);
   361 }
   362 
   363 /* vi: set ts=4 sw=4 expandtab: */