src/video/SDL_renderer_sw.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 07 Dec 2008 22:37:40 +0000
changeset 2853 6258fa7cd300
parent 2811 7af2419ad5b0
child 2859 99210400e8b9
permissions -rw-r--r--
Fixed picking blit function when RLE fails
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b,
    63                          Uint8 a, const SDL_Rect * rect);
    64 static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    65                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    66 static void SW_RenderPresent(SDL_Renderer * renderer);
    67 static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    68 static void SW_DestroyRenderer(SDL_Renderer * renderer);
    69 
    70 
    71 SDL_RenderDriver SW_RenderDriver = {
    72     SW_CreateRenderer,
    73     {
    74      "software",
    75      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
    76       SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
    77       SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_PRESENTVSYNC),
    78      (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
    79       SDL_TEXTUREMODULATE_ALPHA),
    80      (SDL_TEXTUREBLENDMODE_NONE | SDL_TEXTUREBLENDMODE_MASK |
    81       SDL_TEXTUREBLENDMODE_BLEND | SDL_TEXTUREBLENDMODE_ADD |
    82       SDL_TEXTUREBLENDMODE_MOD),
    83      (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST),
    84      14,
    85      {
    86       SDL_PIXELFORMAT_INDEX8,
    87       SDL_PIXELFORMAT_RGB555,
    88       SDL_PIXELFORMAT_RGB565,
    89       SDL_PIXELFORMAT_RGB888,
    90       SDL_PIXELFORMAT_BGR888,
    91       SDL_PIXELFORMAT_ARGB8888,
    92       SDL_PIXELFORMAT_RGBA8888,
    93       SDL_PIXELFORMAT_ABGR8888,
    94       SDL_PIXELFORMAT_BGRA8888,
    95       SDL_PIXELFORMAT_YV12,
    96       SDL_PIXELFORMAT_IYUV,
    97       SDL_PIXELFORMAT_YUY2,
    98       SDL_PIXELFORMAT_UYVY,
    99       SDL_PIXELFORMAT_YVYU},
   100      0,
   101      0}
   102 };
   103 
   104 typedef struct
   105 {
   106     Uint32 format;
   107     SDL_bool updateSize;
   108     int current_texture;
   109     SDL_Texture *texture[3];
   110     SDL_Surface surface;
   111     SDL_Renderer *renderer;
   112     SDL_DirtyRectList dirty;
   113 } SW_RenderData;
   114 
   115 static SDL_Texture *
   116 CreateTexture(SDL_Renderer * renderer, Uint32 format, int w, int h)
   117 {
   118     SDL_Texture *texture;
   119 
   120     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
   121     if (!texture) {
   122         SDL_OutOfMemory();
   123         return NULL;
   124     }
   125 
   126     texture->format = format;
   127     texture->access = SDL_TEXTUREACCESS_STREAMING;
   128     texture->w = w;
   129     texture->h = h;
   130     texture->renderer = renderer;
   131 
   132     if (renderer->CreateTexture(renderer, texture) < 0) {
   133         SDL_free(texture);
   134         return NULL;
   135     }
   136     return texture;
   137 }
   138 
   139 static void
   140 DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   141 {
   142     renderer->DestroyTexture(renderer, texture);
   143     SDL_free(texture);
   144 }
   145 
   146 static int
   147 DisplayPaletteChanged(void *userdata, SDL_Palette * palette)
   148 {
   149     SW_RenderData *data = (SW_RenderData *) userdata;
   150     int i;
   151 
   152     for (i = 0; i < SDL_arraysize(data->texture); ++i) {
   153         if (data->texture[i] && data->renderer->SetTexturePalette) {
   154             data->renderer->SetTexturePalette(data->renderer,
   155                                               data->texture[i],
   156                                               palette->colors, 0,
   157                                               palette->ncolors);
   158         }
   159     }
   160     return 0;
   161 }
   162 
   163 void
   164 Setup_SoftwareRenderer(SDL_Renderer * renderer)
   165 {
   166     renderer->CreateTexture = SW_CreateTexture;
   167     renderer->QueryTexturePixels = SW_QueryTexturePixels;
   168     renderer->SetTexturePalette = SW_SetTexturePalette;
   169     renderer->GetTexturePalette = SW_GetTexturePalette;
   170     renderer->SetTextureColorMod = SW_SetTextureColorMod;
   171     renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
   172     renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
   173     renderer->SetTextureScaleMode = SW_SetTextureScaleMode;
   174     renderer->UpdateTexture = SW_UpdateTexture;
   175     renderer->LockTexture = SW_LockTexture;
   176     renderer->UnlockTexture = SW_UnlockTexture;
   177     renderer->DestroyTexture = SW_DestroyTexture;
   178 
   179     renderer->info.mod_modes = SW_RenderDriver.info.mod_modes;
   180     renderer->info.blend_modes = SW_RenderDriver.info.blend_modes;
   181     renderer->info.scale_modes = SW_RenderDriver.info.scale_modes;
   182     renderer->info.num_texture_formats =
   183         SW_RenderDriver.info.num_texture_formats;
   184     SDL_memcpy(renderer->info.texture_formats,
   185                SW_RenderDriver.info.texture_formats,
   186                sizeof(renderer->info.texture_formats));;
   187     renderer->info.max_texture_width = SW_RenderDriver.info.max_texture_width;
   188     renderer->info.max_texture_height =
   189         SW_RenderDriver.info.max_texture_height;
   190 }
   191 
   192 SDL_Renderer *
   193 SW_CreateRenderer(SDL_Window * window, Uint32 flags)
   194 {
   195     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   196     SDL_DisplayMode *displayMode = &display->current_mode;
   197     SDL_Renderer *renderer;
   198     SW_RenderData *data;
   199     int i, n;
   200     int bpp;
   201     Uint32 Rmask, Gmask, Bmask, Amask;
   202     Uint32 renderer_flags;
   203     const char *desired_driver;
   204 
   205     if (!SDL_PixelFormatEnumToMasks
   206         (displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   207         SDL_SetError("Unknown display format");
   208         return NULL;
   209     }
   210 
   211     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   212     if (!renderer) {
   213         SDL_OutOfMemory();
   214         return NULL;
   215     }
   216 
   217     data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
   218     if (!data) {
   219         SW_DestroyRenderer(renderer);
   220         SDL_OutOfMemory();
   221         return NULL;
   222     }
   223     renderer->ActivateRenderer = SW_ActivateRenderer;
   224     renderer->DisplayModeChanged = SW_DisplayModeChanged;
   225     renderer->RenderFill = SW_RenderFill;
   226     renderer->RenderCopy = SW_RenderCopy;
   227     renderer->RenderPresent = SW_RenderPresent;
   228     renderer->DestroyRenderer = SW_DestroyRenderer;
   229     renderer->info.name = SW_RenderDriver.info.name;
   230     renderer->info.flags = 0;
   231     renderer->window = window->id;
   232     renderer->driverdata = data;
   233     Setup_SoftwareRenderer(renderer);
   234 
   235     if (flags & SDL_RENDERER_PRESENTFLIP2) {
   236         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   237         n = 2;
   238     } else if (flags & SDL_RENDERER_PRESENTFLIP3) {
   239         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   240         n = 3;
   241     } else {
   242         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
   243         n = 1;
   244     }
   245     data->format = displayMode->format;
   246 
   247     /* Find a render driver that we can use to display data */
   248     renderer_flags = (SDL_RENDERER_SINGLEBUFFER |
   249                       SDL_RENDERER_PRESENTDISCARD);
   250     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   251         renderer_flags |= SDL_RENDERER_PRESENTVSYNC;
   252     }
   253     desired_driver = SDL_getenv("SDL_VIDEO_RENDERER_SWDRIVER");
   254     for (i = 0; i < display->num_render_drivers; ++i) {
   255         SDL_RenderDriver *driver = &display->render_drivers[i];
   256         if (driver->info.name == SW_RenderDriver.info.name) {
   257             continue;
   258         }
   259         if (desired_driver
   260             && SDL_strcasecmp(desired_driver, driver->info.name) != 0) {
   261             continue;
   262         }
   263         data->renderer = driver->CreateRenderer(window, renderer_flags);
   264         if (data->renderer) {
   265             break;
   266         }
   267     }
   268     if (i == display->num_render_drivers) {
   269         SW_DestroyRenderer(renderer);
   270         SDL_SetError("Couldn't find display render driver");
   271         return NULL;
   272     }
   273     if (data->renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) {
   274         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   275     }
   276 
   277     /* Create the textures we'll use for display */
   278     for (i = 0; i < n; ++i) {
   279         data->texture[i] =
   280             CreateTexture(data->renderer, data->format, window->w, window->h);
   281         if (!data->texture[i]) {
   282             SW_DestroyRenderer(renderer);
   283             return NULL;
   284         }
   285     }
   286     data->current_texture = 0;
   287 
   288     /* Create a surface we'll use for rendering */
   289     data->surface.flags = SDL_PREALLOC;
   290     data->surface.format = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask);
   291     if (!data->surface.format) {
   292         SW_DestroyRenderer(renderer);
   293         return NULL;
   294     }
   295     SDL_SetSurfacePalette(&data->surface, display->palette);
   296 
   297     /* Set up a palette watch on the display palette */
   298     if (display->palette) {
   299         SDL_AddPaletteWatch(display->palette, DisplayPaletteChanged, data);
   300     }
   301 
   302     return renderer;
   303 }
   304 
   305 static int
   306 SW_ActivateRenderer(SDL_Renderer * renderer)
   307 {
   308     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   309     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   310     int i, n;
   311 
   312     if (data->renderer && data->renderer->ActivateRenderer) {
   313         if (data->renderer->ActivateRenderer(data->renderer) < 0) {
   314             return -1;
   315         }
   316     }
   317     if (data->updateSize) {
   318         /* Recreate the textures for the new window size */
   319         if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   320             n = 2;
   321         } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   322             n = 3;
   323         } else {
   324             n = 1;
   325         }
   326         for (i = 0; i < n; ++i) {
   327             if (data->texture[i]) {
   328                 DestroyTexture(data->renderer, data->texture[i]);
   329                 data->texture[i] = 0;
   330             }
   331         }
   332         for (i = 0; i < n; ++i) {
   333             data->texture[i] =
   334                 CreateTexture(data->renderer, data->format, window->w,
   335                               window->h);
   336             if (!data->texture[i]) {
   337                 return -1;
   338             }
   339         }
   340         data->updateSize = SDL_FALSE;
   341     }
   342     return 0;
   343 }
   344 
   345 static int
   346 SW_DisplayModeChanged(SDL_Renderer * renderer)
   347 {
   348     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   349 
   350     if (data->renderer && data->renderer->DisplayModeChanged) {
   351         if (data->renderer->DisplayModeChanged(data->renderer) < 0) {
   352             return -1;
   353         }
   354     }
   355     data->updateSize = SDL_TRUE;
   356     return 0;
   357 }
   358 
   359 static int
   360 SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   361 {
   362     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   363         texture->driverdata =
   364             SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
   365     } else {
   366         int bpp;
   367         Uint32 Rmask, Gmask, Bmask, Amask;
   368 
   369         if (!SDL_PixelFormatEnumToMasks
   370             (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   371             SDL_SetError("Unknown texture format");
   372             return -1;
   373         }
   374 
   375         texture->driverdata =
   376             SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
   377                                  Bmask, Amask);
   378         if (texture->access == SDL_TEXTUREACCESS_STATIC) {
   379             SDL_SetSurfaceRLE(texture->driverdata, 1);
   380         }
   381     }
   382 
   383     if (!texture->driverdata) {
   384         return -1;
   385     }
   386     return 0;
   387 }
   388 
   389 static int
   390 SW_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   391                       void **pixels, int *pitch)
   392 {
   393     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   394         return SDL_SW_QueryYUVTexturePixels((SDL_SW_YUVTexture *)
   395                                             texture->driverdata, pixels,
   396                                             pitch);
   397     } else {
   398         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   399 
   400         *pixels = surface->pixels;
   401         *pitch = surface->pitch;
   402         return 0;
   403     }
   404 }
   405 
   406 static int
   407 SW_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   408                      const SDL_Color * colors, int firstcolor, int ncolors)
   409 {
   410     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   411         SDL_SetError("YUV textures don't have a palette");
   412         return -1;
   413     } else {
   414         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   415 
   416         return SDL_SetPaletteColors(surface->format->palette, colors,
   417                                     firstcolor, ncolors);
   418     }
   419 }
   420 
   421 static int
   422 SW_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   423                      SDL_Color * colors, int firstcolor, int ncolors)
   424 {
   425     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   426         SDL_SetError("YUV textures don't have a palette");
   427         return -1;
   428     } else {
   429         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   430 
   431         SDL_memcpy(colors, &surface->format->palette->colors[firstcolor],
   432                    ncolors * sizeof(*colors));
   433         return 0;
   434     }
   435 }
   436 
   437 static int
   438 SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   439 {
   440     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   441     return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
   442                                   texture->b);
   443 }
   444 
   445 static int
   446 SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   447 {
   448     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   449     return SDL_SetSurfaceAlphaMod(surface, texture->a);
   450 }
   451 
   452 static int
   453 SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   454 {
   455     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   456     return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
   457 }
   458 
   459 static int
   460 SW_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   461 {
   462     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   463     return SDL_SetSurfaceScaleMode(surface, texture->scaleMode);
   464 }
   465 
   466 static int
   467 SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   468                  const SDL_Rect * rect, const void *pixels, int pitch)
   469 {
   470     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   471         return SDL_SW_UpdateYUVTexture((SDL_SW_YUVTexture *)
   472                                        texture->driverdata, rect, pixels,
   473                                        pitch);
   474     } else {
   475         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   476         Uint8 *src, *dst;
   477         int row;
   478         size_t length;
   479 
   480         src = (Uint8 *) pixels;
   481         dst =
   482             (Uint8 *) surface->pixels + rect->y * surface->pitch +
   483             rect->x * surface->format->BytesPerPixel;
   484         length = rect->w * surface->format->BytesPerPixel;
   485         for (row = 0; row < rect->h; ++row) {
   486             SDL_memcpy(dst, src, length);
   487             src += pitch;
   488             dst += surface->pitch;
   489         }
   490         return 0;
   491     }
   492 }
   493 
   494 static int
   495 SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   496                const SDL_Rect * rect, int markDirty, void **pixels,
   497                int *pitch)
   498 {
   499     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   500         return SDL_SW_LockYUVTexture((SDL_SW_YUVTexture *)
   501                                      texture->driverdata, rect, markDirty,
   502                                      pixels, pitch);
   503     } else {
   504         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   505 
   506         *pixels =
   507             (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
   508                       rect->x * surface->format->BytesPerPixel);
   509         *pitch = surface->pitch;
   510         return 0;
   511     }
   512 }
   513 
   514 static void
   515 SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   516 {
   517     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   518         SDL_SW_UnlockYUVTexture((SDL_SW_YUVTexture *) texture->driverdata);
   519     }
   520 }
   521 
   522 static int
   523 SW_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
   524               const SDL_Rect * rect)
   525 {
   526     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   527     Uint32 color;
   528     SDL_Rect real_rect;
   529     int status;
   530 
   531     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   532         SDL_AddDirtyRect(&data->dirty, rect);
   533     }
   534 
   535     color = SDL_MapRGBA(data->surface.format, r, g, b, a);
   536 
   537     if (data->renderer->LockTexture(data->renderer,
   538                                     data->texture[data->current_texture],
   539                                     rect, 1, &data->surface.pixels,
   540                                     &data->surface.pitch) < 0) {
   541         return -1;
   542     }
   543     data->surface.w = rect->w;
   544     data->surface.h = rect->h;
   545     data->surface.clip_rect.w = rect->w;
   546     data->surface.clip_rect.h = rect->h;
   547     real_rect = data->surface.clip_rect;
   548 
   549     status = SDL_FillRect(&data->surface, &real_rect, color);
   550 
   551     data->renderer->UnlockTexture(data->renderer,
   552                                   data->texture[data->current_texture]);
   553     return status;
   554 }
   555 
   556 static int
   557 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   558               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   559 {
   560     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   561     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   562     int status;
   563 
   564     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   565         SDL_AddDirtyRect(&data->dirty, dstrect);
   566     }
   567 
   568     if (data->renderer->LockTexture(data->renderer,
   569                                     data->texture[data->current_texture],
   570                                     dstrect, 1, &data->surface.pixels,
   571                                     &data->surface.pitch) < 0) {
   572         return -1;
   573     }
   574 
   575     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   576         status =
   577             SDL_SW_CopyYUVToRGB((SDL_SW_YUVTexture *) texture->driverdata,
   578                                 srcrect, data->format, dstrect->w, dstrect->h,
   579                                 data->surface.pixels, data->surface.pitch);
   580     } else {
   581         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   582         SDL_Rect real_srcrect = *srcrect;
   583         SDL_Rect real_dstrect;
   584 
   585         data->surface.w = dstrect->w;
   586         data->surface.h = dstrect->h;
   587         data->surface.clip_rect.w = dstrect->w;
   588         data->surface.clip_rect.h = dstrect->h;
   589         real_dstrect = data->surface.clip_rect;
   590 
   591         status =
   592             SDL_LowerBlit(surface, &real_srcrect, &data->surface,
   593                           &real_dstrect);
   594     }
   595     data->renderer->UnlockTexture(data->renderer,
   596                                   data->texture[data->current_texture]);
   597     return status;
   598 }
   599 
   600 static void
   601 SW_RenderPresent(SDL_Renderer * renderer)
   602 {
   603     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   604     SDL_Texture *texture = data->texture[data->current_texture];
   605 
   606     /* Send the data to the display */
   607     if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) {
   608         SDL_DirtyRect *dirty;
   609         for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
   610             data->renderer->RenderCopy(data->renderer, texture, &dirty->rect,
   611                                        &dirty->rect);
   612         }
   613         SDL_ClearDirtyRects(&data->dirty);
   614     } else {
   615         SDL_Rect rect;
   616         rect.x = 0;
   617         rect.y = 0;
   618         rect.w = texture->w;
   619         rect.h = texture->h;
   620         data->renderer->RenderCopy(data->renderer, texture, &rect, &rect);
   621     }
   622     data->renderer->RenderPresent(data->renderer);
   623 
   624     /* Update the flipping chain, if any */
   625     if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   626         data->current_texture = (data->current_texture + 1) % 2;
   627     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   628         data->current_texture = (data->current_texture + 1) % 3;
   629     }
   630 }
   631 
   632 static void
   633 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   634 {
   635     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   636         SDL_SW_DestroyYUVTexture((SDL_SW_YUVTexture *) texture->driverdata);
   637     } else {
   638         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   639 
   640         SDL_FreeSurface(surface);
   641     }
   642 }
   643 
   644 static void
   645 SW_DestroyRenderer(SDL_Renderer * renderer)
   646 {
   647     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   648     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   649     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   650     int i;
   651 
   652     if (data) {
   653         for (i = 0; i < SDL_arraysize(data->texture); ++i) {
   654             if (data->texture[i]) {
   655                 DestroyTexture(data->renderer, data->texture[i]);
   656             }
   657         }
   658         if (data->surface.format) {
   659             SDL_SetSurfacePalette(&data->surface, NULL);
   660             SDL_FreeFormat(data->surface.format);
   661         }
   662         if (display->palette) {
   663             SDL_DelPaletteWatch(display->palette, DisplayPaletteChanged,
   664                                 data);
   665         }
   666         if (data->renderer) {
   667             data->renderer->DestroyRenderer(data->renderer);
   668         }
   669         SDL_FreeDirtyRects(&data->dirty);
   670         SDL_free(data);
   671     }
   672     SDL_free(renderer);
   673 }
   674 
   675 /* vi: set ts=4 sw=4 expandtab: */