src/video/SDL_renderer_sw.c
author Sam Lantinga
Sat, 19 Sep 2009 13:29:40 +0000
changeset 3280 00cace2d9080
parent 3053 aa34d1180d30
child 3427 36cf454ba065
permissions -rw-r--r--
Merged a cleaned up version of Jiang's code changes from Google Summer of Code 2009
     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_sysvideo.h"
    26 #include "SDL_pixels_c.h"
    27 #include "SDL_rect_c.h"
    28 #include "SDL_yuv_sw_c.h"
    29 
    30 
    31 /* SDL surface based renderer implementation */
    32 
    33 static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags);
    34 static int SW_ActivateRenderer(SDL_Renderer * renderer);
    35 static int SW_DisplayModeChanged(SDL_Renderer * renderer);
    36 static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    37 static int SW_QueryTexturePixels(SDL_Renderer * renderer,
    38                                  SDL_Texture * texture, void **pixels,
    39                                  int *pitch);
    40 static int SW_SetTexturePalette(SDL_Renderer * renderer,
    41                                 SDL_Texture * texture,
    42                                 const SDL_Color * colors, int firstcolor,
    43                                 int ncolors);
    44 static int SW_GetTexturePalette(SDL_Renderer * renderer,
    45                                 SDL_Texture * texture, SDL_Color * colors,
    46                                 int firstcolor, int ncolors);
    47 static int SW_SetTextureColorMod(SDL_Renderer * renderer,
    48                                  SDL_Texture * texture);
    49 static int SW_SetTextureAlphaMod(SDL_Renderer * renderer,
    50                                  SDL_Texture * texture);
    51 static int SW_SetTextureBlendMode(SDL_Renderer * renderer,
    52                                   SDL_Texture * texture);
    53 static int SW_SetTextureScaleMode(SDL_Renderer * renderer,
    54                                   SDL_Texture * texture);
    55 static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    56                             const SDL_Rect * rect, const void *pixels,
    57                             int pitch);
    58 static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    59                           const SDL_Rect * rect, int markDirty, void **pixels,
    60                           int *pitch);
    61 static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    62 static int SW_RenderPoint(SDL_Renderer * renderer, int x, int y);
    63 static int SW_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2,
    64                          int y2);
    65 static int SW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect);
    66 static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    67                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    68 static void SW_RenderPresent(SDL_Renderer * renderer);
    69 static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    70 static void SW_DestroyRenderer(SDL_Renderer * renderer);
    71 
    72 
    73 SDL_RenderDriver SW_RenderDriver = {
    74     SW_CreateRenderer,
    75     {
    76      "software",
    77      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
    78       SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
    79       SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_PRESENTVSYNC),
    80      (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
    81       SDL_TEXTUREMODULATE_ALPHA),
    82      (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK |
    83       SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD),
    84      (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST),
    85      14,
    86      {
    87       SDL_PIXELFORMAT_INDEX8,
    88       SDL_PIXELFORMAT_RGB555,
    89       SDL_PIXELFORMAT_RGB565,
    90       SDL_PIXELFORMAT_RGB888,
    91       SDL_PIXELFORMAT_BGR888,
    92       SDL_PIXELFORMAT_ARGB8888,
    93       SDL_PIXELFORMAT_RGBA8888,
    94       SDL_PIXELFORMAT_ABGR8888,
    95       SDL_PIXELFORMAT_BGRA8888,
    96       SDL_PIXELFORMAT_YV12,
    97       SDL_PIXELFORMAT_IYUV,
    98       SDL_PIXELFORMAT_YUY2,
    99       SDL_PIXELFORMAT_UYVY,
   100       SDL_PIXELFORMAT_YVYU},
   101      0,
   102      0}
   103 };
   104 
   105 typedef struct
   106 {
   107     Uint32 format;
   108     SDL_bool updateSize;
   109     int current_texture;
   110     SDL_Texture *texture[3];
   111     SDL_Surface surface;
   112     SDL_Renderer *renderer;
   113     SDL_DirtyRectList dirty;
   114 } SW_RenderData;
   115 
   116 static SDL_Texture *
   117 CreateTexture(SDL_Renderer * renderer, Uint32 format, int w, int h)
   118 {
   119     SDL_Texture *texture;
   120 
   121     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
   122     if (!texture) {
   123         SDL_OutOfMemory();
   124         return NULL;
   125     }
   126 
   127     texture->format = format;
   128     texture->access = SDL_TEXTUREACCESS_STREAMING;
   129     texture->w = w;
   130     texture->h = h;
   131     texture->renderer = renderer;
   132 
   133     if (renderer->CreateTexture(renderer, texture) < 0) {
   134         SDL_free(texture);
   135         return NULL;
   136     }
   137     return texture;
   138 }
   139 
   140 static void
   141 DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   142 {
   143     renderer->DestroyTexture(renderer, texture);
   144     SDL_free(texture);
   145 }
   146 
   147 static int
   148 DisplayPaletteChanged(void *userdata, SDL_Palette * palette)
   149 {
   150     SW_RenderData *data = (SW_RenderData *) userdata;
   151     int i;
   152 
   153     for (i = 0; i < SDL_arraysize(data->texture); ++i) {
   154         if (data->texture[i] && data->renderer->SetTexturePalette) {
   155             data->renderer->SetTexturePalette(data->renderer,
   156                                               data->texture[i],
   157                                               palette->colors, 0,
   158                                               palette->ncolors);
   159         }
   160     }
   161     return 0;
   162 }
   163 
   164 void
   165 Setup_SoftwareRenderer(SDL_Renderer * renderer)
   166 {
   167     renderer->CreateTexture = SW_CreateTexture;
   168     renderer->QueryTexturePixels = SW_QueryTexturePixels;
   169     renderer->SetTexturePalette = SW_SetTexturePalette;
   170     renderer->GetTexturePalette = SW_GetTexturePalette;
   171     renderer->SetTextureColorMod = SW_SetTextureColorMod;
   172     renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
   173     renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
   174     renderer->SetTextureScaleMode = SW_SetTextureScaleMode;
   175     renderer->UpdateTexture = SW_UpdateTexture;
   176     renderer->LockTexture = SW_LockTexture;
   177     renderer->UnlockTexture = SW_UnlockTexture;
   178     renderer->DestroyTexture = SW_DestroyTexture;
   179 
   180     renderer->info.mod_modes = SW_RenderDriver.info.mod_modes;
   181     renderer->info.blend_modes = SW_RenderDriver.info.blend_modes;
   182     renderer->info.scale_modes = SW_RenderDriver.info.scale_modes;
   183     renderer->info.num_texture_formats =
   184         SW_RenderDriver.info.num_texture_formats;
   185     SDL_memcpy(renderer->info.texture_formats,
   186                SW_RenderDriver.info.texture_formats,
   187                sizeof(renderer->info.texture_formats));;
   188     renderer->info.max_texture_width = SW_RenderDriver.info.max_texture_width;
   189     renderer->info.max_texture_height =
   190         SW_RenderDriver.info.max_texture_height;
   191 }
   192 
   193 SDL_Renderer *
   194 SW_CreateRenderer(SDL_Window * window, Uint32 flags)
   195 {
   196     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   197     SDL_DisplayMode *displayMode = &display->current_mode;
   198     SDL_Renderer *renderer;
   199     SW_RenderData *data;
   200     int i, n;
   201     int bpp;
   202     Uint32 Rmask, Gmask, Bmask, Amask;
   203     Uint32 renderer_flags;
   204     const char *desired_driver;
   205 
   206     if (!SDL_PixelFormatEnumToMasks
   207         (displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   208         SDL_SetError("Unknown display format");
   209         return NULL;
   210     }
   211 
   212     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   213     if (!renderer) {
   214         SDL_OutOfMemory();
   215         return NULL;
   216     }
   217 
   218     data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
   219     if (!data) {
   220         SW_DestroyRenderer(renderer);
   221         SDL_OutOfMemory();
   222         return NULL;
   223     }
   224     renderer->ActivateRenderer = SW_ActivateRenderer;
   225     renderer->DisplayModeChanged = SW_DisplayModeChanged;
   226 
   227     renderer->RenderPoint = SW_RenderPoint;
   228     renderer->RenderLine = SW_RenderLine;
   229     renderer->RenderFill = SW_RenderFill;
   230     renderer->RenderCopy = SW_RenderCopy;
   231     renderer->RenderPresent = SW_RenderPresent;
   232     renderer->DestroyRenderer = SW_DestroyRenderer;
   233     renderer->info.name = SW_RenderDriver.info.name;
   234     renderer->info.flags = 0;
   235     renderer->window = window->id;
   236     renderer->driverdata = data;
   237     Setup_SoftwareRenderer(renderer);
   238 
   239     if (flags & SDL_RENDERER_PRESENTFLIP2) {
   240         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   241         n = 2;
   242     } else if (flags & SDL_RENDERER_PRESENTFLIP3) {
   243         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   244         n = 3;
   245     } else {
   246         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
   247         n = 1;
   248     }
   249     data->format = displayMode->format;
   250 
   251     /* Find a render driver that we can use to display data */
   252     renderer_flags = (SDL_RENDERER_SINGLEBUFFER |
   253                       SDL_RENDERER_PRESENTDISCARD);
   254     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   255         renderer_flags |= SDL_RENDERER_PRESENTVSYNC;
   256     }
   257     desired_driver = SDL_getenv("SDL_VIDEO_RENDERER_SWDRIVER");
   258     for (i = 0; i < display->num_render_drivers; ++i) {
   259         SDL_RenderDriver *driver = &display->render_drivers[i];
   260         if (driver->info.name == SW_RenderDriver.info.name) {
   261             continue;
   262         }
   263         if (desired_driver
   264             && SDL_strcasecmp(desired_driver, driver->info.name) != 0) {
   265             continue;
   266         }
   267         data->renderer = driver->CreateRenderer(window, renderer_flags);
   268         if (data->renderer) {
   269             break;
   270         }
   271     }
   272     if (i == display->num_render_drivers) {
   273         SW_DestroyRenderer(renderer);
   274         SDL_SetError("Couldn't find display render driver");
   275         return NULL;
   276     }
   277     if (data->renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) {
   278         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   279     }
   280 
   281     /* Create the textures we'll use for display */
   282     for (i = 0; i < n; ++i) {
   283         data->texture[i] =
   284             CreateTexture(data->renderer, data->format, window->w, window->h);
   285         if (!data->texture[i]) {
   286             SW_DestroyRenderer(renderer);
   287             return NULL;
   288         }
   289     }
   290     data->current_texture = 0;
   291 
   292     /* Create a surface we'll use for rendering */
   293     data->surface.flags = SDL_PREALLOC;
   294     data->surface.format = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask);
   295     if (!data->surface.format) {
   296         SW_DestroyRenderer(renderer);
   297         return NULL;
   298     }
   299     SDL_SetSurfacePalette(&data->surface, display->palette);
   300 
   301     /* Set up a palette watch on the display palette */
   302     if (display->palette) {
   303         SDL_AddPaletteWatch(display->palette, DisplayPaletteChanged, data);
   304     }
   305 
   306     return renderer;
   307 }
   308 
   309 static int
   310 SW_ActivateRenderer(SDL_Renderer * renderer)
   311 {
   312     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   313     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   314     int i, n;
   315 
   316     if (data->renderer && data->renderer->ActivateRenderer) {
   317         if (data->renderer->ActivateRenderer(data->renderer) < 0) {
   318             return -1;
   319         }
   320     }
   321     if (data->updateSize) {
   322         /* Recreate the textures for the new window size */
   323         if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   324             n = 2;
   325         } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   326             n = 3;
   327         } else {
   328             n = 1;
   329         }
   330         for (i = 0; i < n; ++i) {
   331             if (data->texture[i]) {
   332                 DestroyTexture(data->renderer, data->texture[i]);
   333                 data->texture[i] = 0;
   334             }
   335         }
   336         for (i = 0; i < n; ++i) {
   337             data->texture[i] =
   338                 CreateTexture(data->renderer, data->format, window->w,
   339                               window->h);
   340             if (!data->texture[i]) {
   341                 return -1;
   342             }
   343         }
   344         data->updateSize = SDL_FALSE;
   345     }
   346     return 0;
   347 }
   348 
   349 static int
   350 SW_DisplayModeChanged(SDL_Renderer * renderer)
   351 {
   352     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   353 
   354     if (data->renderer && data->renderer->DisplayModeChanged) {
   355         if (data->renderer->DisplayModeChanged(data->renderer) < 0) {
   356             return -1;
   357         }
   358     }
   359     /* Rebind the context to the window area */
   360     data->updateSize = SDL_TRUE;
   361     return SW_ActivateRenderer(renderer);
   362 }
   363 
   364 static int
   365 SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   366 {
   367     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   368         texture->driverdata =
   369             SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
   370     } else {
   371         int bpp;
   372         Uint32 Rmask, Gmask, Bmask, Amask;
   373 
   374         if (!SDL_PixelFormatEnumToMasks
   375             (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   376             SDL_SetError("Unknown texture format");
   377             return -1;
   378         }
   379 
   380         texture->driverdata =
   381             SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
   382                                  Bmask, Amask);
   383         SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
   384                                texture->b);
   385         SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
   386         SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
   387         SDL_SetSurfaceScaleMode(texture->driverdata, texture->scaleMode);
   388 
   389         if (texture->access == SDL_TEXTUREACCESS_STATIC) {
   390             SDL_SetSurfaceRLE(texture->driverdata, 1);
   391         }
   392     }
   393 
   394     if (!texture->driverdata) {
   395         return -1;
   396     }
   397     return 0;
   398 }
   399 
   400 static int
   401 SW_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   402                       void **pixels, int *pitch)
   403 {
   404     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   405         return SDL_SW_QueryYUVTexturePixels((SDL_SW_YUVTexture *)
   406                                             texture->driverdata, pixels,
   407                                             pitch);
   408     } else {
   409         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   410 
   411         *pixels = surface->pixels;
   412         *pitch = surface->pitch;
   413         return 0;
   414     }
   415 }
   416 
   417 static int
   418 SW_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   419                      const SDL_Color * colors, int firstcolor, int ncolors)
   420 {
   421     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   422         SDL_SetError("YUV textures don't have a palette");
   423         return -1;
   424     } else {
   425         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   426 
   427         return SDL_SetPaletteColors(surface->format->palette, colors,
   428                                     firstcolor, ncolors);
   429     }
   430 }
   431 
   432 static int
   433 SW_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   434                      SDL_Color * colors, int firstcolor, int ncolors)
   435 {
   436     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   437         SDL_SetError("YUV textures don't have a palette");
   438         return -1;
   439     } else {
   440         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   441 
   442         SDL_memcpy(colors, &surface->format->palette->colors[firstcolor],
   443                    ncolors * sizeof(*colors));
   444         return 0;
   445     }
   446 }
   447 
   448 static int
   449 SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   450 {
   451     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   452     return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
   453                                   texture->b);
   454 }
   455 
   456 static int
   457 SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   458 {
   459     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   460     return SDL_SetSurfaceAlphaMod(surface, texture->a);
   461 }
   462 
   463 static int
   464 SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   465 {
   466     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   467     return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
   468 }
   469 
   470 static int
   471 SW_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   472 {
   473     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   474     return SDL_SetSurfaceScaleMode(surface, texture->scaleMode);
   475 }
   476 
   477 static int
   478 SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   479                  const SDL_Rect * rect, const void *pixels, int pitch)
   480 {
   481     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   482         return SDL_SW_UpdateYUVTexture((SDL_SW_YUVTexture *)
   483                                        texture->driverdata, rect, pixels,
   484                                        pitch);
   485     } else {
   486         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   487         Uint8 *src, *dst;
   488         int row;
   489         size_t length;
   490 
   491         src = (Uint8 *) pixels;
   492         dst =
   493             (Uint8 *) surface->pixels + rect->y * surface->pitch +
   494             rect->x * surface->format->BytesPerPixel;
   495         length = rect->w * surface->format->BytesPerPixel;
   496         for (row = 0; row < rect->h; ++row) {
   497             SDL_memcpy(dst, src, length);
   498             src += pitch;
   499             dst += surface->pitch;
   500         }
   501         return 0;
   502     }
   503 }
   504 
   505 static int
   506 SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   507                const SDL_Rect * rect, int markDirty, void **pixels,
   508                int *pitch)
   509 {
   510     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   511         return SDL_SW_LockYUVTexture((SDL_SW_YUVTexture *)
   512                                      texture->driverdata, rect, markDirty,
   513                                      pixels, pitch);
   514     } else {
   515         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   516 
   517         *pixels =
   518             (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
   519                       rect->x * surface->format->BytesPerPixel);
   520         *pitch = surface->pitch;
   521         return 0;
   522     }
   523 }
   524 
   525 static void
   526 SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   527 {
   528     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   529         SDL_SW_UnlockYUVTexture((SDL_SW_YUVTexture *) texture->driverdata);
   530     }
   531 }
   532 
   533 static int
   534 SW_RenderPoint(SDL_Renderer * renderer, int x, int y)
   535 {
   536     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   537     SDL_Rect rect;
   538     int status;
   539 
   540     rect.x = x;
   541     rect.y = y;
   542     rect.w = 1;
   543     rect.h = 1;
   544 
   545     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   546         SDL_AddDirtyRect(&data->dirty, &rect);
   547     }
   548 
   549     if (data->renderer->LockTexture(data->renderer,
   550                                     data->texture[data->current_texture],
   551                                     &rect, 1,
   552                                     &data->surface.pixels,
   553                                     &data->surface.pitch) < 0) {
   554         return -1;
   555     }
   556 
   557     data->surface.w = 1;
   558     data->surface.h = 1;
   559     data->surface.clip_rect.w = 1;
   560     data->surface.clip_rect.h = 1;
   561 
   562     if (renderer->blendMode == SDL_BLENDMODE_NONE ||
   563         renderer->blendMode == SDL_BLENDMODE_MASK) {
   564         Uint32 color =
   565             SDL_MapRGBA(data->surface.format, renderer->r, renderer->g,
   566                         renderer->b, renderer->a);
   567 
   568         status = SDL_DrawPoint(&data->surface, 0, 0, color);
   569     } else {
   570         status =
   571             SDL_BlendPoint(&data->surface, 0, 0, renderer->blendMode,
   572                            renderer->r, renderer->g, renderer->b,
   573                            renderer->a);
   574     }
   575 
   576     data->renderer->UnlockTexture(data->renderer,
   577                                   data->texture[data->current_texture]);
   578     return status;
   579 }
   580 
   581 static int
   582 SW_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
   583 {
   584     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   585     SDL_Rect rect;
   586     int status;
   587 
   588     if (x1 < x2) {
   589         rect.x = x1;
   590         rect.w = (x2 - x1) + 1;
   591         x2 -= x1;
   592         x1 = 0;
   593     } else {
   594         rect.x = x2;
   595         rect.w = (x1 - x2) + 1;
   596         x1 -= x2;
   597         x2 = 0;
   598     }
   599     if (y1 < y2) {
   600         rect.y = y1;
   601         rect.h = (y2 - y1) + 1;
   602         y2 -= y1;
   603         y1 = 0;
   604     } else {
   605         rect.y = y2;
   606         rect.h = (y1 - y2) + 1;
   607         y1 -= y2;
   608         y2 = 0;
   609     }
   610 
   611     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   612         SDL_AddDirtyRect(&data->dirty, &rect);
   613     }
   614 
   615     if (data->renderer->LockTexture(data->renderer,
   616                                     data->texture[data->current_texture],
   617                                     &rect, 1,
   618                                     &data->surface.pixels,
   619                                     &data->surface.pitch) < 0) {
   620         return -1;
   621     }
   622 
   623     data->surface.w = rect.w;
   624     data->surface.h = rect.h;
   625     data->surface.clip_rect.w = rect.w;
   626     data->surface.clip_rect.h = rect.h;
   627 
   628     if (renderer->blendMode == SDL_BLENDMODE_NONE ||
   629         renderer->blendMode == SDL_BLENDMODE_MASK) {
   630         Uint32 color =
   631             SDL_MapRGBA(data->surface.format, renderer->r, renderer->g,
   632                         renderer->b, renderer->a);
   633 
   634         status = SDL_DrawLine(&data->surface, x1, y1, x2, y2, color);
   635     } else {
   636         status =
   637             SDL_BlendLine(&data->surface, x1, y1, x2, y2, renderer->blendMode,
   638                           renderer->r, renderer->g, renderer->b, renderer->a);
   639     }
   640 
   641     data->renderer->UnlockTexture(data->renderer,
   642                                   data->texture[data->current_texture]);
   643     return status;
   644 }
   645 
   646 static int
   647 SW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect)
   648 {
   649     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   650     SDL_Rect real_rect;
   651     int status;
   652 
   653     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   654         SDL_AddDirtyRect(&data->dirty, rect);
   655     }
   656 
   657     if (data->renderer->LockTexture(data->renderer,
   658                                     data->texture[data->current_texture],
   659                                     rect, 1, &data->surface.pixels,
   660                                     &data->surface.pitch) < 0) {
   661         return -1;
   662     }
   663 
   664     data->surface.w = rect->w;
   665     data->surface.h = rect->h;
   666     data->surface.clip_rect.w = rect->w;
   667     data->surface.clip_rect.h = rect->h;
   668     real_rect = data->surface.clip_rect;
   669 
   670     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   671         Uint32 color =
   672             SDL_MapRGBA(data->surface.format, renderer->r, renderer->g,
   673                         renderer->b, renderer->a);
   674 
   675         status = SDL_FillRect(&data->surface, &real_rect, color);
   676     } else {
   677         status =
   678             SDL_BlendRect(&data->surface, &real_rect, renderer->blendMode,
   679                           renderer->r, renderer->g, renderer->b, renderer->a);
   680     }
   681 
   682     data->renderer->UnlockTexture(data->renderer,
   683                                   data->texture[data->current_texture]);
   684     return status;
   685 }
   686 
   687 static int
   688 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   689               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   690 {
   691     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   692     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   693     int status;
   694 
   695     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   696         SDL_AddDirtyRect(&data->dirty, dstrect);
   697     }
   698 
   699     if (data->renderer->LockTexture(data->renderer,
   700                                     data->texture[data->current_texture],
   701                                     dstrect, 1, &data->surface.pixels,
   702                                     &data->surface.pitch) < 0) {
   703         return -1;
   704     }
   705 
   706     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   707         status =
   708             SDL_SW_CopyYUVToRGB((SDL_SW_YUVTexture *) texture->driverdata,
   709                                 srcrect, data->format, dstrect->w, dstrect->h,
   710                                 data->surface.pixels, data->surface.pitch);
   711     } else {
   712         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   713         SDL_Rect real_srcrect = *srcrect;
   714         SDL_Rect real_dstrect;
   715 
   716         data->surface.w = dstrect->w;
   717         data->surface.h = dstrect->h;
   718         data->surface.clip_rect.w = dstrect->w;
   719         data->surface.clip_rect.h = dstrect->h;
   720         real_dstrect = data->surface.clip_rect;
   721 
   722         status =
   723             SDL_LowerBlit(surface, &real_srcrect, &data->surface,
   724                           &real_dstrect);
   725     }
   726     data->renderer->UnlockTexture(data->renderer,
   727                                   data->texture[data->current_texture]);
   728     return status;
   729 }
   730 
   731 static void
   732 SW_RenderPresent(SDL_Renderer * renderer)
   733 {
   734     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   735     SDL_Texture *texture = data->texture[data->current_texture];
   736 
   737     /* Send the data to the display */
   738     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   739         SDL_DirtyRect *dirty;
   740         for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
   741             data->renderer->RenderCopy(data->renderer, texture, &dirty->rect,
   742                                        &dirty->rect);
   743         }
   744         SDL_ClearDirtyRects(&data->dirty);
   745     } else {
   746         SDL_Rect rect;
   747         rect.x = 0;
   748         rect.y = 0;
   749         rect.w = texture->w;
   750         rect.h = texture->h;
   751         data->renderer->RenderCopy(data->renderer, texture, &rect, &rect);
   752     }
   753     data->renderer->RenderPresent(data->renderer);
   754 
   755     /* Update the flipping chain, if any */
   756     if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   757         data->current_texture = (data->current_texture + 1) % 2;
   758     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   759         data->current_texture = (data->current_texture + 1) % 3;
   760     }
   761 }
   762 
   763 static void
   764 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   765 {
   766     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   767         SDL_SW_DestroyYUVTexture((SDL_SW_YUVTexture *) texture->driverdata);
   768     } else {
   769         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   770 
   771         SDL_FreeSurface(surface);
   772     }
   773 }
   774 
   775 static void
   776 SW_DestroyRenderer(SDL_Renderer * renderer)
   777 {
   778     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   779     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   780     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   781     int i;
   782 
   783     if (data) {
   784         for (i = 0; i < SDL_arraysize(data->texture); ++i) {
   785             if (data->texture[i]) {
   786                 DestroyTexture(data->renderer, data->texture[i]);
   787             }
   788         }
   789         if (data->surface.format) {
   790             SDL_SetSurfacePalette(&data->surface, NULL);
   791             SDL_FreeFormat(data->surface.format);
   792         }
   793         if (display->palette) {
   794             SDL_DelPaletteWatch(display->palette, DisplayPaletteChanged,
   795                                 data);
   796         }
   797         if (data->renderer) {
   798             data->renderer->DestroyRenderer(data->renderer);
   799         }
   800         SDL_FreeDirtyRects(&data->dirty);
   801         SDL_free(data);
   802     }
   803     SDL_free(renderer);
   804 }
   805 
   806 /* vi: set ts=4 sw=4 expandtab: */