Commit d1be2d9e authored by Sam Lantinga's avatar Sam Lantinga

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*

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%401942
parent 58d76aea
......@@ -170,14 +170,14 @@ typedef enum
*/
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;
......
......@@ -442,7 +442,8 @@ SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)
}
/* 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 @@ SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)
/* 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 @@ SDL_UpdateRect(SDL_Surface * screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
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);
}
}
......
......@@ -77,12 +77,11 @@ SDL_RenderDriver SDL_SW_RenderDriver = {
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 @@ typedef struct
SDL_Surface *target;
SDL_Renderer *renderer;
SDL_DirtyRectList dirty;
SDL_bool makedirty;
} SDL_SW_RenderData;
SDL_Renderer *
......@@ -185,13 +185,16 @@ SDL_SW_CreateRenderer(SDL_Window * window, Uint32 flags)
}
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 @@ SDL_SW_SelectRenderTexture(SDL_Renderer * renderer, SDL_Texture * texture)
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_SW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
SDL_Rect real_rect = *rect;
Uint8 r, g, b, a;
if (data->makedirty) {
SDL_AddDirtyRect(&data->dirty, rect);
}
a = (Uint8) ((color >> 24) & 0xFF);
r = (Uint8) ((color >> 16) & 0xFF);
......@@ -384,7 +391,9 @@ SDL_SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
SDL_Window *window = SDL_GetWindowFromID(renderer->window);
SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
if (data->makedirty) {
SDL_AddDirtyRect(&data->dirty, dstrect);
}
if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
SDL_Surface *target = data->target;
......@@ -450,7 +459,9 @@ SDL_SW_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
int row;
size_t length;
if (data->makedirty) {
SDL_AddDirtyRect(&data->dirty, rect);
}
src = (Uint8 *) pixels;
dst =
......@@ -471,7 +482,6 @@ SDL_SW_RenderPresent(SDL_Renderer * renderer)
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_SW_RenderPresent(SDL_Renderer * renderer)
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;
}
if (data->target == data->screens[data->current_screen]) {
data->target = data->screens[new_screen];
data->current_screen = (data->current_screen + 1) % 3;
data->target = data->screens[data->current_screen];
}
data->current_screen = new_screen;
}
static void
......
......@@ -1769,9 +1769,8 @@ SDL_RenderFill(const SDL_Rect * rect, Uint32 color)
return 0;
}
}
rect = &real_rect;
return renderer->RenderFill(renderer, rect, color);
return renderer->RenderFill(renderer, &real_rect, color);
}
int
......@@ -1793,25 +1792,26 @@ SDL_RenderCopy(SDL_TextureID textureID, const SDL_Rect * srcrect,
return -1;
}
/* FIXME: implement clipping */
window = SDL_GetWindowFromID(renderer->window);
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) {
real_dstrect = *dstrect;
} else {
real_dstrect.x = 0;
real_dstrect.y = 0;
real_dstrect.w = window->w;
real_dstrect.h = window->h;
if (!srcrect) {
srcrect = &real_srcrect;
}
if (!dstrect) {
dstrect = &real_dstrect;
}
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 @@ SDL_RenderPresent(void)
return;
}
if (renderer->SelectRenderTexture) {
renderer->SelectRenderTexture(renderer, NULL);
}
renderer->RenderPresent(renderer);
}
......
......@@ -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_RenderDriver SDL_GDI_RenderDriver = {
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 @@ typedef struct
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_CreateRenderer(SDL_Window * window, Uint32 flags)
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_GDI_CreateRenderer(SDL_Window * window, Uint32 flags)
}
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 @@ SDL_GDI_CreateRenderer(SDL_Window * window, Uint32 flags)
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 @@ SDL_GDI_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
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 @@ SDL_GDI_SelectRenderTexture(SDL_Renderer * renderer, SDL_Texture * texture)
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 @@ SDL_GDI_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
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_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
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 @@ CreateWindowDIB(SDL_GDI_RenderData * data, SDL_Window * window)
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_GDI_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
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_GDI_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
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 @@ SDL_GDI_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
}
}
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 @@ SDL_GDI_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
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 @@ void
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 @@ SDL_GDI_DestroyRenderer(SDL_Renderer * renderer)
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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment