Solved the performance problems by introducing the concept of a single-buffered
authorSam Lantinga <slouken@libsdl.org>
Wed, 12 Jul 2006 06:39:26 +0000
changeset 1897c2a27da60b18
parent 1896 4a74fa359e7e
child 1898 f89e49e51e89
Solved the performance problems by introducing the concept of a single-buffered
display, which is a fast path used for the whole-surface SDL 1.2 API.
Solved the flicker problems by implementing a backbuffer in the GDI renderer.

Unfortunately, now using the GDI renderer with a backbuffer and HBITMAPs is
significantly slower than SDL's surface code. *sigh*
include/SDL_video.h
src/SDL_compat.c
src/video/SDL_renderer_sw.c
src/video/SDL_video.c
src/video/win32/SDL_gdirender.c
     1.1 --- a/include/SDL_video.h	Mon Jul 10 21:23:51 2006 +0000
     1.2 +++ b/include/SDL_video.h	Wed Jul 12 06:39:26 2006 +0000
     1.3 @@ -170,14 +170,14 @@
     1.4   */
     1.5  typedef enum
     1.6  {
     1.7 -    SDL_Renderer_PresentDiscard = 0x00000001,   /**< Present leaves the contents of the backbuffer undefined */
     1.8 +    SDL_Renderer_SingleBuffer = 0x00000001,     /**< Render directly to the window, if possible */
     1.9      SDL_Renderer_PresentCopy = 0x00000002,      /**< Present uses a copy from back buffer to the front buffer */
    1.10      SDL_Renderer_PresentFlip2 = 0x00000004,     /**< Present uses a flip, swapping back buffer and front buffer */
    1.11      SDL_Renderer_PresentFlip3 = 0x00000008,     /**< Present uses a flip, rotating between two back buffers and a front buffer */
    1.12 -    SDL_Renderer_PresentVSync = 0x00000010,     /**< Present is synchronized with the refresh rate */
    1.13 -    SDL_Renderer_RenderTarget = 0x00000020,     /**< The renderer can create texture render targets */
    1.14 -    SDL_Renderer_Accelerated = 0x00000040,      /**< The renderer uses hardware acceleration */
    1.15 -    SDL_Renderer_ = 0x00000080,      /**< The renderer uses hardware acceleration */
    1.16 +    SDL_Renderer_PresentDiscard = 0x00000010,   /**< Present leaves the contents of the backbuffer undefined */
    1.17 +    SDL_Renderer_PresentVSync = 0x00000020,     /**< Present is synchronized with the refresh rate */
    1.18 +    SDL_Renderer_RenderTarget = 0x00000040,     /**< The renderer can create texture render targets */
    1.19 +    SDL_Renderer_Accelerated = 0x00000080,      /**< The renderer uses hardware acceleration */
    1.20      SDL_Renderer_Minimal = 0x00000100,          /**< The renderer only supports the read/write pixel and present functions */
    1.21  } SDL_RendererFlags;
    1.22  
     2.1 --- a/src/SDL_compat.c	Mon Jul 10 21:23:51 2006 +0000
     2.2 +++ b/src/SDL_compat.c	Wed Jul 12 06:39:26 2006 +0000
     2.3 @@ -442,7 +442,8 @@
     2.4      }
     2.5  
     2.6      /* Create a renderer for the window */
     2.7 -    if (SDL_CreateRenderer(SDL_VideoWindow, -1, 0) < 0) {
     2.8 +    if (SDL_CreateRenderer(SDL_VideoWindow, -1, SDL_Renderer_SingleBuffer) <
     2.9 +        0) {
    2.10          return NULL;
    2.11      }
    2.12  
    2.13 @@ -517,6 +518,7 @@
    2.14  
    2.15      /* Clear the surface for display */
    2.16      SDL_FillRect(SDL_PublicSurface, NULL, 0);
    2.17 +    SDL_UpdateRect(SDL_PublicSurface, 0, 0, 0, 0);
    2.18  
    2.19      /* We're finally done! */
    2.20      return SDL_PublicSurface;
    2.21 @@ -617,21 +619,11 @@
    2.22      if (screen) {
    2.23          SDL_Rect rect;
    2.24  
    2.25 -        /* Perform some checking */
    2.26 -        if (w == 0)
    2.27 -            w = screen->w;
    2.28 -        if (h == 0)
    2.29 -            h = screen->h;
    2.30 -        if ((int) (x + w) > screen->w)
    2.31 -            return;
    2.32 -        if ((int) (y + h) > screen->h)
    2.33 -            return;
    2.34 -
    2.35          /* Fill the rectangle */
    2.36 -        rect.x = (Sint16) x;
    2.37 -        rect.y = (Sint16) y;
    2.38 -        rect.w = (Uint16) w;
    2.39 -        rect.h = (Uint16) h;
    2.40 +        rect.x = (int) x;
    2.41 +        rect.y = (int) y;
    2.42 +        rect.w = (int) (w ? w : screen->w);
    2.43 +        rect.h = (int) (h ? h : screen->h);
    2.44          SDL_UpdateRects(screen, 1, &rect);
    2.45      }
    2.46  }
     3.1 --- a/src/video/SDL_renderer_sw.c	Mon Jul 10 21:23:51 2006 +0000
     3.2 +++ b/src/video/SDL_renderer_sw.c	Wed Jul 12 06:39:26 2006 +0000
     3.3 @@ -77,12 +77,11 @@
     3.4      SDL_SW_CreateRenderer,
     3.5      {
     3.6       "software",
     3.7 -     (SDL_Renderer_PresentDiscard |
     3.8 -      SDL_Renderer_PresentCopy |
     3.9 -      SDL_Renderer_PresentFlip2 |
    3.10 -      SDL_Renderer_PresentFlip3 | SDL_Renderer_RenderTarget),
    3.11 -     (SDL_TextureBlendMode_None |
    3.12 -      SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend),
    3.13 +     (SDL_Renderer_SingleBuffer | SDL_Renderer_PresentCopy |
    3.14 +      SDL_Renderer_PresentFlip2 | SDL_Renderer_PresentFlip3 |
    3.15 +      SDL_Renderer_PresentDiscard | SDL_Renderer_RenderTarget),
    3.16 +     (SDL_TextureBlendMode_None | SDL_TextureBlendMode_Mask |
    3.17 +      SDL_TextureBlendMode_Blend),
    3.18       (SDL_TextureScaleMode_None | SDL_TextureScaleMode_Fast),
    3.19       11,
    3.20       {
    3.21 @@ -108,6 +107,7 @@
    3.22      SDL_Surface *target;
    3.23      SDL_Renderer *renderer;
    3.24      SDL_DirtyRectList dirty;
    3.25 +    SDL_bool makedirty;
    3.26  } SDL_SW_RenderData;
    3.27  
    3.28  SDL_Renderer *
    3.29 @@ -185,13 +185,16 @@
    3.30      }
    3.31      data->current_screen = 0;
    3.32      data->target = data->screens[0];
    3.33 +    data->makedirty = SDL_TRUE;
    3.34  
    3.35      /* Find a render driver that we can use to display data */
    3.36      for (i = 0; i < display->num_render_drivers; ++i) {
    3.37          SDL_RenderDriver *driver = &display->render_drivers[i];
    3.38          if (driver->info.name != SDL_SW_RenderDriver.info.name) {
    3.39              data->renderer =
    3.40 -                driver->CreateRenderer(window, SDL_Renderer_PresentDiscard);
    3.41 +                driver->CreateRenderer(window,
    3.42 +                                       (SDL_Renderer_SingleBuffer |
    3.43 +                                        SDL_Renderer_PresentDiscard));
    3.44              if (data->renderer) {
    3.45                  break;
    3.46              }
    3.47 @@ -351,8 +354,10 @@
    3.48  
    3.49      if (texture) {
    3.50          data->target = (SDL_Surface *) texture->driverdata;
    3.51 +        data->makedirty = SDL_FALSE;
    3.52      } else {
    3.53          data->target = data->screens[data->current_screen];
    3.54 +        data->makedirty = SDL_TRUE;
    3.55      }
    3.56  }
    3.57  
    3.58 @@ -364,7 +369,9 @@
    3.59      SDL_Rect real_rect = *rect;
    3.60      Uint8 r, g, b, a;
    3.61  
    3.62 -    SDL_AddDirtyRect(&data->dirty, rect);
    3.63 +    if (data->makedirty) {
    3.64 +        SDL_AddDirtyRect(&data->dirty, rect);
    3.65 +    }
    3.66  
    3.67      a = (Uint8) ((color >> 24) & 0xFF);
    3.68      r = (Uint8) ((color >> 16) & 0xFF);
    3.69 @@ -384,7 +391,9 @@
    3.70      SDL_Window *window = SDL_GetWindowFromID(renderer->window);
    3.71      SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
    3.72  
    3.73 -    SDL_AddDirtyRect(&data->dirty, dstrect);
    3.74 +    if (data->makedirty) {
    3.75 +        SDL_AddDirtyRect(&data->dirty, dstrect);
    3.76 +    }
    3.77  
    3.78      if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
    3.79          SDL_Surface *target = data->target;
    3.80 @@ -450,7 +459,9 @@
    3.81      int row;
    3.82      size_t length;
    3.83  
    3.84 -    SDL_AddDirtyRect(&data->dirty, rect);
    3.85 +    if (data->makedirty) {
    3.86 +        SDL_AddDirtyRect(&data->dirty, rect);
    3.87 +    }
    3.88  
    3.89      src = (Uint8 *) pixels;
    3.90      dst =
    3.91 @@ -471,7 +482,6 @@
    3.92      SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
    3.93      SDL_Surface *surface = data->screens[data->current_screen];
    3.94      SDL_DirtyRect *dirty;
    3.95 -    int new_screen;
    3.96  
    3.97      /* Send the data to the display */
    3.98      for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
    3.99 @@ -485,19 +495,14 @@
   3.100      SDL_ClearDirtyRects(&data->dirty);
   3.101      data->renderer->RenderPresent(data->renderer);
   3.102  
   3.103 -
   3.104      /* Update the flipping chain, if any */
   3.105      if (renderer->info.flags & SDL_Renderer_PresentFlip2) {
   3.106 -        new_screen = (data->current_screen + 1) % 2;
   3.107 +        data->current_screen = (data->current_screen + 1) % 2;
   3.108 +        data->target = data->screens[data->current_screen];
   3.109      } else if (renderer->info.flags & SDL_Renderer_PresentFlip3) {
   3.110 -        new_screen = (data->current_screen + 1) % 3;
   3.111 -    } else {
   3.112 -        new_screen = 0;
   3.113 +        data->current_screen = (data->current_screen + 1) % 3;
   3.114 +        data->target = data->screens[data->current_screen];
   3.115      }
   3.116 -    if (data->target == data->screens[data->current_screen]) {
   3.117 -        data->target = data->screens[new_screen];
   3.118 -    }
   3.119 -    data->current_screen = new_screen;
   3.120  }
   3.121  
   3.122  static void
     4.1 --- a/src/video/SDL_video.c	Mon Jul 10 21:23:51 2006 +0000
     4.2 +++ b/src/video/SDL_video.c	Wed Jul 12 06:39:26 2006 +0000
     4.3 @@ -1769,9 +1769,8 @@
     4.4              return 0;
     4.5          }
     4.6      }
     4.7 -    rect = &real_rect;
     4.8  
     4.9 -    return renderer->RenderFill(renderer, rect, color);
    4.10 +    return renderer->RenderFill(renderer, &real_rect, color);
    4.11  }
    4.12  
    4.13  int
    4.14 @@ -1793,25 +1792,26 @@
    4.15          return -1;
    4.16      }
    4.17  
    4.18 -    /* FIXME: implement clipping */
    4.19      window = SDL_GetWindowFromID(renderer->window);
    4.20 -    real_srcrect.x = 0;
    4.21 -    real_srcrect.y = 0;
    4.22 -    real_srcrect.w = texture->w;
    4.23 -    real_srcrect.h = texture->h;
    4.24 -    real_dstrect.x = 0;
    4.25 -    real_dstrect.y = 0;
    4.26 -    real_dstrect.w = window->w;
    4.27 -    real_dstrect.h = window->h;
    4.28 -    if (!srcrect) {
    4.29 -        srcrect = &real_srcrect;
    4.30 +    if (srcrect) {
    4.31 +        real_srcrect = *srcrect;
    4.32 +    } else {
    4.33 +        real_srcrect.x = 0;
    4.34 +        real_srcrect.y = 0;
    4.35 +        real_srcrect.w = texture->w;
    4.36 +        real_srcrect.h = texture->h;
    4.37      }
    4.38 -    if (!dstrect) {
    4.39 -        dstrect = &real_dstrect;
    4.40 +    if (dstrect) {
    4.41 +        real_dstrect = *dstrect;
    4.42 +    } else {
    4.43 +        real_dstrect.x = 0;
    4.44 +        real_dstrect.y = 0;
    4.45 +        real_dstrect.w = window->w;
    4.46 +        real_dstrect.h = window->h;
    4.47      }
    4.48  
    4.49 -    return renderer->RenderCopy(renderer, texture, srcrect, dstrect,
    4.50 -                                blendMode, scaleMode);
    4.51 +    return renderer->RenderCopy(renderer, texture, &real_srcrect,
    4.52 +                                &real_dstrect, blendMode, scaleMode);
    4.53  }
    4.54  
    4.55  int
    4.56 @@ -1882,6 +1882,9 @@
    4.57          return;
    4.58      }
    4.59  
    4.60 +    if (renderer->SelectRenderTexture) {
    4.61 +        renderer->SelectRenderTexture(renderer, NULL);
    4.62 +    }
    4.63      renderer->RenderPresent(renderer);
    4.64  }
    4.65  
     5.1 --- a/src/video/win32/SDL_gdirender.c	Mon Jul 10 21:23:51 2006 +0000
     5.2 +++ b/src/video/win32/SDL_gdirender.c	Wed Jul 12 06:39:26 2006 +0000
     5.3 @@ -24,6 +24,7 @@
     5.4  #if SDL_VIDEO_RENDER_GDI
     5.5  
     5.6  #include "SDL_win32video.h"
     5.7 +#include "../SDL_rect_c.h"
     5.8  #include "../SDL_yuv_sw_c.h"
     5.9  
    5.10  /* GDI renderer implementation */
    5.11 @@ -78,10 +79,11 @@
    5.12      SDL_GDI_CreateRenderer,
    5.13      {
    5.14       "gdi",
    5.15 -     (SDL_Renderer_PresentDiscard |
    5.16 -      SDL_Renderer_PresentCopy | SDL_Renderer_RenderTarget),
    5.17 -     (SDL_TextureBlendMode_None |
    5.18 -      SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend),
    5.19 +     (SDL_Renderer_SingleBuffer | SDL_Renderer_PresentCopy |
    5.20 +      SDL_Renderer_PresentFlip2 | SDL_Renderer_PresentFlip3 |
    5.21 +      SDL_Renderer_PresentDiscard | SDL_Renderer_RenderTarget),
    5.22 +     (SDL_TextureBlendMode_None | SDL_TextureBlendMode_Mask |
    5.23 +      SDL_TextureBlendMode_Blend),
    5.24       (SDL_TextureScaleMode_None | SDL_TextureScaleMode_Fast),
    5.25       11,
    5.26       {
    5.27 @@ -108,7 +110,11 @@
    5.28      HDC memory_hdc;
    5.29      HDC current_hdc;
    5.30      LPBITMAPINFO bmi;
    5.31 -    HBITMAP window_bmp;
    5.32 +    HBITMAP hbm[3];
    5.33 +    int current_hbm;
    5.34 +    SDL_DirtyRectList dirty;
    5.35 +    SDL_bool makedirty;
    5.36 +    HBITMAP window_dib;
    5.37      void *window_pixels;
    5.38      int window_pitch;
    5.39  } SDL_GDI_RenderData;
    5.40 @@ -151,6 +157,7 @@
    5.41      SDL_GDI_RenderData *data;
    5.42      int bmi_size;
    5.43      HBITMAP hbm;
    5.44 +    int i, n;
    5.45  
    5.46      renderer = (SDL_Renderer *) SDL_malloc(sizeof(*renderer));
    5.47      if (!renderer) {
    5.48 @@ -167,28 +174,6 @@
    5.49      }
    5.50      SDL_zerop(data);
    5.51  
    5.52 -    data->hwnd = windowdata->hwnd;
    5.53 -    data->window_hdc = GetDC(data->hwnd);
    5.54 -    data->render_hdc = CreateCompatibleDC(data->window_hdc);
    5.55 -    data->memory_hdc = CreateCompatibleDC(data->window_hdc);
    5.56 -    data->current_hdc = data->window_hdc;
    5.57 -
    5.58 -    /* Fill in the compatible bitmap info */
    5.59 -    bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
    5.60 -    data->bmi = (LPBITMAPINFO) SDL_malloc(bmi_size);
    5.61 -    if (!data->bmi) {
    5.62 -        SDL_GDI_DestroyRenderer(renderer);
    5.63 -        SDL_OutOfMemory();
    5.64 -        return NULL;
    5.65 -    }
    5.66 -    SDL_memset(data->bmi, 0, bmi_size);
    5.67 -    data->bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    5.68 -
    5.69 -    hbm = CreateCompatibleBitmap(data->window_hdc, 1, 1);
    5.70 -    GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
    5.71 -    GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
    5.72 -    DeleteObject(hbm);
    5.73 -
    5.74      renderer->CreateTexture = SDL_GDI_CreateTexture;
    5.75      renderer->QueryTexturePixels = SDL_GDI_QueryTexturePixels;
    5.76      renderer->SetTexturePalette = SDL_GDI_SetTexturePalette;
    5.77 @@ -211,6 +196,59 @@
    5.78  
    5.79      renderer->info.flags = SDL_Renderer_RenderTarget;
    5.80  
    5.81 +    data->hwnd = windowdata->hwnd;
    5.82 +    data->window_hdc = GetDC(data->hwnd);
    5.83 +    data->render_hdc = CreateCompatibleDC(data->window_hdc);
    5.84 +    data->memory_hdc = CreateCompatibleDC(data->window_hdc);
    5.85 +
    5.86 +    /* Fill in the compatible bitmap info */
    5.87 +    bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
    5.88 +    data->bmi = (LPBITMAPINFO) SDL_malloc(bmi_size);
    5.89 +    if (!data->bmi) {
    5.90 +        SDL_GDI_DestroyRenderer(renderer);
    5.91 +        SDL_OutOfMemory();
    5.92 +        return NULL;
    5.93 +    }
    5.94 +    SDL_memset(data->bmi, 0, bmi_size);
    5.95 +    data->bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    5.96 +
    5.97 +    hbm = CreateCompatibleBitmap(data->window_hdc, 1, 1);
    5.98 +    GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
    5.99 +    GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
   5.100 +    DeleteObject(hbm);
   5.101 +
   5.102 +    if (flags & SDL_Renderer_SingleBuffer) {
   5.103 +        renderer->info.flags |= SDL_Renderer_SingleBuffer;
   5.104 +        n = 0;
   5.105 +    } else if (flags & SDL_Renderer_PresentFlip2) {
   5.106 +        renderer->info.flags |= SDL_Renderer_PresentFlip2;
   5.107 +        n = 2;
   5.108 +    } else if (flags & SDL_Renderer_PresentFlip3) {
   5.109 +        renderer->info.flags |= SDL_Renderer_PresentFlip3;
   5.110 +        n = 3;
   5.111 +    } else {
   5.112 +        renderer->info.flags |= SDL_Renderer_PresentCopy;
   5.113 +        n = 1;
   5.114 +    }
   5.115 +    for (i = 0; i < n; ++i) {
   5.116 +        data->hbm[i] =
   5.117 +            CreateCompatibleBitmap(data->window_hdc, window->w, window->h);
   5.118 +        if (!data->hbm[i]) {
   5.119 +            SDL_GDI_DestroyRenderer(renderer);
   5.120 +            WIN_SetError("CreateCompatibleBitmap()");
   5.121 +            return NULL;
   5.122 +        }
   5.123 +    }
   5.124 +    if (n > 0) {
   5.125 +        SelectObject(data->render_hdc, data->hbm[0]);
   5.126 +        data->current_hdc = data->render_hdc;
   5.127 +        data->makedirty = SDL_TRUE;
   5.128 +    } else {
   5.129 +        data->current_hdc = data->window_hdc;
   5.130 +        data->makedirty = SDL_FALSE;
   5.131 +    }
   5.132 +    data->current_hbm = 0;
   5.133 +
   5.134      return renderer;
   5.135  }
   5.136  
   5.137 @@ -335,7 +373,7 @@
   5.138          return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch);
   5.139      } else {
   5.140          *pixels = data->pixels;
   5.141 -        *pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   5.142 +        *pitch = data->pitch;
   5.143          return 0;
   5.144      }
   5.145  }
   5.146 @@ -494,8 +532,14 @@
   5.147              RealizePalette(data->render_hdc);
   5.148          }
   5.149          data->current_hdc = data->render_hdc;
   5.150 +        data->makedirty = SDL_FALSE;
   5.151 +    } else if (renderer->info.flags & SDL_Renderer_SingleBuffer) {
   5.152 +        data->current_hdc = data->window_hdc;
   5.153 +        data->makedirty = SDL_FALSE;
   5.154      } else {
   5.155 -        data->current_hdc = data->current_hdc;
   5.156 +        SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
   5.157 +        data->current_hdc = data->render_hdc;
   5.158 +        data->makedirty = SDL_TRUE;
   5.159      }
   5.160  }
   5.161  
   5.162 @@ -509,6 +553,10 @@
   5.163      static HBRUSH brush;
   5.164      int status;
   5.165  
   5.166 +    if (data->makedirty) {
   5.167 +        SDL_AddDirtyRect(&data->dirty, rect);
   5.168 +    }
   5.169 +
   5.170      r = (Uint8) ((color >> 16) & 0xFF);
   5.171      g = (Uint8) ((color >> 8) & 0xFF);
   5.172      b = (Uint8) (color & 0xFF);
   5.173 @@ -540,6 +588,10 @@
   5.174      SDL_GDI_TextureData *texturedata =
   5.175          (SDL_GDI_TextureData *) texture->driverdata;
   5.176  
   5.177 +    if (data->makedirty) {
   5.178 +        SDL_AddDirtyRect(&data->dirty, dstrect);
   5.179 +    }
   5.180 +
   5.181      SelectObject(data->memory_hdc, texturedata->hbm);
   5.182      if (texturedata->hpal) {
   5.183          SelectPalette(data->memory_hdc, texturedata->hpal, TRUE);
   5.184 @@ -590,10 +642,10 @@
   5.185      data->bmi->bmiHeader.biHeight = -window->h;
   5.186      data->bmi->bmiHeader.biSizeImage =
   5.187          window->h * (data->bmi->bmiHeader.biBitCount / 8);
   5.188 -    data->window_bmp =
   5.189 +    data->window_dib =
   5.190          CreateDIBSection(data->window_hdc, data->bmi, DIB_RGB_COLORS,
   5.191                           &data->window_pixels, NULL, 0);
   5.192 -    if (!data->window_bmp) {
   5.193 +    if (!data->window_dib) {
   5.194          WIN_SetError("CreateDIBSection()");
   5.195          return -1;
   5.196      }
   5.197 @@ -607,15 +659,15 @@
   5.198      SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   5.199      SDL_GDI_RenderData *data = (SDL_GDI_RenderData *) renderer->driverdata;
   5.200  
   5.201 -    if (!data->window_bmp) {
   5.202 +    if (!data->window_dib) {
   5.203          if (CreateWindowDIB(data, window) < 0) {
   5.204              return -1;
   5.205          }
   5.206      }
   5.207  
   5.208 -    SelectObject(data->memory_hdc, data->window_bmp);
   5.209 +    SelectObject(data->memory_hdc, data->window_dib);
   5.210      BitBlt(data->memory_hdc, rect->x, rect->y, rect->w, rect->h,
   5.211 -           data->window_hdc, rect->x, rect->y, SRCCOPY);
   5.212 +           data->current_hdc, rect->x, rect->y, SRCCOPY);
   5.213  
   5.214      {
   5.215          int bpp = data->bmi->bmiHeader.biBitCount / 8;
   5.216 @@ -642,7 +694,11 @@
   5.217      SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   5.218      SDL_GDI_RenderData *data = (SDL_GDI_RenderData *) renderer->driverdata;
   5.219  
   5.220 -    if (!data->window_bmp) {
   5.221 +    if (data->makedirty) {
   5.222 +        SDL_AddDirtyRect(&data->dirty, rect);
   5.223 +    }
   5.224 +
   5.225 +    if (!data->window_dib) {
   5.226          if (CreateWindowDIB(data, window) < 0) {
   5.227              return -1;
   5.228          }
   5.229 @@ -663,8 +719,8 @@
   5.230          }
   5.231      }
   5.232  
   5.233 -    SelectObject(data->memory_hdc, data->window_bmp);
   5.234 -    BitBlt(data->window_hdc, rect->x, rect->y, rect->w, rect->h,
   5.235 +    SelectObject(data->memory_hdc, data->window_dib);
   5.236 +    BitBlt(data->current_hdc, rect->x, rect->y, rect->w, rect->h,
   5.237             data->memory_hdc, rect->x, rect->y, SRCCOPY);
   5.238  
   5.239      return 0;
   5.240 @@ -673,6 +729,31 @@
   5.241  static void
   5.242  SDL_GDI_RenderPresent(SDL_Renderer * renderer)
   5.243  {
   5.244 +    SDL_GDI_RenderData *data = (SDL_GDI_RenderData *) renderer->driverdata;
   5.245 +    SDL_DirtyRect *dirty;
   5.246 +    int new_hbm;
   5.247 +
   5.248 +    /* Send the data to the display */
   5.249 +/*
   5.250 +    if (!(renderer->info.flags & SDL_Renderer_SingleBuffer)) {
   5.251 +        for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
   5.252 +            const SDL_Rect *rect = &dirty->rect;
   5.253 +            BitBlt(data->window_hdc, rect->x, rect->y, rect->w, rect->h,
   5.254 +                   data->render_hdc, rect->x, rect->y, SRCCOPY);
   5.255 +        }
   5.256 +        SDL_ClearDirtyRects(&data->dirty);
   5.257 +    }
   5.258 +*/
   5.259 +    BitBlt(data->window_hdc, 0, 0, 640, 480, data->render_hdc, 0, 0, SRCCOPY);
   5.260 +
   5.261 +    /* Update the flipping chain, if any */
   5.262 +    if (renderer->info.flags & SDL_Renderer_PresentFlip2) {
   5.263 +        data->current_hbm = (data->current_hbm + 1) % 2;
   5.264 +        SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
   5.265 +    } else if (renderer->info.flags & SDL_Renderer_PresentFlip3) {
   5.266 +        data->current_hbm = (data->current_hbm + 1) % 3;
   5.267 +        SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
   5.268 +    }
   5.269  }
   5.270  
   5.271  static void
   5.272 @@ -700,6 +781,7 @@
   5.273  SDL_GDI_DestroyRenderer(SDL_Renderer * renderer)
   5.274  {
   5.275      SDL_GDI_RenderData *data = (SDL_GDI_RenderData *) renderer->driverdata;
   5.276 +    int i;
   5.277  
   5.278      if (data) {
   5.279          ReleaseDC(data->hwnd, data->window_hdc);
   5.280 @@ -708,8 +790,14 @@
   5.281          if (data->bmi) {
   5.282              SDL_free(data->bmi);
   5.283          }
   5.284 -        if (data->window_bmp) {
   5.285 -            DeleteObject(data->window_bmp);
   5.286 +        for (i = 0; i < SDL_arraysize(data->hbm); ++i) {
   5.287 +            if (data->hbm[i]) {
   5.288 +                DeleteObject(data->hbm[i]);
   5.289 +            }
   5.290 +        }
   5.291 +        SDL_FreeDirtyRects(&data->dirty);
   5.292 +        if (data->window_dib) {
   5.293 +            DeleteObject(data->window_dib);
   5.294          }
   5.295          SDL_free(data);
   5.296      }