src/video/SDL_fillrect.c
author David Ludwig <dludwig@pobox.com>
Sun, 22 Feb 2015 20:34:08 -0500
changeset 9374 b577c4753421
parent 8641 c576c104923b
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Fixed bug 2868 - SDL_FillRect can crash if surface's clip-rect is out-of-bounds

Thanks to John Skaller for the research into this, and for the fix!
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_internal.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     __m128 c128; \
    40     DECLARE_ALIGNED(Uint32, cccc[4], 16); \
    41     cccc[0] = color; \
    42     cccc[1] = color; \
    43     cccc[2] = color; \
    44     cccc[3] = color; \
    45     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     int i, n; \
    64     Uint8 *p = NULL; \
    65  \
    66     SSE_BEGIN; \
    67  \
    68     while (h--) { \
    69         n = w * bpp; \
    70         p = pixels; \
    71  \
    72         if (n > 63) { \
    73             int adjust = 16 - ((uintptr_t)p & 15); \
    74             if (adjust < 16) { \
    75                 n -= adjust; \
    76                 adjust /= bpp; \
    77                 while (adjust--) { \
    78                     *((type *)p) = (type)color; \
    79                     p += bpp; \
    80                 } \
    81             } \
    82             SSE_WORK; \
    83         } \
    84         if (n & 63) { \
    85             int remainder = (n & 63); \
    86             remainder /= bpp; \
    87             while (remainder--) { \
    88                 *((type *)p) = (type)color; \
    89                 p += bpp; \
    90             } \
    91         } \
    92         pixels += pitch; \
    93     } \
    94  \
    95     SSE_END; \
    96 }
    97 
    98 static void
    99 SDL_FillRect1SSE(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
   100 {
   101     int i, n;
   102 
   103     SSE_BEGIN;
   104     while (h--) {
   105         Uint8 *p = pixels;
   106         n = w;
   107 
   108         if (n > 63) {
   109             int adjust = 16 - ((uintptr_t)p & 15);
   110             if (adjust) {
   111                 n -= adjust;
   112                 SDL_memset(p, color, adjust);
   113                 p += adjust;
   114             }
   115             SSE_WORK;
   116         }
   117         if (n & 63) {
   118             int remainder = (n & 63);
   119             SDL_memset(p, color, remainder);
   120         }
   121         pixels += pitch;
   122     }
   123 
   124     SSE_END;
   125 }
   126 /* DEFINE_SSE_FILLRECT(1, Uint8) */
   127 DEFINE_SSE_FILLRECT(2, Uint16)
   128 DEFINE_SSE_FILLRECT(4, Uint32)
   129 
   130 /* *INDENT-ON* */
   131 #endif /* __SSE__ */
   132 
   133 static void
   134 SDL_FillRect1(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   135 {
   136     int n;
   137     Uint8 *p = NULL;
   138     
   139     while (h--) {
   140         n = w;
   141         p = pixels;
   142 
   143         if (n > 3) {
   144             switch ((uintptr_t) p & 3) {
   145             case 1:
   146                 *p++ = (Uint8) color;
   147                 --n;
   148             case 2:
   149                 *p++ = (Uint8) color;
   150                 --n;
   151             case 3:
   152                 *p++ = (Uint8) color;
   153                 --n;
   154             }
   155             SDL_memset4(p, color, (n >> 2));
   156         }
   157         if (n & 3) {
   158             p += (n & ~3);
   159             switch (n & 3) {
   160             case 3:
   161                 *p++ = (Uint8) color;
   162             case 2:
   163                 *p++ = (Uint8) color;
   164             case 1:
   165                 *p++ = (Uint8) color;
   166             }
   167         }
   168         pixels += pitch;
   169     }
   170 }
   171 
   172 static void
   173 SDL_FillRect2(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   174 {
   175     int n;
   176     Uint16 *p = NULL;
   177     
   178     while (h--) {
   179         n = w;
   180         p = (Uint16 *) pixels;
   181 
   182         if (n > 1) {
   183             if ((uintptr_t) p & 2) {
   184                 *p++ = (Uint16) color;
   185                 --n;
   186             }
   187             SDL_memset4(p, color, (n >> 1));
   188         }
   189         if (n & 1) {
   190             p[n - 1] = (Uint16) color;
   191         }
   192         pixels += pitch;
   193     }
   194 }
   195 
   196 static void
   197 SDL_FillRect3(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   198 {
   199     Uint8 r = (Uint8) ((color >> 16) & 0xFF);
   200     Uint8 g = (Uint8) ((color >> 8) & 0xFF);
   201     Uint8 b = (Uint8) (color & 0xFF);
   202     int n;
   203     Uint8 *p = NULL;
   204 
   205     while (h--) {
   206         n = w;
   207         p = pixels;
   208 
   209         while (n--) {
   210             *p++ = r;
   211             *p++ = g;
   212             *p++ = b;
   213         }
   214         pixels += pitch;
   215     }
   216 }
   217 
   218 static void
   219 SDL_FillRect4(Uint8 * pixels, int pitch, Uint32 color, int w, int h)
   220 {
   221     while (h--) {
   222         SDL_memset4(pixels, color, w);
   223         pixels += pitch;
   224     }
   225 }
   226 
   227 /* 
   228  * This function performs a fast fill of the given rectangle with 'color'
   229  */
   230 int
   231 SDL_FillRect(SDL_Surface * dst, const SDL_Rect * rect, Uint32 color)
   232 {
   233     SDL_Rect clipped;
   234     Uint8 *pixels;
   235 
   236     if (!dst) {
   237         return SDL_SetError("Passed NULL destination surface");
   238     }
   239 
   240     /* This function doesn't work on surfaces < 8 bpp */
   241     if (dst->format->BitsPerPixel < 8) {
   242         return SDL_SetError("SDL_FillRect(): Unsupported surface format");
   243     }
   244 
   245     /* If 'rect' == NULL, then fill the whole surface */
   246     if (rect) {
   247         /* Perform clipping */
   248         if (!SDL_IntersectRect(rect, &dst->clip_rect, &clipped)) {
   249             return 0;
   250         }
   251         rect = &clipped;
   252     } else {
   253         rect = &dst->clip_rect;
   254         /* Don't attempt to fill if the surface's clip_rect is empty */
   255         if (SDL_RectEmpty(rect)) {
   256             return 0;
   257         }
   258     }
   259 
   260     /* Perform software fill */
   261     if (!dst->pixels) {
   262         return SDL_SetError("SDL_FillRect(): You must lock the surface");
   263     }
   264 
   265     pixels = (Uint8 *) dst->pixels + rect->y * dst->pitch +
   266                                      rect->x * dst->format->BytesPerPixel;
   267 
   268     switch (dst->format->BytesPerPixel) {
   269     case 1:
   270         {
   271             color |= (color << 8);
   272             color |= (color << 16);
   273 #ifdef __SSE__
   274             if (SDL_HasSSE()) {
   275                 SDL_FillRect1SSE(pixels, dst->pitch, color, rect->w, rect->h);
   276                 break;
   277             }
   278 #endif
   279             SDL_FillRect1(pixels, dst->pitch, color, rect->w, rect->h);
   280             break;
   281         }
   282 
   283     case 2:
   284         {
   285             color |= (color << 16);
   286 #ifdef __SSE__
   287             if (SDL_HasSSE()) {
   288                 SDL_FillRect2SSE(pixels, dst->pitch, color, rect->w, rect->h);
   289                 break;
   290             }
   291 #endif
   292             SDL_FillRect2(pixels, dst->pitch, color, rect->w, rect->h);
   293             break;
   294         }
   295 
   296     case 3:
   297         /* 24-bit RGB is a slow path, at least for now. */
   298         {
   299             SDL_FillRect3(pixels, dst->pitch, color, rect->w, rect->h);
   300             break;
   301         }
   302 
   303     case 4:
   304         {
   305 #ifdef __SSE__
   306             if (SDL_HasSSE()) {
   307                 SDL_FillRect4SSE(pixels, dst->pitch, color, rect->w, rect->h);
   308                 break;
   309             }
   310 #endif
   311             SDL_FillRect4(pixels, dst->pitch, color, rect->w, rect->h);
   312             break;
   313         }
   314     }
   315 
   316     /* We're done! */
   317     return 0;
   318 }
   319 
   320 int
   321 SDL_FillRects(SDL_Surface * dst, const SDL_Rect * rects, int count,
   322               Uint32 color)
   323 {
   324     int i;
   325     int status = 0;
   326 
   327     if (!rects) {
   328         return SDL_SetError("SDL_FillRects() passed NULL rects");
   329     }
   330 
   331     for (i = 0; i < count; ++i) {
   332         status += SDL_FillRect(dst, &rects[i], color);
   333     }
   334     return status;
   335 }
   336 
   337 /* vi: set ts=4 sw=4 expandtab: */