Added very slow software scaling to the X11 renderer
authorSam Lantinga <slouken@libsdl.org>
Wed, 03 Dec 2008 12:10:51 +0000
changeset 2828 7e5ff6cd05bf
parent 2827 aec4399c507a
child 2829 16fe3b867887
Added very slow software scaling to the X11 renderer
include/SDL_surface.h
src/video/SDL_stretch.c
src/video/SDL_stretch_c.h
src/video/SDL_yuv_sw.c
src/video/x11/SDL_x11render.c
--- a/include/SDL_surface.h	Wed Dec 03 11:09:58 2008 +0000
+++ b/include/SDL_surface.h	Wed Dec 03 12:10:51 2008 +0000
@@ -462,16 +462,16 @@
      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
--- a/src/video/SDL_stretch.c	Wed Dec 03 11:09:58 2008 +0000
+++ b/src/video/SDL_stretch.c	Wed Dec 03 12:10:51 2008 +0000
@@ -173,8 +173,8 @@
    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;
--- a/src/video/SDL_stretch_c.h	Wed Dec 03 11:09:58 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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: */
--- a/src/video/SDL_yuv_sw.c	Wed Dec 03 11:09:58 2008 +0000
+++ b/src/video/SDL_yuv_sw.c	Wed Dec 03 12:10:51 2008 +0000
@@ -85,7 +85,6 @@
 
 #include "SDL_video.h"
 #include "SDL_cpuinfo.h"
-#include "SDL_stretch_c.h"
 #include "SDL_yuv_sw_c.h"
 
 
--- a/src/video/x11/SDL_x11render.c	Wed Dec 03 11:09:58 2008 +0000
+++ b/src/video/x11/SDL_x11render.c	Wed Dec 03 12:10:51 2008 +0000
@@ -97,6 +97,7 @@
     /* MIT shared memory extension information */
     XShmSegmentInfo shminfo;
 #endif
+    XImage *scaling_image;
     void *pixels;
     int pitch;
 } X11_TextureData;
@@ -131,6 +132,21 @@
                         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 @@
     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 @@
 
     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 @@
 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 @@
     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 @@
         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);
     }