# HG changeset patch # User Sam Lantinga # Date 1152686366 0 # Node ID c2a27da60b18b0ff88ea0b5875aa60df17cb1c3b # Parent 4a74fa359e7e170cba052f0937702d25c2518722 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* diff -r 4a74fa359e7e -r c2a27da60b18 include/SDL_video.h --- 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; diff -r 4a74fa359e7e -r c2a27da60b18 src/SDL_compat.c --- 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); } } diff -r 4a74fa359e7e -r c2a27da60b18 src/video/SDL_renderer_sw.c --- 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 diff -r 4a74fa359e7e -r c2a27da60b18 src/video/SDL_video.c --- 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); } diff -r 4a74fa359e7e -r c2a27da60b18 src/video/win32/SDL_gdirender.c --- 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); }