src/render/software/SDL_render_sw.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 07 Feb 2012 19:34:24 -0500
changeset 6283 03a7ceb3487b
parent 6247 b6212690f78d
child 6320 6077a1310907
permissions -rwxr-xr-x
Fixed bug 1412 - Patch - Software renderer crash

Dimitris Zenios Date: 2012-02-06 15:12:37 GMT

Hi gus there is a bug when using software renderer and the window
surface gets destroyed (Fullscreen and back).The solution is easy
     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 #if !SDL_RENDER_DISABLED
    24 
    25 #include "../SDL_sysrender.h"
    26 #include "SDL_render_sw_c.h"
    27 
    28 #include "SDL_draw.h"
    29 #include "SDL_blendfillrect.h"
    30 #include "SDL_blendline.h"
    31 #include "SDL_blendpoint.h"
    32 #include "SDL_drawline.h"
    33 #include "SDL_drawpoint.h"
    34 
    35 
    36 /* SDL surface based renderer implementation */
    37 
    38 static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags);
    39 static void SW_WindowEvent(SDL_Renderer * renderer,
    40                            const SDL_WindowEvent *event);
    41 static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    42 static int SW_SetTextureColorMod(SDL_Renderer * renderer,
    43                                  SDL_Texture * texture);
    44 static int SW_SetTextureAlphaMod(SDL_Renderer * renderer,
    45                                  SDL_Texture * texture);
    46 static int SW_SetTextureBlendMode(SDL_Renderer * renderer,
    47                                   SDL_Texture * texture);
    48 static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    49                             const SDL_Rect * rect, const void *pixels,
    50                             int pitch);
    51 static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    52                           const SDL_Rect * rect, void **pixels, int *pitch);
    53 static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    54 static int SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
    55 static int SW_UpdateViewport(SDL_Renderer * renderer);
    56 static int SW_RenderClear(SDL_Renderer * renderer);
    57 static int SW_RenderDrawPoints(SDL_Renderer * renderer,
    58                                const SDL_Point * points, int count);
    59 static int SW_RenderDrawLines(SDL_Renderer * renderer,
    60                               const SDL_Point * points, int count);
    61 static int SW_RenderFillRects(SDL_Renderer * renderer,
    62                               const SDL_Rect * rects, int count);
    63 static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    64                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    65 static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    66                                Uint32 format, void * pixels, int pitch);
    67 static void SW_RenderPresent(SDL_Renderer * renderer);
    68 static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    69 static void SW_DestroyRenderer(SDL_Renderer * renderer);
    70 
    71 
    72 SDL_RenderDriver SW_RenderDriver = {
    73     SW_CreateRenderer,
    74     {
    75      "software",
    76      SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE,
    77      8,
    78      {
    79       SDL_PIXELFORMAT_RGB555,
    80       SDL_PIXELFORMAT_RGB565,
    81       SDL_PIXELFORMAT_RGB888,
    82       SDL_PIXELFORMAT_BGR888,
    83       SDL_PIXELFORMAT_ARGB8888,
    84       SDL_PIXELFORMAT_RGBA8888,
    85       SDL_PIXELFORMAT_ABGR8888,
    86       SDL_PIXELFORMAT_BGRA8888
    87      },
    88      0,
    89      0}
    90 };
    91 
    92 typedef struct
    93 {
    94     SDL_Surface *surface;
    95     SDL_Surface *window;
    96 } SW_RenderData;
    97 
    98 
    99 static SDL_Surface *
   100 SW_ActivateRenderer(SDL_Renderer * renderer)
   101 {
   102     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   103 
   104     if (!data->surface) {
   105         data->surface = data->window;
   106     }
   107     if (!data->surface) {
   108         data->surface = data->window = SDL_GetWindowSurface(renderer->window);
   109 
   110         SW_UpdateViewport(renderer);
   111     }
   112     return data->surface;
   113 }
   114 
   115 SDL_Renderer *
   116 SW_CreateRendererForSurface(SDL_Surface * surface)
   117 {
   118     SDL_Renderer *renderer;
   119     SW_RenderData *data;
   120 
   121     if (!surface) {
   122         SDL_SetError("Can't create renderer for NULL surface");
   123         return NULL;
   124     }
   125 
   126     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   127     if (!renderer) {
   128         SDL_OutOfMemory();
   129         return NULL;
   130     }
   131 
   132     data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
   133     if (!data) {
   134         SW_DestroyRenderer(renderer);
   135         SDL_OutOfMemory();
   136         return NULL;
   137     }
   138     data->surface = surface;
   139 
   140     renderer->WindowEvent = SW_WindowEvent;
   141     renderer->CreateTexture = SW_CreateTexture;
   142     renderer->SetTextureColorMod = SW_SetTextureColorMod;
   143     renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
   144     renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
   145     renderer->UpdateTexture = SW_UpdateTexture;
   146     renderer->LockTexture = SW_LockTexture;
   147     renderer->UnlockTexture = SW_UnlockTexture;
   148     renderer->SetRenderTarget = SW_SetRenderTarget;
   149     renderer->UpdateViewport = SW_UpdateViewport;
   150     renderer->RenderClear = SW_RenderClear;
   151     renderer->RenderDrawPoints = SW_RenderDrawPoints;
   152     renderer->RenderDrawLines = SW_RenderDrawLines;
   153     renderer->RenderFillRects = SW_RenderFillRects;
   154     renderer->RenderCopy = SW_RenderCopy;
   155     renderer->RenderReadPixels = SW_RenderReadPixels;
   156     renderer->RenderPresent = SW_RenderPresent;
   157     renderer->DestroyTexture = SW_DestroyTexture;
   158     renderer->DestroyRenderer = SW_DestroyRenderer;
   159     renderer->info = SW_RenderDriver.info;
   160     renderer->driverdata = data;
   161 
   162     SW_ActivateRenderer(renderer);
   163 
   164     return renderer;
   165 }
   166 
   167 SDL_Renderer *
   168 SW_CreateRenderer(SDL_Window * window, Uint32 flags)
   169 {
   170     SDL_Surface *surface;
   171 
   172     surface = SDL_GetWindowSurface(window);
   173     if (!surface) {
   174         return NULL;
   175     }
   176     return SW_CreateRendererForSurface(surface);
   177 }
   178 
   179 static void
   180 SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   181 {
   182     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   183 
   184     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   185         data->surface = NULL;
   186         data->window = NULL;
   187     }
   188 }
   189 
   190 static int
   191 SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   192 {
   193     int bpp;
   194     Uint32 Rmask, Gmask, Bmask, Amask;
   195 
   196     if (!SDL_PixelFormatEnumToMasks
   197         (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   198         SDL_SetError("Unknown texture format");
   199         return -1;
   200     }
   201 
   202     texture->driverdata =
   203         SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
   204                              Bmask, Amask);
   205     SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
   206                            texture->b);
   207     SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
   208     SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
   209 
   210     if (texture->access == SDL_TEXTUREACCESS_STATIC) {
   211         SDL_SetSurfaceRLE(texture->driverdata, 1);
   212     }
   213 
   214     if (!texture->driverdata) {
   215         return -1;
   216     }
   217     return 0;
   218 }
   219 
   220 static int
   221 SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   222 {
   223     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   224     return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
   225                                   texture->b);
   226 }
   227 
   228 static int
   229 SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   230 {
   231     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   232     return SDL_SetSurfaceAlphaMod(surface, texture->a);
   233 }
   234 
   235 static int
   236 SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   237 {
   238     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   239     return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
   240 }
   241 
   242 static int
   243 SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   244                  const SDL_Rect * rect, const void *pixels, int pitch)
   245 {
   246     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   247     Uint8 *src, *dst;
   248     int row;
   249     size_t length;
   250 
   251     if(SDL_MUSTLOCK(surface))
   252         SDL_LockSurface(surface);
   253     src = (Uint8 *) pixels;
   254     dst = (Uint8 *) surface->pixels +
   255                         rect->y * surface->pitch +
   256                         rect->x * surface->format->BytesPerPixel;
   257     length = rect->w * surface->format->BytesPerPixel;
   258     for (row = 0; row < rect->h; ++row) {
   259         SDL_memcpy(dst, src, length);
   260         src += pitch;
   261         dst += surface->pitch;
   262     }
   263     if(SDL_MUSTLOCK(surface))
   264         SDL_UnlockSurface(surface);
   265     return 0;
   266 }
   267 
   268 static int
   269 SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   270                const SDL_Rect * rect, void **pixels, int *pitch)
   271 {
   272     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   273 
   274     *pixels =
   275         (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
   276                   rect->x * surface->format->BytesPerPixel);
   277     *pitch = surface->pitch;
   278     return 0;
   279 }
   280 
   281 static void
   282 SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   283 {
   284 }
   285 
   286 static int
   287 SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   288 {
   289     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   290 
   291     if (texture ) {
   292         data->surface = (SDL_Surface *) texture->driverdata;
   293     } else {
   294         data->surface = data->window;
   295     }
   296     return 0;
   297 }
   298 
   299 static int
   300 SW_UpdateViewport(SDL_Renderer * renderer)
   301 {
   302     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   303     SDL_Surface *surface = data->surface;
   304 
   305     if (!surface) {
   306         /* We'll update the viewport after we recreate the surface */
   307         return 0;
   308     }
   309 
   310     if (!renderer->viewport.w && !renderer->viewport.h) {
   311         /* There may be no window, so update the viewport directly */
   312         renderer->viewport.w = surface->w;
   313         renderer->viewport.h = surface->h;
   314     }
   315     SDL_SetClipRect(data->surface, &renderer->viewport);
   316     return 0;
   317 }
   318 
   319 static int
   320 SW_RenderClear(SDL_Renderer * renderer)
   321 {
   322     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   323     Uint32 color;
   324     SDL_Rect clip_rect;
   325 
   326     if (!surface) {
   327         return -1;
   328     }
   329 
   330     color = SDL_MapRGBA(surface->format,
   331                         renderer->r, renderer->g, renderer->b, renderer->a);
   332 
   333     /* By definition the clear ignores the clip rect */
   334     clip_rect = surface->clip_rect;
   335     SDL_SetClipRect(surface, NULL);
   336     SDL_FillRect(surface, NULL, color);
   337     SDL_SetClipRect(surface, &clip_rect);
   338     return 0;
   339 }
   340 
   341 static int
   342 SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   343                     int count)
   344 {
   345     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   346     SDL_Point *temp = NULL;
   347     int status;
   348 
   349     if (!surface) {
   350         return -1;
   351     }
   352 
   353     if (renderer->viewport.x || renderer->viewport.y) {
   354         int i;
   355         int x = renderer->viewport.x;
   356         int y = renderer->viewport.y;
   357 
   358         temp = SDL_stack_alloc(SDL_Point, count);
   359         for (i = 0; i < count; ++i) {
   360             temp[i].x = x + points[i].x;
   361             temp[i].y = y + points[i].x;
   362         }
   363         points = temp;
   364     }
   365 
   366     /* Draw the points! */
   367     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   368         Uint32 color = SDL_MapRGBA(surface->format,
   369                                    renderer->r, renderer->g, renderer->b,
   370                                    renderer->a);
   371 
   372         status = SDL_DrawPoints(surface, points, count, color);
   373     } else {
   374         status = SDL_BlendPoints(surface, points, count,
   375                                 renderer->blendMode,
   376                                 renderer->r, renderer->g, renderer->b,
   377                                 renderer->a);
   378     }
   379 
   380     if (temp) {
   381         SDL_stack_free(temp);
   382     }
   383     return status;
   384 }
   385 
   386 static int
   387 SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   388                    int count)
   389 {
   390     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   391     SDL_Point *temp = NULL;
   392     int status;
   393 
   394     if (!surface) {
   395         return -1;
   396     }
   397 
   398     if (renderer->viewport.x || renderer->viewport.y) {
   399         int i;
   400         int x = renderer->viewport.x;
   401         int y = renderer->viewport.y;
   402 
   403         temp = SDL_stack_alloc(SDL_Point, count);
   404         for (i = 0; i < count; ++i) {
   405             temp[i].x = x + points[i].x;
   406             temp[i].y = y + points[i].y;
   407         }
   408         points = temp;
   409     }
   410 
   411     /* Draw the lines! */
   412     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   413         Uint32 color = SDL_MapRGBA(surface->format,
   414                                    renderer->r, renderer->g, renderer->b,
   415                                    renderer->a);
   416 
   417         status = SDL_DrawLines(surface, points, count, color);
   418     } else {
   419         status = SDL_BlendLines(surface, points, count,
   420                                 renderer->blendMode,
   421                                 renderer->r, renderer->g, renderer->b,
   422                                 renderer->a);
   423     }
   424 
   425     if (temp) {
   426         SDL_stack_free(temp);
   427     }
   428     return status;
   429 }
   430 
   431 static int
   432 SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count)
   433 {
   434     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   435     SDL_Rect *temp = NULL;
   436     int status;
   437 
   438     if (!surface) {
   439         return -1;
   440     }
   441 
   442     if (renderer->viewport.x || renderer->viewport.y) {
   443         int i;
   444         int x = renderer->viewport.x;
   445         int y = renderer->viewport.y;
   446 
   447         temp = SDL_stack_alloc(SDL_Rect, count);
   448         for (i = 0; i < count; ++i) {
   449             temp[i].x = x + rects[i].x;
   450             temp[i].y = y + rects[i].y;
   451             temp[i].w = rects[i].w;
   452             temp[i].h = rects[i].h;
   453         }
   454         rects = temp;
   455     }
   456 
   457     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   458         Uint32 color = SDL_MapRGBA(surface->format,
   459                                    renderer->r, renderer->g, renderer->b,
   460                                    renderer->a);
   461         status = SDL_FillRects(surface, rects, count, color);
   462     } else {
   463         status = SDL_BlendFillRects(surface, rects, count,
   464                                     renderer->blendMode,
   465                                     renderer->r, renderer->g, renderer->b,
   466                                     renderer->a);
   467     }
   468 
   469     if (temp) {
   470         SDL_stack_free(temp);
   471     }
   472     return status;
   473 }
   474 
   475 static int
   476 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   477               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   478 {
   479     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   480     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   481     SDL_Rect final_rect = *dstrect;
   482 
   483     if (!surface) {
   484         return -1;
   485     }
   486 
   487     if (renderer->viewport.x || renderer->viewport.y) {
   488         final_rect.x += renderer->viewport.x;
   489         final_rect.y += renderer->viewport.y;
   490     }
   491     if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {
   492         return SDL_BlitSurface(src, srcrect, surface, &final_rect);
   493     } else {
   494         return SDL_BlitScaled(src, srcrect, surface, &final_rect);
   495     }
   496 }
   497 
   498 static int
   499 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   500                     Uint32 format, void * pixels, int pitch)
   501 {
   502     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   503     Uint32 src_format;
   504     void *src_pixels;
   505     SDL_Rect final_rect;
   506 
   507     if (!surface) {
   508         return -1;
   509     }
   510 
   511     if (renderer->viewport.x || renderer->viewport.y) {
   512         final_rect.x = renderer->viewport.x + rect->x;
   513         final_rect.y = renderer->viewport.y + rect->y;
   514         final_rect.w = rect->w;
   515         final_rect.h = rect->h;
   516         rect = &final_rect;
   517     }
   518 
   519     if (rect->x < 0 || rect->x+rect->w > surface->w ||
   520         rect->y < 0 || rect->y+rect->h > surface->h) {
   521         SDL_SetError("Tried to read outside of surface bounds");
   522         return -1;
   523     }
   524 
   525     src_format = surface->format->format;
   526     src_pixels = (void*)((Uint8 *) surface->pixels +
   527                     rect->y * surface->pitch +
   528                     rect->x * surface->format->BytesPerPixel);
   529 
   530     return SDL_ConvertPixels(rect->w, rect->h,
   531                              src_format, src_pixels, surface->pitch,
   532                              format, pixels, pitch);
   533 }
   534 
   535 static void
   536 SW_RenderPresent(SDL_Renderer * renderer)
   537 {
   538     SDL_Window *window = renderer->window;
   539 
   540     if (window) {
   541         SDL_UpdateWindowSurface(window);
   542     }
   543 }
   544 
   545 static void
   546 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   547 {
   548     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   549 
   550     SDL_FreeSurface(surface);
   551 }
   552 
   553 static void
   554 SW_DestroyRenderer(SDL_Renderer * renderer)
   555 {
   556     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   557 
   558     if (data) {
   559         SDL_free(data);
   560     }
   561     SDL_free(renderer);
   562 }
   563 
   564 #endif /* !SDL_RENDER_DISABLED */
   565 
   566 /* vi: set ts=4 sw=4 expandtab: */