diff src/video/win32/SDL_gdirender.c @ 1897:c2a27da60b18

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*
author Sam Lantinga <slouken@libsdl.org>
date Wed, 12 Jul 2006 06:39:26 +0000
parents c121d94672cb
children f89e49e51e89
line wrap: on
line diff
--- a/src/video/win32/SDL_gdirender.c	Mon Jul 10 21:23:51 2006 +0000
+++ b/src/video/win32/SDL_gdirender.c	Wed Jul 12 06:39:26 2006 +0000
@@ -24,6 +24,7 @@
 #if SDL_VIDEO_RENDER_GDI
 
 #include "SDL_win32video.h"
+#include "../SDL_rect_c.h"
 #include "../SDL_yuv_sw_c.h"
 
 /* GDI renderer implementation */
@@ -78,10 +79,11 @@
     SDL_GDI_CreateRenderer,
     {
      "gdi",
-     (SDL_Renderer_PresentDiscard |
-      SDL_Renderer_PresentCopy | SDL_Renderer_RenderTarget),
-     (SDL_TextureBlendMode_None |
-      SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend),
+     (SDL_Renderer_SingleBuffer | SDL_Renderer_PresentCopy |
+      SDL_Renderer_PresentFlip2 | SDL_Renderer_PresentFlip3 |
+      SDL_Renderer_PresentDiscard | SDL_Renderer_RenderTarget),
+     (SDL_TextureBlendMode_None | SDL_TextureBlendMode_Mask |
+      SDL_TextureBlendMode_Blend),
      (SDL_TextureScaleMode_None | SDL_TextureScaleMode_Fast),
      11,
      {
@@ -108,7 +110,11 @@
     HDC memory_hdc;
     HDC current_hdc;
     LPBITMAPINFO bmi;
-    HBITMAP window_bmp;
+    HBITMAP hbm[3];
+    int current_hbm;
+    SDL_DirtyRectList dirty;
+    SDL_bool makedirty;
+    HBITMAP window_dib;
     void *window_pixels;
     int window_pitch;
 } SDL_GDI_RenderData;
@@ -151,6 +157,7 @@
     SDL_GDI_RenderData *data;
     int bmi_size;
     HBITMAP hbm;
+    int i, n;
 
     renderer = (SDL_Renderer *) SDL_malloc(sizeof(*renderer));
     if (!renderer) {
@@ -167,28 +174,6 @@
     }
     SDL_zerop(data);
 
-    data->hwnd = windowdata->hwnd;
-    data->window_hdc = GetDC(data->hwnd);
-    data->render_hdc = CreateCompatibleDC(data->window_hdc);
-    data->memory_hdc = CreateCompatibleDC(data->window_hdc);
-    data->current_hdc = data->window_hdc;
-
-    /* Fill in the compatible bitmap info */
-    bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
-    data->bmi = (LPBITMAPINFO) SDL_malloc(bmi_size);
-    if (!data->bmi) {
-        SDL_GDI_DestroyRenderer(renderer);
-        SDL_OutOfMemory();
-        return NULL;
-    }
-    SDL_memset(data->bmi, 0, bmi_size);
-    data->bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
-
-    hbm = CreateCompatibleBitmap(data->window_hdc, 1, 1);
-    GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
-    GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
-    DeleteObject(hbm);
-
     renderer->CreateTexture = SDL_GDI_CreateTexture;
     renderer->QueryTexturePixels = SDL_GDI_QueryTexturePixels;
     renderer->SetTexturePalette = SDL_GDI_SetTexturePalette;
@@ -211,6 +196,59 @@
 
     renderer->info.flags = SDL_Renderer_RenderTarget;
 
+    data->hwnd = windowdata->hwnd;
+    data->window_hdc = GetDC(data->hwnd);
+    data->render_hdc = CreateCompatibleDC(data->window_hdc);
+    data->memory_hdc = CreateCompatibleDC(data->window_hdc);
+
+    /* Fill in the compatible bitmap info */
+    bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
+    data->bmi = (LPBITMAPINFO) SDL_malloc(bmi_size);
+    if (!data->bmi) {
+        SDL_GDI_DestroyRenderer(renderer);
+        SDL_OutOfMemory();
+        return NULL;
+    }
+    SDL_memset(data->bmi, 0, bmi_size);
+    data->bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+
+    hbm = CreateCompatibleBitmap(data->window_hdc, 1, 1);
+    GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
+    GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
+    DeleteObject(hbm);
+
+    if (flags & SDL_Renderer_SingleBuffer) {
+        renderer->info.flags |= SDL_Renderer_SingleBuffer;
+        n = 0;
+    } else if (flags & SDL_Renderer_PresentFlip2) {
+        renderer->info.flags |= SDL_Renderer_PresentFlip2;
+        n = 2;
+    } else if (flags & SDL_Renderer_PresentFlip3) {
+        renderer->info.flags |= SDL_Renderer_PresentFlip3;
+        n = 3;
+    } else {
+        renderer->info.flags |= SDL_Renderer_PresentCopy;
+        n = 1;
+    }
+    for (i = 0; i < n; ++i) {
+        data->hbm[i] =
+            CreateCompatibleBitmap(data->window_hdc, window->w, window->h);
+        if (!data->hbm[i]) {
+            SDL_GDI_DestroyRenderer(renderer);
+            WIN_SetError("CreateCompatibleBitmap()");
+            return NULL;
+        }
+    }
+    if (n > 0) {
+        SelectObject(data->render_hdc, data->hbm[0]);
+        data->current_hdc = data->render_hdc;
+        data->makedirty = SDL_TRUE;
+    } else {
+        data->current_hdc = data->window_hdc;
+        data->makedirty = SDL_FALSE;
+    }
+    data->current_hbm = 0;
+
     return renderer;
 }
 
@@ -335,7 +373,7 @@
         return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch);
     } else {
         *pixels = data->pixels;
-        *pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
+        *pitch = data->pitch;
         return 0;
     }
 }
@@ -494,8 +532,14 @@
             RealizePalette(data->render_hdc);
         }
         data->current_hdc = data->render_hdc;
+        data->makedirty = SDL_FALSE;
+    } else if (renderer->info.flags & SDL_Renderer_SingleBuffer) {
+        data->current_hdc = data->window_hdc;
+        data->makedirty = SDL_FALSE;
     } else {
-        data->current_hdc = data->current_hdc;
+        SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
+        data->current_hdc = data->render_hdc;
+        data->makedirty = SDL_TRUE;
     }
 }
 
@@ -509,6 +553,10 @@
     static HBRUSH brush;
     int status;
 
+    if (data->makedirty) {
+        SDL_AddDirtyRect(&data->dirty, rect);
+    }
+
     r = (Uint8) ((color >> 16) & 0xFF);
     g = (Uint8) ((color >> 8) & 0xFF);
     b = (Uint8) (color & 0xFF);
@@ -540,6 +588,10 @@
     SDL_GDI_TextureData *texturedata =
         (SDL_GDI_TextureData *) texture->driverdata;
 
+    if (data->makedirty) {
+        SDL_AddDirtyRect(&data->dirty, dstrect);
+    }
+
     SelectObject(data->memory_hdc, texturedata->hbm);
     if (texturedata->hpal) {
         SelectPalette(data->memory_hdc, texturedata->hpal, TRUE);
@@ -590,10 +642,10 @@
     data->bmi->bmiHeader.biHeight = -window->h;
     data->bmi->bmiHeader.biSizeImage =
         window->h * (data->bmi->bmiHeader.biBitCount / 8);
-    data->window_bmp =
+    data->window_dib =
         CreateDIBSection(data->window_hdc, data->bmi, DIB_RGB_COLORS,
                          &data->window_pixels, NULL, 0);
-    if (!data->window_bmp) {
+    if (!data->window_dib) {
         WIN_SetError("CreateDIBSection()");
         return -1;
     }
@@ -607,15 +659,15 @@
     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
     SDL_GDI_RenderData *data = (SDL_GDI_RenderData *) renderer->driverdata;
 
-    if (!data->window_bmp) {
+    if (!data->window_dib) {
         if (CreateWindowDIB(data, window) < 0) {
             return -1;
         }
     }
 
-    SelectObject(data->memory_hdc, data->window_bmp);
+    SelectObject(data->memory_hdc, data->window_dib);
     BitBlt(data->memory_hdc, rect->x, rect->y, rect->w, rect->h,
-           data->window_hdc, rect->x, rect->y, SRCCOPY);
+           data->current_hdc, rect->x, rect->y, SRCCOPY);
 
     {
         int bpp = data->bmi->bmiHeader.biBitCount / 8;
@@ -642,7 +694,11 @@
     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
     SDL_GDI_RenderData *data = (SDL_GDI_RenderData *) renderer->driverdata;
 
-    if (!data->window_bmp) {
+    if (data->makedirty) {
+        SDL_AddDirtyRect(&data->dirty, rect);
+    }
+
+    if (!data->window_dib) {
         if (CreateWindowDIB(data, window) < 0) {
             return -1;
         }
@@ -663,8 +719,8 @@
         }
     }
 
-    SelectObject(data->memory_hdc, data->window_bmp);
-    BitBlt(data->window_hdc, rect->x, rect->y, rect->w, rect->h,
+    SelectObject(data->memory_hdc, data->window_dib);
+    BitBlt(data->current_hdc, rect->x, rect->y, rect->w, rect->h,
            data->memory_hdc, rect->x, rect->y, SRCCOPY);
 
     return 0;
@@ -673,6 +729,31 @@
 static void
 SDL_GDI_RenderPresent(SDL_Renderer * renderer)
 {
+    SDL_GDI_RenderData *data = (SDL_GDI_RenderData *) renderer->driverdata;
+    SDL_DirtyRect *dirty;
+    int new_hbm;
+
+    /* Send the data to the display */
+/*
+    if (!(renderer->info.flags & SDL_Renderer_SingleBuffer)) {
+        for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
+            const SDL_Rect *rect = &dirty->rect;
+            BitBlt(data->window_hdc, rect->x, rect->y, rect->w, rect->h,
+                   data->render_hdc, rect->x, rect->y, SRCCOPY);
+        }
+        SDL_ClearDirtyRects(&data->dirty);
+    }
+*/
+    BitBlt(data->window_hdc, 0, 0, 640, 480, data->render_hdc, 0, 0, SRCCOPY);
+
+    /* Update the flipping chain, if any */
+    if (renderer->info.flags & SDL_Renderer_PresentFlip2) {
+        data->current_hbm = (data->current_hbm + 1) % 2;
+        SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
+    } else if (renderer->info.flags & SDL_Renderer_PresentFlip3) {
+        data->current_hbm = (data->current_hbm + 1) % 3;
+        SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
+    }
 }
 
 static void
@@ -700,6 +781,7 @@
 SDL_GDI_DestroyRenderer(SDL_Renderer * renderer)
 {
     SDL_GDI_RenderData *data = (SDL_GDI_RenderData *) renderer->driverdata;
+    int i;
 
     if (data) {
         ReleaseDC(data->hwnd, data->window_hdc);
@@ -708,8 +790,14 @@
         if (data->bmi) {
             SDL_free(data->bmi);
         }
-        if (data->window_bmp) {
-            DeleteObject(data->window_bmp);
+        for (i = 0; i < SDL_arraysize(data->hbm); ++i) {
+            if (data->hbm[i]) {
+                DeleteObject(data->hbm[i]);
+            }
+        }
+        SDL_FreeDirtyRects(&data->dirty);
+        if (data->window_dib) {
+            DeleteObject(data->window_dib);
         }
         SDL_free(data);
     }