From f817fbf65a745b86b1bfde298683c353b7ce7eb6 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 3 Dec 2008 12:10:51 +0000 Subject: [PATCH] Added very slow software scaling to the X11 renderer --- include/SDL_surface.h | 6 +- src/video/SDL_stretch.c | 4 +- src/video/SDL_stretch_c.h | 29 ------- src/video/SDL_yuv_sw.c | 1 - src/video/x11/SDL_x11render.c | 142 ++++++++++++++++++++++++++++++---- 5 files changed, 130 insertions(+), 52 deletions(-) delete mode 100644 src/video/SDL_stretch_c.h diff --git a/include/SDL_surface.h b/include/SDL_surface.h index 2bf38fd53..7100c20e8 100644 --- a/include/SDL_surface.h +++ b/include/SDL_surface.h @@ -462,16 +462,16 @@ extern DECLSPEC int SDLCALL SDL_LowerBlit SDL_Surface * dst, SDL_Rect * dstrect); /** - * \fn int SDL_SoftStretch(SDL_Surface * src, SDL_Rect * srcrect, SDL_Surface * dst, SDL_Rect * dstrect) + * \fn int SDL_SoftStretch(SDL_Surface * src, const SDL_Rect * srcrect, SDL_Surface * dst, const SDL_Rect * dstrect) * * \brief Perform a fast, low quality, stretch blit between two surfaces of the same pixel format. * * \note This function uses a static buffer, and is not thread-safe. */ extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface * src, - SDL_Rect * srcrect, + const SDL_Rect * srcrect, SDL_Surface * dst, - SDL_Rect * dstrect); + const SDL_Rect * dstrect); /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff --git a/src/video/SDL_stretch.c b/src/video/SDL_stretch.c index 780cec1cc..4849ff83e 100644 --- a/src/video/SDL_stretch.c +++ b/src/video/SDL_stretch.c @@ -173,8 +173,8 @@ copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w) NOTE: This function is not safe to call from multiple threads! */ int -SDL_SoftStretch(SDL_Surface * src, SDL_Rect * srcrect, - SDL_Surface * dst, SDL_Rect * dstrect) +SDL_SoftStretch(SDL_Surface * src, const SDL_Rect * srcrect, + SDL_Surface * dst, const SDL_Rect * dstrect) { int src_locked; int dst_locked; diff --git a/src/video/SDL_stretch_c.h b/src/video/SDL_stretch_c.h deleted file mode 100644 index 48d82fdc3..000000000 --- a/src/video/SDL_stretch_c.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2006 Sam Lantinga - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org -*/ -#include "SDL_config.h" - -/* Perform a stretch blit between two surfaces of the same format. - NOTE: This function is not safe to call from multiple threads! -*/ -extern int SDL_SoftStretch(SDL_Surface * src, SDL_Rect * srcrect, - SDL_Surface * dst, SDL_Rect * dstrect); -/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_yuv_sw.c b/src/video/SDL_yuv_sw.c index 9ba0a5261..ef80fa702 100644 --- a/src/video/SDL_yuv_sw.c +++ b/src/video/SDL_yuv_sw.c @@ -85,7 +85,6 @@ #include "SDL_video.h" #include "SDL_cpuinfo.h" -#include "SDL_stretch_c.h" #include "SDL_yuv_sw_c.h" diff --git a/src/video/x11/SDL_x11render.c b/src/video/x11/SDL_x11render.c index 833e29afc..fbf28d776 100644 --- a/src/video/x11/SDL_x11render.c +++ b/src/video/x11/SDL_x11render.c @@ -97,6 +97,7 @@ typedef struct /* MIT shared memory extension information */ XShmSegmentInfo shminfo; #endif + XImage *scaling_image; void *pixels; int pitch; } X11_TextureData; @@ -131,6 +132,21 @@ UpdateYUVTextureData(SDL_Texture * texture) texture->h, data->pixels, data->pitch); } +static int +X11_GetDepthFromPixelFormat(Uint32 format) +{ + int depth, order; + + depth = SDL_BITSPERPIXEL(format); + order = SDL_PIXELORDER(format); + if (depth == 32 + && (order == SDL_PACKEDORDER_XRGB || order == SDL_PACKEDORDER_RGBX + || SDL_PACKEDORDER_XBGR || order == SDL_PACKEDORDER_BGRX)) { + depth = 24; + } + return depth; +} + static Uint32 X11_GetPixelFormatFromDepth(Display * display, int screen, int depth, int bpp) { @@ -385,7 +401,7 @@ X11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); X11_TextureData *data; XWindowAttributes attributes; - int depth, order; + int depth; data = (X11_TextureData *) SDL_calloc(1, sizeof(*data)); if (!data) { @@ -409,13 +425,7 @@ X11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) XGetWindowAttributes(renderdata->display, renderdata->window, &attributes); - depth = SDL_BITSPERPIXEL(data->format); - order = SDL_PIXELORDER(data->format); - if (depth == 32 - && (order == SDL_PACKEDORDER_XRGB || order == SDL_PACKEDORDER_RGBX - || SDL_PACKEDORDER_XBGR || order == SDL_PACKEDORDER_BGRX)) { - depth = 24; - } + depth = X11_GetDepthFromPixelFormat(data->format); if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) { #ifndef NO_SHARED_MEMORY @@ -532,9 +542,17 @@ X11_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) static int X11_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture) { + X11_TextureData *data = (X11_TextureData *) texture->driverdata; + switch (texture->scaleMode) { case SDL_TEXTURESCALEMODE_NONE: return 0; + case SDL_TEXTURESCALEMODE_FAST: + /* We can sort of fake it for streaming textures */ + if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) { + return 0; + } + /* Fall through to unsupported case */ default: SDL_Unsupported(); texture->scaleMode = SDL_TEXTURESCALEMODE_NONE; @@ -646,17 +664,102 @@ X11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, if (data->makedirty) { SDL_AddDirtyRect(&data->dirty, dstrect); } + if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) { #ifndef NO_SHARED_MEMORY - if (texturedata->shminfo.shmaddr) { - XShmPutImage(data->display, data->drawable, data->gc, - texturedata->image, srcrect->x, srcrect->y, dstrect->x, - dstrect->y, srcrect->w, srcrect->h, False); - } else + if (texturedata->shminfo.shmaddr) { + XShmPutImage(data->display, data->drawable, data->gc, + texturedata->image, srcrect->x, srcrect->y, + dstrect->x, dstrect->y, srcrect->w, srcrect->h, + False); + } else #endif - if (texturedata->pixels) { - XPutImage(data->display, data->drawable, data->gc, texturedata->image, - srcrect->x, srcrect->y, dstrect->x, dstrect->y, srcrect->w, - srcrect->h); + if (texturedata->pixels) { + XPutImage(data->display, data->drawable, data->gc, + texturedata->image, srcrect->x, srcrect->y, dstrect->x, + dstrect->y, srcrect->w, srcrect->h); + } else { + XCopyArea(data->display, texturedata->pixmap, data->drawable, + data->gc, srcrect->x, srcrect->y, dstrect->w, + dstrect->h, srcrect->x, srcrect->y); + } + } else if (texturedata->yuv + || texture->access == SDL_TEXTUREACCESS_STREAMING) { + SDL_Surface src, dst; + SDL_PixelFormat fmt; + SDL_Rect rect; + XImage *image = texturedata->scaling_image; + + if (!image) { + XWindowAttributes attributes; + int depth; + void *pixels; + int pitch; + + XGetWindowAttributes(data->display, data->window, &attributes); + + pitch = dstrect->w * SDL_BYTESPERPIXEL(texturedata->format); + pixels = SDL_malloc(dstrect->h * pitch); + if (!pixels) { + SDL_OutOfMemory(); + return -1; + } + + depth = X11_GetDepthFromPixelFormat(texturedata->format); + image = + XCreateImage(data->display, attributes.visual, depth, ZPixmap, + 0, pixels, dstrect->w, dstrect->h, + SDL_BYTESPERPIXEL(texturedata->format) * 8, + pitch); + if (!image) { + SDL_SetError("XCreateImage() failed"); + return -1; + } + texturedata->scaling_image = image; + + } else if (image->width != dstrect->w || image->height != dstrect->h + || !image->data) { + image->width = dstrect->w; + image->height = dstrect->h; + image->bytes_per_line = + image->width * SDL_BYTESPERPIXEL(texturedata->format); + image->data = + (char *) SDL_realloc(image->data, + image->height * image->bytes_per_line); + if (!image->data) { + SDL_OutOfMemory(); + return -1; + } + } + + /* Set up fake surfaces for SDL_SoftStretch() */ + src.format = &fmt; + src.w = texture->w; + src.h = texture->h; +#ifndef NO_SHARED_MEMORY + if (texturedata->shminfo.shmaddr) { + src.pixels = texturedata->shminfo.shmaddr; + } else +#endif + src.pixels = texturedata->pixels; + src.pitch = texturedata->pitch; + + dst.format = &fmt; + dst.w = image->width; + dst.h = image->height; + dst.pixels = image->data; + dst.pitch = image->bytes_per_line; + + fmt.BytesPerPixel = SDL_BYTESPERPIXEL(texturedata->format); + + rect.x = 0; + rect.y = 0; + rect.w = dstrect->w; + rect.h = dstrect->h; + if (SDL_SoftStretch(&src, srcrect, &dst, &rect) < 0) { + return -1; + } + XPutImage(data->display, data->drawable, data->gc, image, 0, 0, + dstrect->x, dstrect->y, dstrect->w, dstrect->h); } else { XCopyArea(data->display, texturedata->pixmap, data->drawable, data->gc, srcrect->x, srcrect->y, dstrect->w, dstrect->h, @@ -720,6 +823,11 @@ X11_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) data->pixels = NULL; } #endif + if (data->scaling_image) { + SDL_free(data->scaling_image->data); + data->scaling_image->data = NULL; + XDestroyImage(data->scaling_image); + } if (data->pixels) { SDL_free(data->pixels); }