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*
--- a/include/SDL_video.h Mon Jul 10 21:23:51 2006 +0000
+++ b/include/SDL_video.h Wed Jul 12 06:39:26 2006 +0000
@@ -170,14 +170,14 @@
*/
typedef enum
{
- SDL_Renderer_PresentDiscard = 0x00000001, /**< Present leaves the contents of the backbuffer undefined */
+ SDL_Renderer_SingleBuffer = 0x00000001, /**< Render directly to the window, if possible */
SDL_Renderer_PresentCopy = 0x00000002, /**< Present uses a copy from back buffer to the front buffer */
SDL_Renderer_PresentFlip2 = 0x00000004, /**< Present uses a flip, swapping back buffer and front buffer */
SDL_Renderer_PresentFlip3 = 0x00000008, /**< Present uses a flip, rotating between two back buffers and a front buffer */
- SDL_Renderer_PresentVSync = 0x00000010, /**< Present is synchronized with the refresh rate */
- SDL_Renderer_RenderTarget = 0x00000020, /**< The renderer can create texture render targets */
- SDL_Renderer_Accelerated = 0x00000040, /**< The renderer uses hardware acceleration */
- SDL_Renderer_ = 0x00000080, /**< The renderer uses hardware acceleration */
+ SDL_Renderer_PresentDiscard = 0x00000010, /**< Present leaves the contents of the backbuffer undefined */
+ SDL_Renderer_PresentVSync = 0x00000020, /**< Present is synchronized with the refresh rate */
+ SDL_Renderer_RenderTarget = 0x00000040, /**< The renderer can create texture render targets */
+ SDL_Renderer_Accelerated = 0x00000080, /**< The renderer uses hardware acceleration */
SDL_Renderer_Minimal = 0x00000100, /**< The renderer only supports the read/write pixel and present functions */
} SDL_RendererFlags;
--- a/src/SDL_compat.c Mon Jul 10 21:23:51 2006 +0000
+++ b/src/SDL_compat.c Wed Jul 12 06:39:26 2006 +0000
@@ -442,7 +442,8 @@
}
/* Create a renderer for the window */
- if (SDL_CreateRenderer(SDL_VideoWindow, -1, 0) < 0) {
+ if (SDL_CreateRenderer(SDL_VideoWindow, -1, SDL_Renderer_SingleBuffer) <
+ 0) {
return NULL;
}
@@ -517,6 +518,7 @@
/* Clear the surface for display */
SDL_FillRect(SDL_PublicSurface, NULL, 0);
+ SDL_UpdateRect(SDL_PublicSurface, 0, 0, 0, 0);
/* We're finally done! */
return SDL_PublicSurface;
@@ -617,21 +619,11 @@
if (screen) {
SDL_Rect rect;
- /* Perform some checking */
- if (w == 0)
- w = screen->w;
- if (h == 0)
- h = screen->h;
- if ((int) (x + w) > screen->w)
- return;
- if ((int) (y + h) > screen->h)
- return;
-
/* Fill the rectangle */
- rect.x = (Sint16) x;
- rect.y = (Sint16) y;
- rect.w = (Uint16) w;
- rect.h = (Uint16) h;
+ rect.x = (int) x;
+ rect.y = (int) y;
+ rect.w = (int) (w ? w : screen->w);
+ rect.h = (int) (h ? h : screen->h);
SDL_UpdateRects(screen, 1, &rect);
}
}
--- a/src/video/SDL_renderer_sw.c Mon Jul 10 21:23:51 2006 +0000
+++ b/src/video/SDL_renderer_sw.c Wed Jul 12 06:39:26 2006 +0000
@@ -77,12 +77,11 @@
SDL_SW_CreateRenderer,
{
"software",
- (SDL_Renderer_PresentDiscard |
- SDL_Renderer_PresentCopy |
- SDL_Renderer_PresentFlip2 |
- SDL_Renderer_PresentFlip3 | 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,6 +107,7 @@
SDL_Surface *target;
SDL_Renderer *renderer;
SDL_DirtyRectList dirty;
+ SDL_bool makedirty;
} SDL_SW_RenderData;
SDL_Renderer *
@@ -185,13 +185,16 @@
}
data->current_screen = 0;
data->target = data->screens[0];
+ data->makedirty = SDL_TRUE;
/* Find a render driver that we can use to display data */
for (i = 0; i < display->num_render_drivers; ++i) {
SDL_RenderDriver *driver = &display->render_drivers[i];
if (driver->info.name != SDL_SW_RenderDriver.info.name) {
data->renderer =
- driver->CreateRenderer(window, SDL_Renderer_PresentDiscard);
+ driver->CreateRenderer(window,
+ (SDL_Renderer_SingleBuffer |
+ SDL_Renderer_PresentDiscard));
if (data->renderer) {
break;
}
@@ -351,8 +354,10 @@
if (texture) {
data->target = (SDL_Surface *) texture->driverdata;
+ data->makedirty = SDL_FALSE;
} else {
data->target = data->screens[data->current_screen];
+ data->makedirty = SDL_TRUE;
}
}
@@ -364,7 +369,9 @@
SDL_Rect real_rect = *rect;
Uint8 r, g, b, a;
- SDL_AddDirtyRect(&data->dirty, rect);
+ if (data->makedirty) {
+ SDL_AddDirtyRect(&data->dirty, rect);
+ }
a = (Uint8) ((color >> 24) & 0xFF);
r = (Uint8) ((color >> 16) & 0xFF);
@@ -384,7 +391,9 @@
SDL_Window *window = SDL_GetWindowFromID(renderer->window);
SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
- SDL_AddDirtyRect(&data->dirty, dstrect);
+ if (data->makedirty) {
+ SDL_AddDirtyRect(&data->dirty, dstrect);
+ }
if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
SDL_Surface *target = data->target;
@@ -450,7 +459,9 @@
int row;
size_t length;
- SDL_AddDirtyRect(&data->dirty, rect);
+ if (data->makedirty) {
+ SDL_AddDirtyRect(&data->dirty, rect);
+ }
src = (Uint8 *) pixels;
dst =
@@ -471,7 +482,6 @@
SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
SDL_Surface *surface = data->screens[data->current_screen];
SDL_DirtyRect *dirty;
- int new_screen;
/* Send the data to the display */
for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
@@ -485,19 +495,14 @@
SDL_ClearDirtyRects(&data->dirty);
data->renderer->RenderPresent(data->renderer);
-
/* Update the flipping chain, if any */
if (renderer->info.flags & SDL_Renderer_PresentFlip2) {
- new_screen = (data->current_screen + 1) % 2;
+ data->current_screen = (data->current_screen + 1) % 2;
+ data->target = data->screens[data->current_screen];
} else if (renderer->info.flags & SDL_Renderer_PresentFlip3) {
- new_screen = (data->current_screen + 1) % 3;
- } else {
- new_screen = 0;
+ data->current_screen = (data->current_screen + 1) % 3;
+ data->target = data->screens[data->current_screen];
}
- if (data->target == data->screens[data->current_screen]) {
- data->target = data->screens[new_screen];
- }
- data->current_screen = new_screen;
}
static void
--- a/src/video/SDL_video.c Mon Jul 10 21:23:51 2006 +0000
+++ b/src/video/SDL_video.c Wed Jul 12 06:39:26 2006 +0000
@@ -1769,9 +1769,8 @@
return 0;
}
}
- rect = &real_rect;
- return renderer->RenderFill(renderer, rect, color);
+ return renderer->RenderFill(renderer, &real_rect, color);
}
int
@@ -1793,25 +1792,26 @@
return -1;
}
- /* FIXME: implement clipping */
window = SDL_GetWindowFromID(renderer->window);
- real_srcrect.x = 0;
- real_srcrect.y = 0;
- real_srcrect.w = texture->w;
- real_srcrect.h = texture->h;
- real_dstrect.x = 0;
- real_dstrect.y = 0;
- real_dstrect.w = window->w;
- real_dstrect.h = window->h;
- if (!srcrect) {
- srcrect = &real_srcrect;
+ if (srcrect) {
+ real_srcrect = *srcrect;
+ } else {
+ real_srcrect.x = 0;
+ real_srcrect.y = 0;
+ real_srcrect.w = texture->w;
+ real_srcrect.h = texture->h;
}
- if (!dstrect) {
- dstrect = &real_dstrect;
+ if (dstrect) {
+ real_dstrect = *dstrect;
+ } else {
+ real_dstrect.x = 0;
+ real_dstrect.y = 0;
+ real_dstrect.w = window->w;
+ real_dstrect.h = window->h;
}
- return renderer->RenderCopy(renderer, texture, srcrect, dstrect,
- blendMode, scaleMode);
+ return renderer->RenderCopy(renderer, texture, &real_srcrect,
+ &real_dstrect, blendMode, scaleMode);
}
int
@@ -1882,6 +1882,9 @@
return;
}
+ if (renderer->SelectRenderTexture) {
+ renderer->SelectRenderTexture(renderer, NULL);
+ }
renderer->RenderPresent(renderer);
}
--- 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);
}