src/video/win32/SDL_gdirender.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 05 Aug 2006 17:09:42 +0000
changeset 1965 a788656ca29a
parent 1924 69217fdd2c0a
child 1975 ccef0d0c40c6
permissions -rw-r--r--
SDL constants are all uppercase.
     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 #if SDL_VIDEO_RENDER_GDI
    25 
    26 #include "SDL_win32video.h"
    27 #include "../SDL_rect_c.h"
    28 #include "../SDL_yuv_sw_c.h"
    29 
    30 /* GDI renderer implementation */
    31 
    32 static SDL_Renderer *GDI_CreateRenderer(SDL_Window * window, Uint32 flags);
    33 static int GDI_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    34 static int GDI_QueryTexturePixels(SDL_Renderer * renderer,
    35                                   SDL_Texture * texture, void **pixels,
    36                                   int *pitch);
    37 static int GDI_SetTexturePalette(SDL_Renderer * renderer,
    38                                  SDL_Texture * texture,
    39                                  const SDL_Color * colors, int firstcolor,
    40                                  int ncolors);
    41 static int GDI_GetTexturePalette(SDL_Renderer * renderer,
    42                                  SDL_Texture * texture, SDL_Color * colors,
    43                                  int firstcolor, int ncolors);
    44 static int GDI_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    45                              const SDL_Rect * rect, const void *pixels,
    46                              int pitch);
    47 static int GDI_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    48                            const SDL_Rect * rect, int markDirty,
    49                            void **pixels, int *pitch);
    50 static void GDI_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    51 static void GDI_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    52                              int numrects, const SDL_Rect * rects);
    53 static int GDI_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
    54                           Uint32 color);
    55 static int GDI_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    56                           const SDL_Rect * srcrect, const SDL_Rect * dstrect,
    57                           int blendMode, int scaleMode);
    58 static void GDI_RenderPresent(SDL_Renderer * renderer);
    59 static void GDI_DestroyTexture(SDL_Renderer * renderer,
    60                                SDL_Texture * texture);
    61 static void GDI_DestroyRenderer(SDL_Renderer * renderer);
    62 
    63 
    64 SDL_RenderDriver GDI_RenderDriver = {
    65     GDI_CreateRenderer,
    66     {
    67      "gdi",
    68      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
    69       SDL_RENDERER_PRESENTFLIP2 | sDL_RENDERER_PRESENTFLIP3 |
    70       SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED),
    71      (SDL_TEXTUREBLENDMODE_NONE | SDL_TEXTUREBLENDMODE_MASK |
    72       SDL_TEXTUREBLENDMODE_BLEND),
    73      (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST),
    74      11,
    75      {
    76       SDL_PIXELFORMAT_INDEX8,
    77       SDL_PIXELFORMAT_RGB555,
    78       SDL_PIXELFORMAT_RGB565,
    79       SDL_PIXELFORMAT_RGB888,
    80       SDL_PIXELFORMAT_BGR888,
    81       SDL_PIXELFORMAT_ARGB8888,
    82       SDL_PIXELFORMAT_RGBA8888,
    83       SDL_PIXELFORMAT_ABGR8888,
    84       SDL_PIXELFORMAT_BGRA8888,
    85       SDL_PIXELFORMAT_YUY2,
    86       SDL_PIXELFORMAT_UYVY},
    87      0,
    88      0}
    89 };
    90 
    91 typedef struct
    92 {
    93     HWND hwnd;
    94     HDC window_hdc;
    95     HDC render_hdc;
    96     HDC memory_hdc;
    97     HDC current_hdc;
    98     LPBITMAPINFO bmi;
    99     HBITMAP hbm[3];
   100     int current_hbm;
   101     SDL_DirtyRectList dirty;
   102     SDL_bool makedirty;
   103 } GDI_RenderData;
   104 
   105 typedef struct
   106 {
   107     SDL_SW_YUVTexture *yuv;
   108     Uint32 format;
   109     HPALETTE hpal;
   110     HBITMAP hbm;
   111     void *pixels;
   112     int pitch;
   113 } GDI_TextureData;
   114 
   115 static void
   116 UpdateYUVTextureData(SDL_Texture * texture)
   117 {
   118     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   119     SDL_Rect rect;
   120 
   121     rect.x = 0;
   122     rect.y = 0;
   123     rect.w = texture->w;
   124     rect.h = texture->h;
   125     SDL_SW_CopyYUVToRGB(data->yuv, &rect, data->format, texture->w,
   126                         texture->h, data->pixels, data->pitch);
   127 }
   128 
   129 void
   130 GDI_AddRenderDriver(_THIS)
   131 {
   132     SDL_AddRenderDriver(0, &GDI_RenderDriver);
   133 }
   134 
   135 SDL_Renderer *
   136 GDI_CreateRenderer(SDL_Window * window, Uint32 flags)
   137 {
   138     SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
   139     SDL_Renderer *renderer;
   140     GDI_RenderData *data;
   141     int bmi_size;
   142     HBITMAP hbm;
   143     int i, n;
   144 
   145     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   146     if (!renderer) {
   147         SDL_OutOfMemory();
   148         return NULL;
   149     }
   150 
   151     data = (GDI_RenderData *) SDL_calloc(1, sizeof(*data));
   152     if (!data) {
   153         GDI_DestroyRenderer(renderer);
   154         SDL_OutOfMemory();
   155         return NULL;
   156     }
   157 
   158     renderer->CreateTexture = GDI_CreateTexture;
   159     renderer->QueryTexturePixels = GDI_QueryTexturePixels;
   160     renderer->SetTexturePalette = GDI_SetTexturePalette;
   161     renderer->GetTexturePalette = GDI_GetTexturePalette;
   162     renderer->UpdateTexture = GDI_UpdateTexture;
   163     renderer->LockTexture = GDI_LockTexture;
   164     renderer->UnlockTexture = GDI_UnlockTexture;
   165     renderer->DirtyTexture = GDI_DirtyTexture;
   166     renderer->RenderFill = GDI_RenderFill;
   167     renderer->RenderCopy = GDI_RenderCopy;
   168     renderer->RenderPresent = GDI_RenderPresent;
   169     renderer->DestroyTexture = GDI_DestroyTexture;
   170     renderer->DestroyRenderer = GDI_DestroyRenderer;
   171     renderer->info = GDI_RenderDriver.info;
   172     renderer->window = window->id;
   173     renderer->driverdata = data;
   174 
   175     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   176 
   177     data->hwnd = windowdata->hwnd;
   178     data->window_hdc = windowdata->hdc;
   179     data->render_hdc = CreateCompatibleDC(data->window_hdc);
   180     data->memory_hdc = CreateCompatibleDC(data->window_hdc);
   181 
   182     /* Fill in the compatible bitmap info */
   183     bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
   184     data->bmi = (LPBITMAPINFO) SDL_calloc(1, bmi_size);
   185     if (!data->bmi) {
   186         GDI_DestroyRenderer(renderer);
   187         SDL_OutOfMemory();
   188         return NULL;
   189     }
   190     data->bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   191 
   192     hbm = CreateCompatibleBitmap(data->window_hdc, 1, 1);
   193     GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
   194     GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
   195     DeleteObject(hbm);
   196 
   197     if (flags & SDL_RENDERER_SINGLEBUFFER) {
   198         renderer->info.flags |=
   199             (SDL_RENDERER_SINGLEBUFFER | sDL_RENDERER_PRESENTCOPY);
   200         n = 0;
   201     } else if (flags & SDL_RENDERER_PRESENTFLIP2) {
   202         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   203         n = 2;
   204     } else if (flags & SDL_RENDERER_PRESENTFLIP3) {
   205         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   206         n = 3;
   207     } else {
   208         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
   209         n = 1;
   210     }
   211     for (i = 0; i < n; ++i) {
   212         data->hbm[i] =
   213             CreateCompatibleBitmap(data->window_hdc, window->w, window->h);
   214         if (!data->hbm[i]) {
   215             GDI_DestroyRenderer(renderer);
   216             WIN_SetError("CreateCompatibleBitmap()");
   217             return NULL;
   218         }
   219     }
   220     if (n > 0) {
   221         SelectObject(data->render_hdc, data->hbm[0]);
   222         data->current_hdc = data->render_hdc;
   223         data->makedirty = SDL_TRUE;
   224     } else {
   225         data->current_hdc = data->window_hdc;
   226         data->makedirty = SDL_FALSE;
   227     }
   228     data->current_hbm = 0;
   229 
   230     return renderer;
   231 }
   232 
   233 static int
   234 GDI_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   235 {
   236     GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
   237     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   238     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   239     GDI_TextureData *data;
   240 
   241     data = (GDI_TextureData *) SDL_calloc(1, sizeof(*data));
   242     if (!data) {
   243         SDL_OutOfMemory();
   244         return -1;
   245     }
   246 
   247     texture->driverdata = data;
   248 
   249     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   250         data->yuv = SDL_SW_CreateYUVTexture(texture);
   251         if (!data->yuv) {
   252             return -1;
   253         }
   254         data->format = display->current_mode.format;
   255     } else {
   256         data->format = texture->format;
   257     }
   258     data->pitch = (texture->w * SDL_BYTESPERPIXEL(data->format));
   259 
   260     if (data->yuv || texture->access == SDL_TEXTUREACCESS_LOCAL
   261         || texture->format != SDL_GetCurrentDisplayMode()->format) {
   262         int bmi_size;
   263         LPBITMAPINFO bmi;
   264 
   265         bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
   266         bmi = (LPBITMAPINFO) SDL_calloc(1, bmi_size);
   267         if (!bmi) {
   268             SDL_OutOfMemory();
   269             return -1;
   270         }
   271         bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   272         bmi->bmiHeader.biWidth = texture->w;
   273         bmi->bmiHeader.biHeight = -texture->h;  /* topdown bitmap */
   274         bmi->bmiHeader.biPlanes = 1;
   275         bmi->bmiHeader.biSizeImage = texture->h * data->pitch;
   276         bmi->bmiHeader.biXPelsPerMeter = 0;
   277         bmi->bmiHeader.biYPelsPerMeter = 0;
   278         bmi->bmiHeader.biClrUsed = 0;
   279         bmi->bmiHeader.biClrImportant = 0;
   280         bmi->bmiHeader.biBitCount = SDL_BYTESPERPIXEL(data->format) * 8;
   281         if (SDL_ISPIXELFORMAT_INDEXED(data->format)) {
   282             int i, ncolors;
   283             LOGPALETTE *palette;
   284 
   285             bmi->bmiHeader.biCompression = BI_RGB;
   286             ncolors = (1 << SDL_BITSPERPIXEL(data->format));
   287             palette =
   288                 (LOGPALETTE *) SDL_malloc(sizeof(*palette) +
   289                                           ncolors * sizeof(PALETTEENTRY));
   290             if (!palette) {
   291                 SDL_free(bmi);
   292                 SDL_OutOfMemory();
   293                 return -1;
   294             }
   295             palette->palVersion = 0x300;
   296             palette->palNumEntries = ncolors;
   297             for (i = 0; i < ncolors; ++i) {
   298                 palette->palPalEntry[i].peRed = 0xFF;
   299                 palette->palPalEntry[i].peGreen = 0xFF;
   300                 palette->palPalEntry[i].peBlue = 0xFF;
   301                 palette->palPalEntry[i].peFlags = 0;
   302             }
   303             data->hpal = CreatePalette(palette);
   304             SDL_free(palette);
   305         } else {
   306             int bpp;
   307             Uint32 Rmask, Gmask, Bmask, Amask;
   308 
   309             bmi->bmiHeader.biCompression = BI_BITFIELDS;
   310             SDL_PixelFormatEnumToMasks(data->format, &bpp, &Rmask, &Gmask,
   311                                        &Bmask, &Amask);
   312             ((Uint32 *) bmi->bmiColors)[0] = Rmask;
   313             ((Uint32 *) bmi->bmiColors)[1] = Gmask;
   314             ((Uint32 *) bmi->bmiColors)[2] = Bmask;
   315             data->hpal = NULL;
   316         }
   317         data->hbm =
   318             CreateDIBSection(renderdata->memory_hdc, bmi, DIB_RGB_COLORS,
   319                              &data->pixels, NULL, 0);
   320     } else {
   321         data->hbm =
   322             CreateCompatibleBitmap(renderdata->window_hdc, texture->w,
   323                                    texture->h);
   324         data->pixels = NULL;
   325     }
   326     if (!data->hbm) {
   327         WIN_SetError("Couldn't create bitmap");
   328         return -1;
   329     }
   330     return 0;
   331 }
   332 
   333 static int
   334 GDI_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   335                        void **pixels, int *pitch)
   336 {
   337     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   338 
   339     if (data->yuv) {
   340         return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch);
   341     } else {
   342         *pixels = data->pixels;
   343         *pitch = data->pitch;
   344         return 0;
   345     }
   346 }
   347 
   348 static int
   349 GDI_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   350                       const SDL_Color * colors, int firstcolor, int ncolors)
   351 {
   352     GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
   353     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   354 
   355     if (data->yuv) {
   356         SDL_SetError("YUV textures don't have a palette");
   357         return -1;
   358     } else {
   359         PALETTEENTRY entries[256];
   360         int i;
   361 
   362         for (i = 0; i < ncolors; ++i) {
   363             entries[i].peRed = colors[i].r;
   364             entries[i].peGreen = colors[i].g;
   365             entries[i].peBlue = colors[i].b;
   366             entries[i].peFlags = 0;
   367         }
   368         if (!SetPaletteEntries(data->hpal, firstcolor, ncolors, entries)) {
   369             WIN_SetError("SetPaletteEntries()");
   370             return -1;
   371         }
   372         return 0;
   373     }
   374 }
   375 
   376 static int
   377 GDI_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   378                       SDL_Color * colors, int firstcolor, int ncolors)
   379 {
   380     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   381 
   382     if (data->yuv) {
   383         SDL_SetError("YUV textures don't have a palette");
   384         return -1;
   385     } else {
   386         PALETTEENTRY entries[256];
   387         int i;
   388 
   389         if (!GetPaletteEntries(data->hpal, firstcolor, ncolors, entries)) {
   390             WIN_SetError("GetPaletteEntries()");
   391             return -1;
   392         }
   393         for (i = 0; i < ncolors; ++i) {
   394             colors[i].r = entries[i].peRed;
   395             colors[i].g = entries[i].peGreen;
   396             colors[i].b = entries[i].peBlue;
   397         }
   398         return 0;
   399     }
   400 }
   401 
   402 static int
   403 GDI_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   404                   const SDL_Rect * rect, const void *pixels, int pitch)
   405 {
   406     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   407 
   408     if (data->yuv) {
   409         if (SDL_SW_UpdateYUVTexture(data->yuv, rect, pixels, pitch) < 0) {
   410             return -1;
   411         }
   412         UpdateYUVTextureData(texture);
   413         return 0;
   414     } else {
   415         GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
   416 
   417         if (data->pixels) {
   418             Uint8 *src, *dst;
   419             int row;
   420             size_t length;
   421 
   422             src = (Uint8 *) pixels;
   423             dst =
   424                 (Uint8 *) data->pixels + rect->y * data->pitch +
   425                 rect->x * SDL_BYTESPERPIXEL(texture->format);
   426             length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   427             for (row = 0; row < rect->h; ++row) {
   428                 SDL_memcpy(dst, src, length);
   429                 src += pitch;
   430                 dst += data->pitch;
   431             }
   432         } else if (rect->w == texture->w && pitch == data->pitch) {
   433             if (!SetDIBits
   434                 (renderdata->window_hdc, data->hbm, rect->y, rect->h, pixels,
   435                  renderdata->bmi, DIB_RGB_COLORS)) {
   436                 WIN_SetError("SetDIBits()");
   437                 return -1;
   438             }
   439         } else {
   440             SDL_SetError
   441                 ("FIXME: Need to allocate temporary memory and do GetDIBits() followed by SetDIBits(), since we can only set blocks of scanlines at a time");
   442             return -1;
   443         }
   444         return 0;
   445     }
   446 }
   447 
   448 static int
   449 GDI_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   450                 const SDL_Rect * rect, int markDirty, void **pixels,
   451                 int *pitch)
   452 {
   453     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   454 
   455     if (data->yuv) {
   456         return SDL_SW_LockYUVTexture(data->yuv, rect, markDirty, pixels,
   457                                      pitch);
   458     } else if (data->pixels) {
   459         GdiFlush();
   460         *pixels =
   461             (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   462                       rect->x * SDL_BYTESPERPIXEL(texture->format));
   463         *pitch = data->pitch;
   464         return 0;
   465     } else {
   466         SDL_SetError("No pixels available");
   467         return -1;
   468     }
   469 }
   470 
   471 static void
   472 GDI_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   473 {
   474     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   475 
   476     if (data->yuv) {
   477         SDL_SW_UnlockYUVTexture(data->yuv);
   478         UpdateYUVTextureData(texture);
   479     }
   480 }
   481 
   482 static void
   483 GDI_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
   484                  const SDL_Rect * rects)
   485 {
   486 }
   487 
   488 static int
   489 GDI_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 color)
   490 {
   491     GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
   492     Uint8 r, g, b;
   493     RECT rc;
   494     HBRUSH brush;
   495     int status;
   496 
   497     if (data->makedirty) {
   498         SDL_AddDirtyRect(&data->dirty, rect);
   499     }
   500 
   501     r = (Uint8) ((color >> 16) & 0xFF);
   502     g = (Uint8) ((color >> 8) & 0xFF);
   503     b = (Uint8) (color & 0xFF);
   504 
   505     rc.left = rect->x;
   506     rc.top = rect->y;
   507     rc.right = rect->x + rect->w + 1;
   508     rc.bottom = rect->y + rect->h + 1;
   509 
   510     /* Should we cache the brushes? .. it looks like GDI does for us. :) */
   511     brush = CreateSolidBrush(RGB(r, g, b));
   512     SelectObject(data->current_hdc, brush);
   513     status = FillRect(data->current_hdc, &rc, brush);
   514     DeleteObject(brush);
   515 
   516     if (!status) {
   517         WIN_SetError("FillRect()");
   518         return -1;
   519     }
   520     return 0;
   521 }
   522 
   523 static int
   524 GDI_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   525                const SDL_Rect * srcrect, const SDL_Rect * dstrect,
   526                int blendMode, int scaleMode)
   527 {
   528     GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
   529     GDI_TextureData *texturedata = (GDI_TextureData *) texture->driverdata;
   530 
   531     if (data->makedirty) {
   532         SDL_AddDirtyRect(&data->dirty, dstrect);
   533     }
   534 
   535     SelectObject(data->memory_hdc, texturedata->hbm);
   536     if (texturedata->hpal) {
   537         SelectPalette(data->memory_hdc, texturedata->hpal, TRUE);
   538         RealizePalette(data->memory_hdc);
   539     }
   540     if (blendMode & (SDL_TEXTUREBLENDMODE_MASK | SDL_TEXTUREBLENDMODE_BLEND)) {
   541         static BLENDFUNCTION blendFunc = {
   542             AC_SRC_OVER,
   543             0,
   544             255,
   545             AC_SRC_ALPHA
   546         };
   547         /* FIXME: GDI uses premultiplied alpha! */
   548         if (!AlphaBlend
   549             (data->current_hdc, dstrect->x, dstrect->y, dstrect->w,
   550              dstrect->h, data->memory_hdc, srcrect->x, srcrect->y, srcrect->w,
   551              srcrect->h, blendFunc)) {
   552             WIN_SetError("AlphaBlend()");
   553             return -1;
   554         }
   555     } else {
   556         if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) {
   557             if (!BitBlt
   558                 (data->current_hdc, dstrect->x, dstrect->y, dstrect->w,
   559                  srcrect->h, data->memory_hdc, srcrect->x, srcrect->y,
   560                  SRCCOPY)) {
   561                 WIN_SetError("BitBlt()");
   562                 return -1;
   563             }
   564         } else {
   565             if (!StretchBlt
   566                 (data->current_hdc, dstrect->x, dstrect->y, dstrect->w,
   567                  dstrect->h, data->memory_hdc, srcrect->x, srcrect->y,
   568                  srcrect->w, srcrect->h, SRCCOPY)) {
   569                 WIN_SetError("StretchBlt()");
   570                 return -1;
   571             }
   572         }
   573     }
   574     return 0;
   575 }
   576 
   577 static void
   578 GDI_RenderPresent(SDL_Renderer * renderer)
   579 {
   580     GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
   581     SDL_DirtyRect *dirty;
   582 
   583     /* Send the data to the display */
   584     if (!(renderer->info.flags & SDL_RENDERER_SINGLEBUFFER)) {
   585         for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
   586             const SDL_Rect *rect = &dirty->rect;
   587             BitBlt(data->window_hdc, rect->x, rect->y, rect->w, rect->h,
   588                    data->render_hdc, rect->x, rect->y, SRCCOPY);
   589         }
   590         SDL_ClearDirtyRects(&data->dirty);
   591     }
   592 
   593     /* Update the flipping chain, if any */
   594     if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   595         data->current_hbm = (data->current_hbm + 1) % 2;
   596         SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
   597     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   598         data->current_hbm = (data->current_hbm + 1) % 3;
   599         SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
   600     }
   601 }
   602 
   603 static void
   604 GDI_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   605 {
   606     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   607 
   608     if (!data) {
   609         return;
   610     }
   611     if (data->yuv) {
   612         SDL_SW_DestroyYUVTexture(data->yuv);
   613     }
   614     if (data->hpal) {
   615         DeleteObject(data->hpal);
   616     }
   617     if (data->hbm) {
   618         DeleteObject(data->hbm);
   619     }
   620     SDL_free(data);
   621     texture->driverdata = NULL;
   622 }
   623 
   624 void
   625 GDI_DestroyRenderer(SDL_Renderer * renderer)
   626 {
   627     GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
   628     int i;
   629 
   630     if (data) {
   631         DeleteDC(data->render_hdc);
   632         DeleteDC(data->memory_hdc);
   633         if (data->bmi) {
   634             SDL_free(data->bmi);
   635         }
   636         for (i = 0; i < SDL_arraysize(data->hbm); ++i) {
   637             if (data->hbm[i]) {
   638                 DeleteObject(data->hbm[i]);
   639             }
   640         }
   641         SDL_FreeDirtyRects(&data->dirty);
   642         SDL_free(data);
   643     }
   644     SDL_free(renderer);
   645 }
   646 
   647 #endif /* SDL_VIDEO_RENDER_GDI */
   648 
   649 /* vi: set ts=4 sw=4 expandtab: */