src/video/SDL_fillrect.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 06 Sep 2012 21:34:52 -0700
changeset 6417 e54cc2d4e89a
parent 5535 96594ac5fd1a
child 6885 700f1b25f77f
permissions -rwxr-xr-x
Fixed error message when destroying a software renderer, thanks to wahono for the patch.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #include "SDL_video.h"
    24 #include "SDL_blit.h"
    25 
    26 
    27 #ifdef __SSE__
    28 /* *INDENT-OFF* */
    29 
    30 #ifdef _MSC_VER
    31 #define SSE_BEGIN \
    32     __m128 c128; \
    33     c128.m128_u32[0] = color; \
    34     c128.m128_u32[1] = color; \
    35     c128.m128_u32[2] = color; \
    36     c128.m128_u32[3] = color;
    37 #else
    38 #define SSE_BEGIN \
    39     DECLARE_ALIGNED(Uint32, cccc[4], 16); \
    40     cccc[0] = color; \
    41     cccc[1] = color; \
    42     cccc[2] = color; \
    43     cccc[3] = color; \
    44     __m128 c128 = *(__m128 *)cccc;
    45 #endif
    46 
    47 #define SSE_WORK \
    48     for (i = n / 64; i--;) { \
    49         _mm_stream_ps((float *)(p+0), c128); \
    50         _mm_stream_ps((float *)(p+16), c128); \
    51         _mm_stream_ps((float *)(p+32), c128); \
    52         _mm_stream_ps((float *)(p+48), c128); \
    53         p += 64; \
    54     }
    55 
    56 #define SSE_END
    57 
    58 #define DEFINE_SSE_FILLRECT(bpp, type) \
    59 static void \
    60 SDL_FillRect##bpp##SSE(Uint8 *pixels, int pitch, Uint32 color, int w, int h) \
    61 { \
    62     SSE_BEGIN; \
    63  \
    64     while (h--) { \
    65         int i, n = w * bpp; \
    66         Uint8 *p = pixels; \
    67  \
    68         if (n > 63) { \
    69             int adjust = 16 - ((uintptr_t)p & 15); \
    70             if (adjust < 16) { \
    71                 n -= adjust; \
    72                 adjust /= bpp; \
    73                 while (adjust--) { \
    74                     *((type *)p) = (type)color; \
    75                     p += bpp; \
    76                 } \
    77             } \
    78             SSE_WORK; \
    79         } \
    80         if (n & 63) { \
    81             int remainder = (n & 63); \
    82             remainder /= bpp; \
    83             while (remainder--) { \
    84                 *((type *)p) = (type)color; \
    85                 p += bpp; \
    86             } \
    87         } \
    88         pixels += pitch; \
    89     } \
    90  \
    91     SSE_END; \
    92 }
    93 
    94 static void
    95 SDL_FillRect1SSE(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
    96 {
    97     SSE_BEGIN;
    98 
    99     while (h--) {
   100         int i, n = w;
   101         Uint8 *p = pixels;
   102 
   103         if (n > 63) {
   104             int adjust = 16 - ((uintptr_t)p & 15);
   105             if (adjust) {
   106                 n -= adjust;
   107                 SDL_memset(p, color, adjust);
   108                 p += adjust;
   109             }
   110             SSE_WORK;
   111         }
   112         if (n & 63) {
   113             int remainder = (n & 63);
   114             SDL_memset(p, color, remainder);
   115             p += remainder;
   116         }
   117         pixels += pitch;
   118     }
   119 
   120     SSE_END;
   121 }
   122 /*DEFINE_SSE_FILLRECT(1, Uint8)*/
   123 DEFINE_SSE_FILLRECT(2, Uint16)
   124 DEFINE_SSE_FILLRECT(4, Uint32)
   125 
   126 /* *INDENT-ON* */
   127 #endif /* __SSE__ */
   128 
   129 #ifdef __MMX__
   130 /* *INDENT-OFF* */
   131 
   132 #define MMX_BEGIN \
   133     __m64 c64 = _mm_set_pi32(color, color)
   134 
   135 #define MMX_WORK \
   136     for (i = n / 64; i--;) { \
   137         _mm_stream_pi((__m64 *)(p+0), c64); \
   138         _mm_stream_pi((__m64 *)(p+8), c64); \
   139         _mm_stream_pi((__m64 *)(p+16), c64); \
   140         _mm_stream_pi((__m64 *)(p+24), c64); \
   141         _mm_stream_pi((__m64 *)(p+32), c64); \
   142         _mm_stream_pi((__m64 *)(p+40), c64); \
   143         _mm_stream_pi((__m64 *)(p+48), c64); \
   144         _mm_stream_pi((__m64 *)(p+56), c64); \
   145         p += 64; \
   146     }
   147 
   148 #define MMX_END \
   149     _mm_empty()
   150 
   151 #define DEFINE_MMX_FILLRECT(bpp, type) \
   152 static void \
   153 SDL_FillRect##bpp##MMX(Uint8 *pixels, int pitch, Uint32 color, int w, int h) \
   154 { \
   155     MMX_BEGIN; \
   156  \
   157     while (h--) { \
   158         int i, n = w * bpp; \
   159         Uint8 *p = pixels; \
   160  \
   161         if (n > 63) { \
   162             int adjust = 8 - ((uintptr_t)p & 7); \
   163             if (adjust < 8) { \
   164                 n -= adjust; \
   165                 adjust /= bpp; \
   166                 while (adjust--) { \
   167                     *((type *)p) = (type)color; \
   168                     p += bpp; \
   169                 } \
   170             } \
   171             MMX_WORK; \
   172         } \
   173         if (n & 63) { \
   174             int remainder = (n & 63); \
   175             remainder /= bpp; \
   176             while (remainder--) { \
   177                 *((type *)p) = (type)color; \
   178                 p += bpp; \
   179             } \
   180         } \
   181         pixels += pitch; \
   182     } \
   183  \
   184     MMX_END; \
   185 }
   186 
   187 static void
   188 SDL_FillRect1MMX(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
   189 {
   190     MMX_BEGIN;
   191 
   192     while (h--) {
   193         int i, n = w;
   194         Uint8 *p = pixels;
   195 
   196         if (n > 63) {
   197             int adjust = 8 - ((uintptr_t)p & 7);
   198             if (adjust) {
   199                 n -= adjust;
   200                 SDL_memset(p, color, adjust);
   201                 p += adjust;
   202             }
   203             MMX_WORK;
   204         }
   205         if (n & 63) {
   206             int remainder = (n & 63);
   207             SDL_memset(p, color, remainder);
   208             p += remainder;
   209         }
   210         pixels += pitch;
   211     }
   212 
   213     MMX_END;
   214 }
   215 /*DEFINE_MMX_FILLRECT(1, Uint8)*/
   216 DEFINE_MMX_FILLRECT(2, Uint16)
   217 DEFINE_MMX_FILLRECT(4, Uint32)
   218 
   219 /* *INDENT-ON* */
   220 #endif /* __MMX__ */
   221 
   222 static void
   223 SDL_FillRect1(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   224 {
   225     while (h--) {
   226         int n = w;
   227         Uint8 *p = pixels;
   228 
   229         if (n > 3) {
   230             switch ((uintptr_t) p & 3) {
   231             case 1:
   232                 *p++ = (Uint8) color;
   233                 --n;
   234             case 2:
   235                 *p++ = (Uint8) color;
   236                 --n;
   237             case 3:
   238                 *p++ = (Uint8) color;
   239                 --n;
   240             }
   241             SDL_memset4(p, color, (n >> 2));
   242         }
   243         if (n & 3) {
   244             p += (n & ~3);
   245             switch (n & 3) {
   246             case 3:
   247                 *p++ = (Uint8) color;
   248             case 2:
   249                 *p++ = (Uint8) color;
   250             case 1:
   251                 *p++ = (Uint8) color;
   252             }
   253         }
   254         pixels += pitch;
   255     }
   256 }
   257 
   258 static void
   259 SDL_FillRect2(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   260 {
   261     while (h--) {
   262         int n = w;
   263         Uint16 *p = (Uint16 *) pixels;
   264 
   265         if (n > 1) {
   266             if ((uintptr_t) p & 2) {
   267                 *p++ = (Uint16) color;
   268                 --n;
   269             }
   270             SDL_memset4(p, color, (n >> 1));
   271         }
   272         if (n & 1) {
   273             p[n - 1] = (Uint16) color;
   274         }
   275         pixels += pitch;
   276     }
   277 }
   278 
   279 static void
   280 SDL_FillRect3(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   281 {
   282     Uint8 r = (Uint8) ((color >> 16) & 0xFF);
   283     Uint8 g = (Uint8) ((color >> 8) & 0xFF);
   284     Uint8 b = (Uint8) (color & 0xFF);
   285 
   286     while (h--) {
   287         int n = w;
   288         Uint8 *p = pixels;
   289 
   290         while (n--) {
   291             *p++ = r;
   292             *p++ = g;
   293             *p++ = b;
   294         }
   295         pixels += pitch;
   296     }
   297 }
   298 
   299 static void
   300 SDL_FillRect4(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   301 {
   302     while (h--) {
   303         SDL_memset4(pixels, color, w);
   304         pixels += pitch;
   305     }
   306 }
   307 
   308 /* 
   309  * This function performs a fast fill of the given rectangle with 'color'
   310  */
   311 int
   312 SDL_FillRect(SDL_Surface * dst, const SDL_Rect * rect, Uint32 color)
   313 {
   314     SDL_Rect clipped;
   315     Uint8 *pixels;
   316 
   317     if (!dst) {
   318         SDL_SetError("Passed NULL destination surface");
   319         return -1;
   320     }
   321 
   322     /* This function doesn't work on surfaces < 8 bpp */
   323     if (dst->format->BitsPerPixel < 8) {
   324         SDL_SetError("SDL_FillRect(): Unsupported surface format");
   325         return -1;
   326     }
   327 
   328     /* If 'rect' == NULL, then fill the whole surface */
   329     if (rect) {
   330         /* Perform clipping */
   331         if (!SDL_IntersectRect(rect, &dst->clip_rect, &clipped)) {
   332             return 0;
   333         }
   334         rect = &clipped;
   335     } else {
   336         rect = &dst->clip_rect;
   337     }
   338 
   339     /* Perform software fill */
   340     if (!dst->pixels) {
   341         SDL_SetError("SDL_FillRect(): You must lock the surface");
   342         return (-1);
   343     }
   344 
   345     pixels = (Uint8 *) dst->pixels + rect->y * dst->pitch +
   346                                      rect->x * dst->format->BytesPerPixel;
   347 
   348     switch (dst->format->BytesPerPixel) {
   349     case 1:
   350         {
   351             color |= (color << 8);
   352             color |= (color << 16);
   353 #ifdef __SSE__
   354             if (SDL_HasSSE()) {
   355                 SDL_FillRect1SSE(pixels, dst->pitch, color, rect->w, rect->h);
   356                 break;
   357             }
   358 #endif
   359 #ifdef __MMX__
   360             if (SDL_HasMMX()) {
   361                 SDL_FillRect1MMX(pixels, dst->pitch, color, rect->w, rect->h);
   362                 break;
   363             }
   364 #endif
   365             SDL_FillRect1(pixels, dst->pitch, color, rect->w, rect->h);
   366             break;
   367         }
   368 
   369     case 2:
   370         {
   371             color |= (color << 16);
   372 #ifdef __SSE__
   373             if (SDL_HasSSE()) {
   374                 SDL_FillRect2SSE(pixels, dst->pitch, color, rect->w, rect->h);
   375                 break;
   376             }
   377 #endif
   378 #ifdef __MMX__
   379             if (SDL_HasMMX()) {
   380                 SDL_FillRect2MMX(pixels, dst->pitch, color, rect->w, rect->h);
   381                 break;
   382             }
   383 #endif
   384             SDL_FillRect2(pixels, dst->pitch, color, rect->w, rect->h);
   385             break;
   386         }
   387 
   388     case 3:
   389         /* 24-bit RGB is a slow path, at least for now. */
   390         {
   391             SDL_FillRect3(pixels, dst->pitch, color, rect->w, rect->h);
   392             break;
   393         }
   394 
   395     case 4:
   396         {
   397 #ifdef __SSE__
   398             if (SDL_HasSSE()) {
   399                 SDL_FillRect4SSE(pixels, dst->pitch, color, rect->w, rect->h);
   400                 break;
   401             }
   402 #endif
   403 #ifdef __MMX__
   404             if (SDL_HasMMX()) {
   405                 SDL_FillRect4MMX(pixels, dst->pitch, color, rect->w, rect->h);
   406                 break;
   407             }
   408 #endif
   409             SDL_FillRect4(pixels, dst->pitch, color, rect->w, rect->h);
   410             break;
   411         }
   412     }
   413 
   414     /* We're done! */
   415     return 0;
   416 }
   417 
   418 int
   419 SDL_FillRects(SDL_Surface * dst, const SDL_Rect * rects, int count,
   420               Uint32 color)
   421 {
   422     int i;
   423     int status = 0;
   424 
   425     if (!rects) {
   426         SDL_SetError("SDL_FillRects() passed NULL rects");
   427         return -1;
   428     }
   429 
   430     for (i = 0; i < count; ++i) {
   431         status += SDL_FillRect(dst, &rects[i], color);
   432     }
   433     return status;
   434 }
   435 
   436 /* vi: set ts=4 sw=4 expandtab: */