diff src/video/x11/SDL_x11render.c @ 4618:844b5ef4b149

Merged Sunny's XRender changes from SDL-gsoc2010_xrender
author Sam Lantinga <slouken@libsdl.org>
date Wed, 28 Jul 2010 00:54:23 -0700
parents 791b3256fb22 cfbb1ff4b8ec
children b9a205e6369f
line wrap: on
line diff
--- a/src/video/x11/SDL_x11render.c	Tue Jul 27 21:31:28 2010 -0700
+++ b/src/video/x11/SDL_x11render.c	Wed Jul 28 00:54:23 2010 -0700
@@ -1,4 +1,5 @@
 /*
+
     SDL - Simple DirectMedia Layer
     Copyright (C) 1997-2010 Sam Lantinga
 
@@ -39,6 +40,8 @@
 static int X11_QueryTexturePixels(SDL_Renderer * renderer,
                                   SDL_Texture * texture, void **pixels,
                                   int *pitch);
+static int X11_SetTextureRGBAMod(SDL_Renderer * renderer,
+                                 SDL_Texture * texture);
 static int X11_SetTextureBlendMode(SDL_Renderer * renderer,
                                    SDL_Texture * texture);
 static int X11_SetTextureScaleMode(SDL_Renderer * renderer,
@@ -96,6 +99,25 @@
     int scanline_pad;
     Window xwindow;
     Pixmap pixmaps[3];
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    Pixmap stencil;
+    Pixmap brush;
+    Picture brush_pict;
+    Picture xwindow_pict;
+    Picture pixmap_picts[3];
+    Picture drawable_pict;
+    Picture stencil_pict;
+    int blend_op;
+    XRenderPictFormat *xwindow_pict_fmt;
+    XRenderPictFormat *drawable_pict_fmt;
+    GC stencil_gc;
+    SDL_bool use_xrender;
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+    SDL_bool use_xdamage;
+    Damage stencil_damage;
+    XserverRegion stencil_parts;
+#endif
+#endif
     int current_pixmap;
     Drawable drawable;
     SDL_PixelFormat format;
@@ -109,6 +131,17 @@
     SDL_SW_YUVTexture *yuv;
     Uint32 format;
     Pixmap pixmap;
+    int depth;
+    Visual *visual;
+    GC gc;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    Picture picture;
+    Pixmap modulated_pixmap;
+    Picture modulated_picture;
+    XRenderPictFormat* picture_fmt;
+    int blend_op;
+    const char* filter;
+#endif
     XImage *image;
 #ifndef NO_SHARED_MEMORY
     /* MIT shared memory extension information */
@@ -149,11 +182,109 @@
                         texture->h, data->pixels, data->pitch);
 }
 
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+static SDL_bool
+CheckXRender(Display *display, int *major, int *minor) {
+    const char *env;
+
+    *major = *minor = 0;
+
+    env = SDL_getenv("SDL_VIDEO_X11_XRENDER");
+
+    if (env && !SDL_atoi(env)) {
+        return SDL_FALSE;
+    }
+
+    if (!SDL_X11_HAVE_XRENDER) {
+        return SDL_FALSE;
+    }
+
+    if (!XRenderQueryVersion(display, major, minor)) {
+        return SDL_FALSE;
+    }
+
+    return SDL_TRUE;
+}
+#endif
+
+#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
+static SDL_bool
+CheckXFixes(Display *display, int *major, int *minor) {
+    const char *env;
+
+    *major = *minor = 0;
+
+    env = SDL_getenv("SDL_VIDEO_X11_XFIXES");
+
+    if (env && !SDL_atoi(env)) {
+        return SDL_FALSE;
+    }
+
+    if (!SDL_X11_HAVE_XFIXES) {
+        return SDL_FALSE;
+    }
+
+    if (!XFixesQueryVersion(display, major, minor)) {
+        return SDL_FALSE;
+    }
+
+    return SDL_TRUE;
+}
+#endif
+
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+static SDL_bool
+CheckXDamage(Display *display, int *major, int *minor) {
+    const char *env;
+
+    *major = *minor = 0;
+
+    env = SDL_getenv("SDL_VIDEO_X11_XDAMAGE");
+
+    if (env && !SDL_atoi(env)) {
+        return SDL_FALSE;
+    }
+
+    if (!SDL_X11_HAVE_XDAMAGE) {
+        return SDL_FALSE;
+    }
+
+    if (!XDamageQueryVersion(display, major, minor)) {
+        return SDL_FALSE;
+    }
+
+    return SDL_TRUE;
+}
+#endif
+
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+static Uint32
+XRenderPictFormatToSDLPixelFormatEnum(XRenderPictFormat *pict_format) {
+    if (pict_format->type != PictTypeDirect) {
+        SDL_SetError("Indexed pict formats not supported ATM");
+        return 0;
+    }
+    Uint32 Amask, Rmask, Gmask, Bmask;
+    int bpp;
+
+    Rmask = pict_format->direct.redMask << pict_format->direct.red;
+    Gmask = pict_format->direct.greenMask << pict_format->direct.green;
+    Bmask = pict_format->direct.blueMask << pict_format->direct.blue;
+    Amask = pict_format->direct.alphaMask << pict_format->direct.alpha;
+    bpp = pict_format->depth;
+
+    Uint32 format;
+    format = SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
+    return format;
+}
+#endif
+
 void
 X11_AddRenderDriver(_THIS)
 {
     SDL_RendererInfo *info = &X11_RenderDriver.info;
     SDL_DisplayMode *mode = &SDL_CurrentDisplay->desktop_mode;
+    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
     int i;
 
     info->texture_formats[info->num_texture_formats++] = mode->format;
@@ -163,6 +294,34 @@
     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YVYU;
 
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    int major, minor;
+    if (CheckXRender(data->display, &major, &minor)) {
+        XRenderPictFormat templ;
+        templ.type = PictTypeDirect;
+        XRenderPictFormat *pict_format;
+        Uint32 format;
+        int i = 0;
+        while (info->num_texture_formats < 50) {
+            pict_format =
+                XRenderFindFormat(data->display, PictFormatType, &templ, i++);
+            if (pict_format) {
+                format = XRenderPictFormatToSDLPixelFormatEnum(pict_format);
+                if (format != SDL_PIXELTYPE_UNKNOWN) {
+                    info->texture_formats[info->num_texture_formats++] = format;
+                }
+            }
+            else
+                break;
+        }
+        info->blend_modes |= (SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD |
+                             SDL_BLENDMODE_MOD | SDL_BLENDMODE_MASK);
+        info->scale_modes |= (SDL_TEXTURESCALEMODE_FAST | SDL_TEXTURESCALEMODE_SLOW |
+                             SDL_TEXTURESCALEMODE_BEST);
+        info->mod_modes |= (SDL_TEXTUREMODULATE_COLOR | SDL_TEXTUREMODULATE_ALPHA);
+    }
+#endif
+
     for (i = 0; i < _this->num_displays; ++i) {
         SDL_AddRenderDriver(&_this->displays[i], &X11_RenderDriver);
     }
@@ -177,6 +336,7 @@
     SDL_Renderer *renderer;
     X11_RenderData *data;
     XGCValues gcv;
+    gcv.graphics_exposures = False;
     int i, n;
     int bpp;
     Uint32 Rmask, Gmask, Bmask, Amask;
@@ -199,10 +359,12 @@
     data->depth = displaydata->depth;
     data->scanline_pad = displaydata->scanline_pad;
     data->xwindow = windowdata->xwindow;
-
+    
     renderer->DisplayModeChanged = X11_DisplayModeChanged;
     renderer->CreateTexture = X11_CreateTexture;
     renderer->QueryTexturePixels = X11_QueryTexturePixels;
+    renderer->SetTextureAlphaMod = X11_SetTextureRGBAMod;
+    renderer->SetTextureColorMod = X11_SetTextureRGBAMod;
     renderer->SetTextureBlendMode = X11_SetTextureBlendMode;
     renderer->SetTextureScaleMode = X11_SetTextureScaleMode;
     renderer->UpdateTexture = X11_UpdateTexture;
@@ -225,6 +387,82 @@
 
     renderer->info.flags = SDL_RENDERER_ACCELERATED;
 
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    int major, minor;
+    data->use_xrender = CheckXRender(data->display, &major, &minor);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+    if (CheckXDamage(data->display, &major, &minor)) {
+        if (CheckXFixes(data->display, &major, &minor)) {
+            if (major >= 2)
+                data->use_xdamage = SDL_TRUE;
+        }
+    }
+#endif
+    if (data->use_xrender) {
+        /* Find the PictFormat from the visual.
+         * Should be an RGB PictFormat most of the time. */
+        data->xwindow_pict_fmt = XRenderFindVisualFormat(data->display,
+                                                         data->visual);
+        if (!data->xwindow_pict_fmt) {
+            SDL_SetError("XRenderFindVisualFormat() failed");
+            return NULL;
+        }
+        data->xwindow_pict = XRenderCreatePicture(data->display,
+                                                  data->xwindow,
+                                                  data->xwindow_pict_fmt,
+                                                  0, NULL);
+        if (!data->xwindow_pict) {
+            SDL_SetError("XRenderCreatePicture() failed");
+            return NULL;
+        }
+        // FIXME: Clear the window. Is this required?
+        XRenderComposite(data->display,
+                         PictOpClear,
+                         data->xwindow_pict,
+                         None,
+                         data->xwindow_pict,
+                         0, 0,
+                         0, 0,
+                         0, 0,
+                         window->w, window->h);
+        /* Create a clip mask that is used for rendering primitives. */
+        data->stencil = XCreatePixmap(data->display, data->xwindow,
+                                   window->w, window->h, 32);
+        
+        /* Create the GC for the clip mask. */
+        data->stencil_gc = XCreateGC(data->display, data->stencil,
+                                  GCGraphicsExposures, &gcv);
+        XSetBackground(data->display, data->stencil_gc, 0);
+        XSetForeground(data->display, data->stencil_gc, 0);
+        XFillRectangle(data->display, data->stencil, data->stencil_gc,
+                       0, 0, window->w, window->h);
+        XSetForeground(data->display, data->stencil_gc, 0xFFFFFFFF);
+        data->stencil_pict =
+            XRenderCreatePicture(data->display, data->stencil,
+                                 XRenderFindStandardFormat(data->display,
+                                                           PictStandardARGB32),
+                                 0, NULL);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+        if (data->use_xdamage) {
+            data->stencil_damage =
+                XDamageCreate(data->display, data->stencil, XDamageReportNonEmpty);
+            XDamageSubtract(data->display, data->stencil_damage, None, data->stencil_parts);
+        }
+#endif
+        data->brush =
+            XCreatePixmap(data->display, data->xwindow, 1, 1, 32);
+        XRenderPictureAttributes brush_attr;
+        brush_attr.repeat = RepeatNormal;
+        data->brush_pict =
+            XRenderCreatePicture(data->display, data->brush,
+                                 XRenderFindStandardFormat(data->display,
+                                                           PictStandardARGB32),
+                                 CPRepeat, &brush_attr);
+        // Set the default blending mode.
+        renderer->blendMode = SDL_BLENDMODE_BLEND;
+        data->blend_op = PictOpOver;
+    }
+#endif
     if (flags & SDL_RENDERER_SINGLEBUFFER) {
         renderer->info.flags |=
             (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY);
@@ -239,39 +477,110 @@
         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
         n = 1;
     }
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    if (data->use_xrender) {
+        if (n > 0)
+            data->drawable_pict_fmt =
+                XRenderFindStandardFormat(data->display, PictStandardARGB32);
+        else
+            data->drawable_pict_fmt = data->xwindow_pict_fmt;
+    }
+#endif
     for (i = 0; i < n; ++i) {
-        data->pixmaps[i] =
-            XCreatePixmap(data->display, data->xwindow, window->w, window->h,
-                          displaydata->depth);
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (data->use_xrender) {
+            data->pixmaps[i] = XCreatePixmap(data->display,
+                                             data->xwindow,
+                                             window->w,
+                                             window->h,
+                                             32);
+        }
+        else
+#endif
+        {
+            data->pixmaps[i] =
+                XCreatePixmap(data->display, data->xwindow, window->w, window->h,
+                              displaydata->depth);
+        }
         if (data->pixmaps[i] == None) {
             X11_DestroyRenderer(renderer);
             SDL_SetError("XCreatePixmap() failed");
             return NULL;
         }
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (data->use_xrender) {
+            /* Create xrender pictures for each of the pixmaps
+             * and clear the pixmaps. */
+            data->pixmap_picts[i] = 
+                XRenderCreatePicture(data->display,
+                                     data->pixmaps[i],
+                                     XRenderFindStandardFormat(data->display,
+                                                               PictStandardARGB32),
+                                     0, None);
+            if (!data->pixmap_picts[i]) {
+                SDL_SetError("XRenderCreatePicture() failed");
+                return NULL;
+            }
+
+            XRenderComposite(data->display,
+                             PictOpClear,
+                             data->pixmap_picts[i],
+                             None,
+                             data->pixmap_picts[i],
+                             0, 0,
+                             0, 0,
+                             0, 0,
+                             window->w, window->h);
+        }
+#endif
     }
     if (n > 0) {
         data->drawable = data->pixmaps[0];
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if(data->use_xrender == SDL_TRUE)
+            data->drawable_pict = data->pixmap_picts[0];
+#endif
         data->makedirty = SDL_TRUE;
     } else {
         data->drawable = data->xwindow;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if(data->use_xrender == SDL_TRUE)
+            data->drawable_pict = data->xwindow_pict;
+#endif
         data->makedirty = SDL_FALSE;
     }
     data->current_pixmap = 0;
 
-    /* Get the format of the window */
-    if (!SDL_PixelFormatEnumToMasks
-        (display->current_mode.format, &bpp, &Rmask, &Gmask, &Bmask,
-         &Amask)) {
-        SDL_SetError("Unknown display format");
-        X11_DestroyRenderer(renderer);
-        return NULL;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    if (data->use_xrender) {
+        bpp = data->drawable_pict_fmt->depth;
+        Rmask = ((data->drawable_pict_fmt->direct.redMask)
+                    << (data->drawable_pict_fmt->direct.red));
+        Gmask = ((data->drawable_pict_fmt->direct.greenMask)
+                    << (data->drawable_pict_fmt->direct.green));
+        Bmask = ((data->drawable_pict_fmt->direct.blueMask)
+                    << (data->drawable_pict_fmt->direct.blue));
+        Amask = ((data->drawable_pict_fmt->direct.alphaMask)
+                    << (data->drawable_pict_fmt->direct.alpha));
+    }
+    else
+#endif
+    {
+        /* Get the format of the window */
+        if (!SDL_PixelFormatEnumToMasks
+            (display->current_mode.format, &bpp, &Rmask, &Gmask, &Bmask,
+             &Amask)) {
+            SDL_SetError("Unknown display format");
+            X11_DestroyRenderer(renderer);
+            return NULL;
+        }
     }
     SDL_InitFormat(&data->format, bpp, Rmask, Gmask, Bmask, Amask);
 
     /* Create the drawing context */
     gcv.graphics_exposures = False;
     data->gc =
-        XCreateGC(data->display, data->xwindow, GCGraphicsExposures, &gcv);
+        XCreateGC(data->display, data->drawable, GCGraphicsExposures, &gcv);
     if (!data->gc) {
         X11_DestroyRenderer(renderer);
         SDL_SetError("XCreateGC() failed");
@@ -288,6 +597,47 @@
     SDL_Window *window = renderer->window;
     int i, n;
 
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    if (data->use_xrender) {
+        XRenderFreePicture(data->display, data->xwindow_pict);
+        
+        data->xwindow_pict_fmt =
+            XRenderFindVisualFormat(data->display, data->visual);
+        data->xwindow_pict =
+            XRenderCreatePicture(data->display, data->xwindow,
+                                 data->xwindow_pict_fmt, 0, NULL);
+        
+        XRenderComposite(data->display,
+                         PictOpClear,
+                         data->xwindow_pict,
+                         None,
+                         data->xwindow_pict,
+                         0, 0,
+                         0, 0,
+                         0, 0,
+                         window->w, window->h);
+        
+        XFreePixmap(data->display, data->stencil);
+        /* Create a clip mask that is used for rendering primitives. */
+        data->stencil = XCreatePixmap(data->display, data->xwindow,
+                                   window->w, window->h, 32);
+        
+        XRenderFreePicture(data->display, data->stencil_pict);
+        data->stencil_pict =
+            XRenderCreatePicture(data->display, data->stencil,
+                                 XRenderFindStandardFormat(data->display,
+                                                           PictStandardARGB32),
+                                 0, NULL);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+        XDamageDestroy(data->display, data->stencil_damage);
+        if (data->use_xdamage) {
+            data->stencil_damage =
+                XDamageCreate(data->display, data->stencil, XDamageReportNonEmpty);
+            XDamageSubtract(data->display, data->stencil_damage, None, data->stencil_parts);
+        }
+#endif
+    }
+#endif
     if (renderer->info.flags & SDL_RENDERER_SINGLEBUFFER) {
         n = 0;
     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
@@ -301,25 +651,170 @@
         if (data->pixmaps[i] != None) {
             XFreePixmap(data->display, data->pixmaps[i]);
             data->pixmaps[i] = None;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+            XRenderFreePicture(data->display, data->pixmap_picts[i]);
+            data->pixmap_picts[i] = None;
+#endif
         }
     }
     for (i = 0; i < n; ++i) {
-        data->pixmaps[i] =
-            XCreatePixmap(data->display, data->xwindow, window->w, window->h,
-                          data->depth);
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (data->use_xrender) {
+            data->pixmaps[i] =
+                XCreatePixmap(data->display,
+                              data->xwindow,
+                              window->w,
+                              window->h,
+                              32);
+        }
+        else
+#endif
+        {
+            data->pixmaps[i] =
+                XCreatePixmap(data->display, data->xwindow, window->w, window->h,
+                              data->depth);
+        }
         if (data->pixmaps[i] == None) {
             SDL_SetError("XCreatePixmap() failed");
             return -1;
         }
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (data->use_xrender) {
+            data->pixmap_picts[i] = 
+                XRenderCreatePicture(data->display,
+                                     data->pixmaps[i],
+                                     XRenderFindStandardFormat(data->display,
+                                                               PictStandardARGB32),
+                                     0, None);
+            if (!data->pixmap_picts[i]) {
+                SDL_SetError("XRenderCreatePicture() failed");
+                return -1;
+            }
+            XRenderComposite(data->display,
+                             PictOpClear,
+                             data->pixmap_picts[i],
+                             None,
+                             data->pixmap_picts[i],
+                             0, 0,
+                             0, 0,
+                             0, 0,
+                             window->w, window->h);
+
+       }
+#endif
     }
     if (n > 0) {
         data->drawable = data->pixmaps[0];
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        data->drawable_pict = data->pixmap_picts[0];
+#endif
     }
     data->current_pixmap = 0;
 
     return 0;
 }
 
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+static void
+SDLMaskToXRenderMask(Uint32 sdl_mask, short *comp, short *compMask) {
+    if (sdl_mask == 0) {
+        *comp = 0;
+        *compMask = 0;
+    } else {
+        (*comp) = 0;
+        (*compMask) = 0;
+        while(!(sdl_mask & 1)) {
+            (*comp)++;
+            sdl_mask >>= 1;
+        }
+        while(sdl_mask & 1) {
+            (*compMask) = ((*compMask) << 1) | 1;
+            sdl_mask >>= 1;
+        }
+    }
+}
+
+static XRenderPictFormat*
+PixelFormatEnumToXRenderPictFormat(SDL_Renderer * renderer, Uint32 format) {
+    XRenderPictFormat* pict_fmt = NULL;
+    X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
+    
+    if (data->use_xrender) {
+
+        int bpp;
+        Uint32 Amask, Rmask, Gmask, Bmask;
+        if(!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
+            SDL_SetError("Unknown pixel format");
+            return NULL;
+        }
+        XRenderPictFormat templ;
+        unsigned long mask = (PictFormatType | PictFormatDepth | PictFormatRed |
+                              PictFormatRedMask | PictFormatGreen | PictFormatGreenMask |
+                              PictFormatBlue | PictFormatBlueMask | PictFormatAlpha |
+                              PictFormatAlphaMask);
+
+        templ.type = PictTypeDirect;
+        templ.depth = bpp;
+        SDLMaskToXRenderMask(Amask, &(templ.direct.alpha), &(templ.direct.alphaMask));
+        SDLMaskToXRenderMask(Rmask, &(templ.direct.red), &(templ.direct.redMask));
+        SDLMaskToXRenderMask(Gmask, &(templ.direct.green), &(templ.direct.greenMask));
+        SDLMaskToXRenderMask(Bmask, &(templ.direct.blue), &(templ.direct.blueMask));
+        pict_fmt = XRenderFindFormat(data->display, mask, &templ, 0);
+    }
+    
+    return pict_fmt;
+}
+
+
+static Visual*
+PixelFormatEnumToVisual(SDL_Renderer * renderer, Uint32 format) {
+    X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
+
+    if (data->use_xrender) {
+        int bpp;
+        Uint32 Amask, Rmask, Gmask, Bmask;
+        SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask);
+
+        XVisualInfo vinfo_templ;
+        long vinfo_mask;
+        int nitems_return;
+
+        vinfo_mask = (VisualDepthMask | VisualRedMaskMask |
+                      VisualGreenMaskMask | VisualBlueMaskMask);
+        vinfo_templ.depth = bpp;
+        vinfo_templ.red_mask = Rmask;
+        vinfo_templ.green_mask = Gmask;
+        vinfo_templ.blue_mask = Bmask;
+
+        XVisualInfo * ret = XGetVisualInfo(data->display, vinfo_mask,
+                                           &vinfo_templ, &nitems_return);
+        
+        if (nitems_return) {
+            return ret[0].visual;
+        }
+    }
+
+    return NULL;
+}
+
+static XRenderColor
+SDLColorToXRenderColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
+    double rd, gd, bd, ad;
+    XRenderColor ret;
+    rd = r / 255.0;
+    gd = g / 255.0;
+    bd = b / 255.0;
+    ad = a / 255.0;
+    
+    ret.red = (unsigned short) (rd * ad * 0xFFFF);
+    ret.green = (unsigned short) (gd * ad * 0xFFFF);
+    ret.blue = (unsigned short) (bd * ad * 0xFFFF);
+    ret.alpha = (unsigned short) (ad * 0xFFFF);
+
+    return ret;
+}
+#endif
+
 static int
 X11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
 {
@@ -328,15 +823,18 @@
     SDL_VideoDisplay *display = window->display;
     X11_TextureData *data;
     int pitch_alignmask = ((renderdata->scanline_pad / 8) - 1);
-
+    XGCValues gcv;
+    
     data = (X11_TextureData *) SDL_calloc(1, sizeof(*data));
     if (!data) {
         SDL_OutOfMemory();
         return -1;
     }
+    data->depth = renderdata->depth;
+    data->visual = renderdata->visual;
+    data->gc = renderdata->gc;
 
     texture->driverdata = data;
-
     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
         data->yuv =
             SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
@@ -345,18 +843,26 @@
         }
         data->format = display->current_mode.format;
     } else {
-        /* The image/pixmap depth must be the same as the window or you
-           get a BadMatch error when trying to putimage or copyarea.
-         */
-        if (texture->format != display->current_mode.format) {
-            SDL_SetError("Texture format doesn't match window format");
-            return -1;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (renderdata->use_xrender)
+        {
+            Uint32 Amask, Rmask, Gmask, Bmask;
+            SDL_PixelFormatEnumToMasks(texture->format, &(data->depth),
+                                       &Rmask, &Gmask, &Bmask, &Amask);
+            data->visual = PixelFormatEnumToVisual(renderer, texture->format);
+        }
+        else
+#endif
+        {
+            if (texture->format != display->current_mode.format)
+            {
+                SDL_SetError("Texture format doesn't match window format");
+                return -1;
+            }
         }
         data->format = texture->format;
     }
-    data->pitch = texture->w * SDL_BYTESPERPIXEL(data->format);
-    data->pitch = (data->pitch + pitch_alignmask) & ~pitch_alignmask;
-
+    
     if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) {
 #ifndef NO_SHARED_MEMORY
         XShmSegmentInfo *shminfo = &data->shminfo;
@@ -364,37 +870,42 @@
         shm_error = True;
 
         if (SDL_X11_HAVE_SHM) {
-            shminfo->shmid =
-                shmget(IPC_PRIVATE, texture->h * data->pitch,
-                       IPC_CREAT | 0777);
-            if (shminfo->shmid >= 0) {
-                shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
-                shminfo->readOnly = False;
-                if (shminfo->shmaddr != (char *) -1) {
-                    shm_error = False;
-                    X_handler = XSetErrorHandler(shm_errhandler);
-                    XShmAttach(renderdata->display, shminfo);
-                    XSync(renderdata->display, False);
-                    XSetErrorHandler(X_handler);
-                    if (shm_error) {
-                        shmdt(shminfo->shmaddr);
+            data->image =
+                XShmCreateImage(renderdata->display, data->visual,
+                                data->depth, ZPixmap, NULL,
+                                shminfo, texture->w, texture->h);
+            if (data->image) {
+                shminfo->shmid =
+                    shmget(IPC_PRIVATE, texture->h * data->image->bytes_per_line,
+                           IPC_CREAT | 0777);
+                if (shminfo->shmid >= 0) {
+                    shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
+                    shminfo->readOnly = False;
+                    if (shminfo->shmaddr != (char *) -1) {
+                        shm_error = False;
+                        X_handler = XSetErrorHandler(shm_errhandler);
+                        XShmAttach(renderdata->display, shminfo);
+                        XSync(renderdata->display, False);
+                        XSetErrorHandler(X_handler);
+                        if (shm_error) {
+                            XShmDetach(renderdata->display, shminfo);
+                            shmdt(shminfo->shmaddr);
+                            XDestroyImage(data->image);
+                            XSync(renderdata->display, False);
+                        }
+                        else {
+                            data->pixels = data->image->data = shminfo->shmaddr;
+                            shmctl(shminfo->shmid, IPC_RMID, NULL);
+                            data->pixmap =
+                                XCreatePixmap(renderdata->display, renderdata->xwindow,
+                                              texture->w, texture->h, data->depth);
+                            if (!data->pixmap) {
+                                SDL_SetError("XCreatePixmap() failed");
+                                return -1;
+                            }
+                        }
                     }
                 }
-                shmctl(shminfo->shmid, IPC_RMID, NULL);
-            }
-        }
-        if (!shm_error) {
-            data->pixels = shminfo->shmaddr;
-
-            data->image =
-                XShmCreateImage(renderdata->display, renderdata->visual,
-                                renderdata->depth, ZPixmap, shminfo->shmaddr,
-                                shminfo, texture->w, texture->h);
-            if (!data->image) {
-                XShmDetach(renderdata->display, shminfo);
-                XSync(renderdata->display, False);
-                shmdt(shminfo->shmaddr);
-                shm_error = True;
             }
         }
         if (shm_error) {
@@ -403,47 +914,102 @@
         if (!data->image)
 #endif /* not NO_SHARED_MEMORY */
         {
-            data->pixels = SDL_malloc(texture->h * data->pitch);
-            if (!data->pixels) {
-                X11_DestroyTexture(renderer, texture);
-                SDL_OutOfMemory();
-                return -1;
-            }
-
             data->image =
-                XCreateImage(renderdata->display, renderdata->visual,
-                             renderdata->depth, ZPixmap, 0, data->pixels,
+                XCreateImage(renderdata->display, data->visual,
+                             data->depth, ZPixmap, 0, NULL,
                              texture->w, texture->h,
                              SDL_BYTESPERPIXEL(data->format) * 8,
-                             data->pitch);
+                             0);
             if (!data->image) {
                 X11_DestroyTexture(renderer, texture);
                 SDL_SetError("XCreateImage() failed");
                 return -1;
             }
+            data->pixels = SDL_malloc(texture->h * data->image->bytes_per_line);
+            if (!data->pixels) {
+                X11_DestroyTexture(renderer, texture);
+                SDL_OutOfMemory();
+                return -1;
+            }
+            data->image->data = data->pixels;
+            data->pixmap =
+                XCreatePixmap(renderdata->display, renderdata->xwindow, texture->w,
+                              texture->h, data->depth);
+            if (data->pixmap == None) {
+                X11_DestroyTexture(renderer, texture);
+                SDL_SetError("XCreatePixmap() failed");
+                return -1;
+            }
         }
-    } else {
+    } 
+    else {
+        data->image =
+            XCreateImage(renderdata->display, data->visual,
+                         data->depth, ZPixmap, 0, NULL,
+                         texture->w, texture->h,
+                         SDL_BYTESPERPIXEL(data->format) * 8,
+                         0);
+        if (!data->image) {
+            X11_DestroyTexture(renderer, texture);
+            SDL_SetError("XCreateImage() failed");
+            return -1;
+        }
         data->pixmap =
             XCreatePixmap(renderdata->display, renderdata->xwindow, texture->w,
-                          texture->h, renderdata->depth);
+                          texture->h, data->depth);
         if (data->pixmap == None) {
             X11_DestroyTexture(renderer, texture);
             SDL_SetError("XCreatePixmap() failed");
             return -1;
         }
+    }
 
-        data->image =
-            XCreateImage(renderdata->display, renderdata->visual,
-                         renderdata->depth, ZPixmap, 0, NULL, texture->w,
-                         texture->h, SDL_BYTESPERPIXEL(data->format) * 8,
-                         data->pitch);
-        if (!data->image) {
+    data->pitch = data->image->bytes_per_line;
+
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    if(renderdata->use_xrender) {
+        gcv.graphics_exposures = False;
+        data->gc =
+            XCreateGC(renderdata->display, data->pixmap, GCGraphicsExposures, &gcv);
+        if (!data->gc) {
+            SDL_SetError("XCreateGC() failed");
+            return -1;
+        }
+        data->picture_fmt =
+            PixelFormatEnumToXRenderPictFormat(renderer, texture->format);
+        if (data->picture_fmt == NULL) {
             X11_DestroyTexture(renderer, texture);
-            SDL_SetError("XCreateImage() failed");
+            SDL_SetError("Texture format not supported by driver");
             return -1;
         }
+        data->picture =
+            XRenderCreatePicture(renderdata->display, data->pixmap,
+                                 data->picture_fmt, 0, NULL);
+        if (!data->picture) {
+            X11_DestroyTexture(renderer, texture);
+            SDL_SetError("XRenderCreatePicture() failed");
+            return -1;
+        }
+        data->modulated_pixmap =
+            XCreatePixmap(renderdata->display, renderdata->xwindow,
+                          texture->w, texture->h, data->depth);
+        if (!data->modulated_pixmap) {
+            X11_DestroyTexture(renderer, texture);
+            SDL_SetError("XCreatePixmap() failed");
+            return -1;
+        }
+        data->modulated_picture =
+            XRenderCreatePicture(renderdata->display, data->modulated_pixmap,
+                                 data->picture_fmt, 0, NULL);
+        if (!data->modulated_picture) {
+            X11_DestroyTexture(renderer, texture);
+            SDL_SetError("XRenderCreatePicture() failed");
+            return -1;
+        }
+        texture->blendMode = SDL_BLENDMODE_NONE;
+        data->blend_op = PictOpSrc;
     }
-
+#endif
     return 0;
 }
 
@@ -463,14 +1029,106 @@
 }
 
 static int
+X11_SetTextureRGBAMod(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+
+    X11_TextureData *data = (X11_TextureData *) texture->driverdata;
+    X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata;
+
+    if (renderdata->use_xrender) {
+
+        Uint8 r = 0xFF, g = 0xFF, b = 0xFF, a = 0xFF;
+
+        /* Check if alpha modulation is required. */
+        if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) {
+            a = texture->a;
+        }
+
+        /* Check if color modulation is required. */
+        if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
+            r = texture->r;
+            g = texture->g;
+            b = texture->b;
+        }
+
+        /* We can save some labour if no modulation is required. */
+        if (texture->modMode != SDL_TEXTUREMODULATE_NONE) {
+            XRenderColor mod_color =
+                SDLColorToXRenderColor(r, g, b, a);
+            XRenderFillRectangle(renderdata->display, PictOpSrc,
+                                 renderdata->brush_pict, &mod_color,
+                                 0, 0, 1, 1);
+        }
+
+        /* We can save some labour dealing with component alpha
+         * if color modulation is not required. */
+        XRenderPictureAttributes attr;
+        if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
+            attr.component_alpha = True;
+            XRenderChangePicture(renderdata->display, renderdata->brush_pict,
+                                 CPComponentAlpha, &attr);
+        }
+
+        /* Again none of this is necessary is no modulation
+         * is required. */
+        if (texture->modMode != SDL_TEXTUREMODULATE_NONE) {
+            XRenderComposite(renderdata->display, PictOpSrc,
+                             data->picture, renderdata->brush_pict,
+                             data->modulated_picture,
+                             0, 0, 0, 0, 0, 0, texture->w, texture->h);
+        }
+
+        /* We only need to reset the component alpha
+         * attribute if color modulation is required. */
+        if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) { 
+            attr.component_alpha = False;
+            XRenderChangePicture(renderdata->display, renderdata->brush_pict,
+                                 CPComponentAlpha, &attr);
+        }
+
+        return 0;
+    }
+    else {
+        SDL_Unsupported();
+        return -1;
+    }
+}
+
+static int
 X11_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
 {
+    X11_TextureData *data = (X11_TextureData *) texture->driverdata;
+    X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata;
     switch (texture->blendMode) {
     case SDL_BLENDMODE_NONE:
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (renderdata->use_xrender) {
+            data->blend_op = PictOpSrc;
+            return 0;
+        }
+    case SDL_BLENDMODE_MOD:
+    case SDL_BLENDMODE_MASK:
+    case SDL_BLENDMODE_BLEND:
+        if (renderdata->use_xrender) {
+            data->blend_op = PictOpOver;
+            return 0;
+        }
+    case SDL_BLENDMODE_ADD:
+        if (renderdata->use_xrender) {
+            data->blend_op = PictOpAdd;
+            return 0;
+        }
+#endif
         return 0;
     default:
         SDL_Unsupported();
         texture->blendMode = SDL_BLENDMODE_NONE;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (renderdata->use_xrender) {
+            texture->blendMode = SDL_BLENDMODE_BLEND;
+            data->blend_op = PictOpOver;
+        }
+#endif
         return -1;
     }
 }
@@ -479,6 +1137,7 @@
 X11_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
 {
     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
+    X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata;
 
     switch (texture->scaleMode) {
     case SDL_TEXTURESCALEMODE_NONE:
@@ -488,10 +1147,33 @@
         if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) {
             return 0;
         }
-        /* Fall through to unsupported case */
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (renderdata->use_xrender) {
+            data->filter = FilterFast;
+            return 0;
+        }
+    case SDL_TEXTURESCALEMODE_SLOW:
+        if (renderdata->use_xrender) {
+            data->filter = FilterGood;
+            return 0;
+        }
+    case SDL_TEXTURESCALEMODE_BEST:
+        if (renderdata->use_xrender) {
+            data->filter = FilterBest;
+            return 0;
+        }
+#endif
+    /* Fall through to unsupported case */
     default:
         SDL_Unsupported();
-        texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (renderdata->use_xrender) {
+            texture->scaleMode = SDL_TEXTURESCALEMODE_FAST;
+            data->filter = FilterFast;
+        }
+        else
+#endif
+            texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
         return -1;
     }
     return 0;
@@ -532,7 +1214,7 @@
             data->image->height = rect->h;
             data->image->data = (char *) pixels;
             data->image->bytes_per_line = pitch;
-            XPutImage(renderdata->display, data->pixmap, renderdata->gc,
+            XPutImage(renderdata->display, data->pixmap, data->gc,
                       data->image, 0, 0, rect->x, rect->y, rect->w, rect->h);
         }
         return 0;
@@ -575,12 +1257,36 @@
 static int
 X11_SetDrawBlendMode(SDL_Renderer * renderer)
 {
+    X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
     switch (renderer->blendMode) {
     case SDL_BLENDMODE_NONE:
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        //PictOpSrc
+        data->blend_op = PictOpSrc;
+        return 0;
+    case SDL_BLENDMODE_MOD:
+    case SDL_BLENDMODE_MASK:
+    case SDL_BLENDMODE_BLEND: // PictOpOver
+        data->blend_op = PictOpOver;
+        return 0;
+    case SDL_BLENDMODE_ADD: // PictOpAdd
+        data->blend_op = PictOpAdd;
+        return 0;
+    /* FIXME case SDL_BLENDMODE_MOD: */
+#endif
         return 0;
     default:
         SDL_Unsupported();
-        renderer->blendMode = SDL_BLENDMODE_NONE;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if(data->use_xrender) {
+            renderer->blendMode = SDL_BLENDMODE_BLEND;
+            data->blend_op = PictOpOver;
+        }
+        else
+#endif
+        {
+            renderer->blendMode = SDL_BLENDMODE_NONE;
+        }
         return -1;
     }
 }
@@ -601,16 +1307,35 @@
         return SDL_MapRGBA(&data->format, r, g, b, a);
 }
 
+static XRenderColor
+xrenderdrawcolor(SDL_Renderer *renderer)
+{
+    XRenderColor xrender_color;
+    if(renderer->blendMode == SDL_BLENDMODE_NONE) {
+        xrender_color =
+            SDLColorToXRenderColor(renderer->r, renderer->g, renderer->b, 0xFF);
+    }
+    else {
+        xrender_color =
+            SDLColorToXRenderColor(renderer->r, renderer->g, renderer->b, renderer->a);
+    }
+    return xrender_color;
+}
+
 static int
 X11_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
                      int count)
 {
     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
     SDL_Window *window = renderer->window;
-    unsigned long foreground;
     XPoint *xpoints, *xpoint;
     int i, xcount;
+    SDL_Rect clip;
 
+    clip.x = 0;
+    clip.y = 0;
+    clip.w = window->w;
+    clip.h = window->h;
     if (data->makedirty) {
         SDL_Rect rect;
 
@@ -625,27 +1350,105 @@
         }
         SDL_AddDirtyRect(&data->dirty, &rect);
     }
+    {
+        xpoint = xpoints = SDL_stack_alloc(XPoint, count);
+        xcount = 0;
+        for (i = 0; i < count; ++i) {
+            int x = points[i].x;
+            int y = points[i].y;
+            if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
+                continue;
+            }
+            xpoint->x = (short)x;
+            xpoint->y = (short)y;
+            ++xpoint;
+            ++xcount;
+        }
 
-    foreground = renderdrawcolor(renderer, 1);
-    XSetForeground(data->display, data->gc, foreground);
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (data->use_xrender &&
+            (renderer->blendMode != SDL_BLENDMODE_NONE) &&
+            !(renderer->a == 0xFF &&
+              renderer->blendMode != SDL_BLENDMODE_ADD &&
+              renderer->blendMode != SDL_BLENDMODE_MOD))
+        {
+            XSetForeground(data->display, data->stencil_gc, 0);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+            if (data->use_xdamage)
+            {
+                /* Update only those parts which were changed
+                * in the previous drawing operation */
+                XFixesSetGCClipRegion(data->display, data->stencil_gc,
+                                      0, 0, data->stencil_parts);
+            }
+#endif
+            XFillRectangle(data->display, data->stencil, data->stencil_gc,
+                           0, 0, window->w, window->h);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+            if (data->use_xdamage)
+            {
+                XFixesSetGCClipRegion(data->display, data->stencil_gc, 0, 0, None);
+            }
+#endif
+            XSetForeground(data->display, data->stencil_gc, 0xFFFFFFFF);
 
-    xpoint = xpoints = SDL_stack_alloc(XPoint, count);
-    xcount = 0;
-    for (i = 0; i < count; ++i) {
-        int x = points[i].x;
-        int y = points[i].y;
-        if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
-            continue;
+            XDrawPoints(data->display, data->stencil, data->stencil_gc, xpoints, xcount,
+                        CoordModeOrigin);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+            if (data->use_xdamage)
+            {
+                /* Store the damaged region in stencil_parts */
+                XDamageSubtract(data->display, data->stencil_damage, None, data->stencil_parts);
+            }
+#endif
         }
-        xpoint->x = (short)x;
-        xpoint->y = (short)y;
-        ++xpoint;
-        ++xcount;
+#endif
     }
-    if (xcount > 0) {
-        XDrawPoints(data->display, data->drawable, data->gc, xpoints, xcount,
-                    CoordModeOrigin);
+
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    if (data->use_xrender &&
+            (renderer->blendMode != SDL_BLENDMODE_NONE) &&
+            !(renderer->a == 0xFF &&
+              renderer->blendMode != SDL_BLENDMODE_ADD &&
+              renderer->blendMode != SDL_BLENDMODE_MOD))
+    {
+        XRenderColor foreground;
+        foreground = xrenderdrawcolor(renderer);
+
+        XRenderFillRectangle(data->display, PictOpSrc, data->brush_pict,
+                             &foreground, 0, 0, 1, 1);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+        if (data->use_xdamage)
+        {
+            /* Update only those parts which drawn
+             * to in the current drawing operation */
+            XFixesSetPictureClipRegion(data->display, data->drawable_pict,
+                                       0, 0, data->stencil_parts);
+        }
+#endif
+        XRenderComposite(data->display, data->blend_op, data->brush_pict,
+                         data->stencil_pict, data->drawable_pict,
+                         0, 0, 0, 0, 0, 0, window->w, window->h);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+        if (data->use_xdamage)
+        {
+            XFixesSetPictureClipRegion(data->display, data->drawable_pict, 0, 0, None);
+        }
+#endif
     }
+    else
+#endif
+    {
+        unsigned long foreground = renderdrawcolor(renderer, 1);
+        XSetForeground(data->display, data->gc, foreground);
+
+
+        if (xcount > 0) {
+            XDrawPoints(data->display, data->drawable, data->gc, xpoints, xcount,
+                        CoordModeOrigin);
+        }
+    }
+
     SDL_stack_free(xpoints);
 
     return 0;
@@ -668,65 +1471,146 @@
     clip.y = 0;
     clip.w = window->w;
     clip.h = window->h;
-
-    foreground = renderdrawcolor(renderer, 1);
-    XSetForeground(data->display, data->gc, foreground);
-
-    xpoint = xpoints = SDL_stack_alloc(XPoint, count);
-    xcount = 0;
-    minx = INT_MAX;
-    miny = INT_MAX;
-    maxx = INT_MIN;
-    maxy = INT_MIN;
-    for (i = 0; i < count; ++i) {
-        int x = points[i].x;
-        int y = points[i].y;
+    {
+        Pixmap drawable;
+        GC gc;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+       if (data->use_xrender &&
+            (renderer->blendMode != SDL_BLENDMODE_NONE) &&
+            !(renderer->a == 0xFF &&
+              renderer->blendMode != SDL_BLENDMODE_ADD &&
+              renderer->blendMode != SDL_BLENDMODE_MOD))
+       { 
+            drawable = data->stencil;
+            gc = data->stencil_gc;
 
-        /* If the point is inside the window, add it to the list */
-        if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
-            if (x < minx) {
-                minx = x;
-            } else if (x > maxx) {
-                maxx = x;
-            }
-            if (y < miny) {
-                miny = y;
-            } else if (y > maxy) {
-                maxy = y;
-            }
-            xpoint->x = (short)x;
-            xpoint->y = (short)y;
-            ++xpoint;
-            ++xcount;
-            continue;
+            XSetForeground(data->display, data->stencil_gc, 0);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+            if (data->use_xdamage)
+                XFixesSetGCClipRegion(data->display, data->stencil_gc,
+                                      0, 0, data->stencil_parts);
+#endif
+            XFillRectangle(data->display, data->stencil, data->stencil_gc,
+                           0, 0, window->w, window->h);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+            if (data->use_xdamage)
+                XFixesSetGCClipRegion(data->display, data->stencil_gc,
+                                      0, 0, None);
+#endif
+            XSetForeground(data->display, data->stencil_gc, 0xFFFFFFFF);
+        }
+        else
+#endif
+        {
+            drawable = data->drawable;
+            gc = data->gc;
         }
 
-        /* We need to clip the line segments joined by this point */
-        if (xcount > 0) {
-            int x1 = xpoint[-1].x;
-            int y1 = xpoint[-1].y;
-            int x2 = x;
-            int y2 = y;
-            if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) {
-                if (x2 < minx) {
-                    minx = x2;
-                } else if (x2 > maxx) {
-                    maxx = x2;
+        foreground = renderdrawcolor(renderer, 1);
+        XSetForeground(data->display, data->gc, foreground);
+
+        xpoint = xpoints = SDL_stack_alloc(XPoint, count);
+        xcount = 0;
+        minx = INT_MAX;
+        miny = INT_MAX;
+        maxx = INT_MIN;
+        maxy = INT_MIN;
+        for (i = 0; i < count; ++i) {
+            int x = points[i].x;
+            int y = points[i].y;
+
+            /* If the point is inside the window, add it to the list */
+            if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
+                if (x < minx) {
+                    minx = x;
+                } else if (x > maxx) {
+                    maxx = x;
                 }
-                if (y2 < miny) {
-                    miny = y2;
-                } else if (y2 > maxy) {
-                    maxy = y2;
+                if (y < miny) {
+                    miny = y;
+                } else if (y > maxy) {
+                    maxy = y;
                 }
-                xpoint->x = (short)x2;
-                xpoint->y = (short)y2;
+                xpoint->x = (short)x;
+                xpoint->y = (short)y;
                 ++xpoint;
                 ++xcount;
+                continue;
             }
-            XDrawLines(data->display, data->drawable, data->gc,
-                       xpoints, xcount, CoordModeOrigin);
+
+            /* We need to clip the line segments joined by this point */
+            if (xcount > 0) {
+                int x1 = xpoint[-1].x;
+                int y1 = xpoint[-1].y;
+                int x2 = x;
+                int y2 = y;
+                if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) {
+                    if (x2 < minx) {
+                        minx = x2;
+                    } else if (x2 > maxx) {
+                        maxx = x2;
+                    }
+                    if (y2 < miny) {
+                        miny = y2;
+                    } else if (y2 > maxy) {
+                        maxy = y2;
+                    }
+                    xpoint->x = (short)x2;
+                    xpoint->y = (short)y2;
+                    ++xpoint;
+                    ++xcount;
+                }
+                XDrawLines(data->display, drawable, gc,
+                           xpoints, xcount, CoordModeOrigin);
+                if (xpoints[0].x != x2 || xpoints[0].y != y2) {
+                    XDrawPoint(data->display, drawable, gc, x2, y2);
+                }
+                if (data->makedirty) {
+                    SDL_Rect rect;
+
+                    rect.x = minx;
+                    rect.y = miny;
+                    rect.w = (maxx - minx) + 1;
+                    rect.h = (maxy - miny) + 1;
+                    SDL_AddDirtyRect(&data->dirty, &rect);
+                }
+                xpoint = xpoints;
+                xcount = 0;
+                minx = INT_MAX;
+                miny = INT_MAX;
+                maxx = INT_MIN;
+                maxy = INT_MIN;
+            }
+            if (i < (count-1)) {
+                int x1 = x;
+                int y1 = y;
+                int x2 = points[i+1].x;
+                int y2 = points[i+1].y;
+                if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) {
+                    if (x1 < minx) {
+                        minx = x1;
+                    } else if (x1 > maxx) {
+                        maxx = x1;
+                    }
+                    if (y1 < miny) {
+                        miny = y1;
+                    } else if (y1 > maxy) {
+                        maxy = y1;
+                    }
+                    xpoint->x = (short)x1;
+                    xpoint->y = (short)y1;
+                    ++xpoint;
+                    ++xcount;
+                }
+            }
+        }
+        if (xcount > 1) {
+            int x2 = xpoint[-1].x;
+            int y2 = xpoint[-1].y;
+            XDrawLines(data->display, drawable, gc, xpoints, xcount,
+                       CoordModeOrigin);
             if (xpoints[0].x != x2 || xpoints[0].y != y2) {
-                XDrawPoint(data->display, data->drawable, data->gc, x2, y2);
+                XDrawPoint(data->display, drawable, gc, x2, y2);
             }
             if (data->makedirty) {
                 SDL_Rect rect;
@@ -737,54 +1621,37 @@
                 rect.h = (maxy - miny) + 1;
                 SDL_AddDirtyRect(&data->dirty, &rect);
             }
-            xpoint = xpoints;
-            xcount = 0;
-            minx = INT_MAX;
-            miny = INT_MAX;
-            maxx = INT_MIN;
-            maxy = INT_MIN;
-        }
-        if (i < (count-1)) {
-            int x1 = x;
-            int y1 = y;
-            int x2 = points[i+1].x;
-            int y2 = points[i+1].y;
-            if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) {
-                if (x1 < minx) {
-                    minx = x1;
-                } else if (x1 > maxx) {
-                    maxx = x1;
-                }
-                if (y1 < miny) {
-                    miny = y1;
-                } else if (y1 > maxy) {
-                    maxy = y1;
-                }
-                xpoint->x = (short)x1;
-                xpoint->y = (short)y1;
-                ++xpoint;
-                ++xcount;
-            }
         }
     }
-    if (xcount > 1) {
-        int x2 = xpoint[-1].x;
-        int y2 = xpoint[-1].y;
-        XDrawLines(data->display, data->drawable, data->gc, xpoints, xcount,
-                   CoordModeOrigin);
-        if (xpoints[0].x != x2 || xpoints[0].y != y2) {
-            XDrawPoint(data->display, data->drawable, data->gc, x2, y2);
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    if (data->use_xrender &&
+            (renderer->blendMode != SDL_BLENDMODE_NONE) &&
+            !(renderer->a == 0xFF &&
+              renderer->blendMode != SDL_BLENDMODE_ADD &&
+              renderer->blendMode != SDL_BLENDMODE_MOD))
+    {
+        XRenderColor xrforeground = xrenderdrawcolor(renderer);
+        XRenderFillRectangle(data->display, PictOpSrc, data->brush_pict,
+                             &xrforeground, 0, 0, 1, 1);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+        if (data->use_xdamage)
+        {
+            XDamageSubtract(data->display, data->stencil_damage, None, data->stencil_parts);
+
+            XFixesSetPictureClipRegion(data->display, data->drawable_pict,
+                                       0, 0, data->stencil_parts);
         }
-        if (data->makedirty) {
-            SDL_Rect rect;
-
-            rect.x = minx;
-            rect.y = miny;
-            rect.w = (maxx - minx) + 1;
-            rect.h = (maxy - miny) + 1;
-            SDL_AddDirtyRect(&data->dirty, &rect);
-        }
+#endif
+        XRenderComposite(data->display, data->blend_op, data->brush_pict,
+                         data->stencil_pict, data->drawable_pict,
+                         0, 0, 0, 0, 0, 0, window->w, window->h);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+        if (data->use_xdamage)
+            XFixesSetPictureClipRegion(data->display, data->drawable_pict,
+                                       0, 0, None);
+#endif
     }
+#endif
     SDL_stack_free(xpoints);
 
     return 0;
@@ -796,18 +1663,122 @@
     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
     SDL_Window *window = renderer->window;
     SDL_Rect clip, rect;
-    unsigned long foreground;
+    int i, xcount;
     XRectangle *xrects, *xrect;
-    int i, xcount;
-
+    xrect = xrects = SDL_stack_alloc(XRectangle, count);
+    xcount = 0;
+    
     clip.x = 0;
     clip.y = 0;
     clip.w = window->w;
     clip.h = window->h;
+    {
 
-    foreground = renderdrawcolor(renderer, 1);
-    XSetForeground(data->display, data->gc, foreground);
+        for (i = 0; i < count; ++i) {
+            if (!SDL_IntersectRect(rects[i], &clip, &rect)) {
+                continue;
+            }
+
+            xrect->x = (short)rect.x;
+            xrect->y = (short)rect.y;
+            xrect->width = (unsigned short)rect.w - 1;
+            xrect->height = (unsigned short)rect.h - 1;
+            ++xrect;
+            ++xcount;
+
+            if (data->makedirty) {
+                SDL_AddDirtyRect(&data->dirty, &rect);
+            }
+        }
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (data->use_xrender &&
+            (renderer->blendMode != SDL_BLENDMODE_NONE) &&
+            !(renderer->a == 0xFF &&
+              renderer->blendMode != SDL_BLENDMODE_ADD &&
+              renderer->blendMode != SDL_BLENDMODE_MOD))
+        {
+            XSetForeground(data->display, data->stencil_gc, 0);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+            if (data->use_xdamage)
+                XFixesSetGCClipRegion(data->display, data->stencil_gc,
+                                      0, 0, data->stencil_parts);
+#endif
+            XFillRectangle(data->display, data->stencil, data->stencil_gc,
+                           0, 0, window->w, window->h);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+            if (data->use_xdamage)
+                XFixesSetGCClipRegion(data->display, data->stencil_gc,
+                                      0, 0, None);
+#endif
+            XSetForeground(data->display, data->stencil_gc, 0xFFFFFFFF);
+
+            XDrawRectangles(data->display, data->stencil, data->stencil_gc, xrects, xcount);
 
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+            if (data->use_xdamage)
+                XDamageSubtract(data->display, data->stencil_damage,
+                                None, data->stencil_parts);
+#endif
+        }
+#endif
+    }
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    if (data->use_xrender &&
+            (renderer->blendMode != SDL_BLENDMODE_NONE) &&
+            !(renderer->a == 0xFF &&
+              renderer->blendMode != SDL_BLENDMODE_ADD &&
+              renderer->blendMode != SDL_BLENDMODE_MOD))
+    {
+        XRenderColor foreground;
+        foreground = xrenderdrawcolor(renderer);
+        XRenderFillRectangle(data->display, PictOpSrc, data->brush_pict,
+                             &foreground, 0, 0, 1, 1);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+        if (data->use_xdamage)
+            XFixesSetPictureClipRegion(data->display, data->drawable_pict,
+                                       0, 0, data->stencil_parts);
+#endif
+        XRenderComposite(data->display, data->blend_op, data->brush_pict,
+                         data->stencil_pict, data->drawable_pict,
+                         0, 0, 0, 0, 0, 0, window->w, window->h);
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+        if (data->use_xdamage)
+            XFixesSetPictureClipRegion(data->display, data->drawable_pict,
+                                       0, 0, None);
+#endif
+    }
+    else
+#endif
+    {
+        unsigned long foreground;
+        
+        foreground = renderdrawcolor(renderer, 1);
+        XSetForeground(data->display, data->gc, foreground);
+    
+        if (xcount > 0) {
+            XDrawRectangles(data->display, data->drawable, data->gc,
+                            xrects, xcount);
+        }
+    }
+    SDL_stack_free(xrects);
+
+    return 0;
+}
+
+static int
+X11_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
+{
+    X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
+    SDL_Window *window = renderer->window;
+    SDL_Rect clip, rect;
+    
+    clip.x = 0;
+    clip.y = 0;
+    clip.w = window->w;
+    clip.h = window->h;
+    
+    int i, xcount;
+    XRectangle *xrects, *xrect;
     xrect = xrects = SDL_stack_alloc(XRectangle, count);
     xcount = 0;
     for (i = 0; i < count; ++i) {
@@ -826,57 +1797,34 @@
             SDL_AddDirtyRect(&data->dirty, &rect);
         }
     }
-    if (xcount > 0) {
-        XDrawRectangles(data->display, data->drawable, data->gc,
-                        xrects, xcount);
-    }
-    SDL_stack_free(xpoints);
 
-    return 0;
-}
-
-static int
-X11_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
-{
-    X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
-    SDL_Window *window = renderer->window;
-    SDL_Rect clip, rect;
-    unsigned long foreground;
-    XRectangle *xrects, *xrect;
-    int i, xcount;
-
-    clip.x = 0;
-    clip.y = 0;
-    clip.w = window->w;
-    clip.h = window->h;
-
-    foreground = renderdrawcolor(renderer, 1);
-    XSetForeground(data->display, data->gc, foreground);
-
-    xrect = xrects = SDL_stack_alloc(XRectangle, count);
-    xcount = 0;
-    for (i = 0; i < count; ++i) {
-        if (!SDL_IntersectRect(rects[i], &clip, &rect)) {
-            continue;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    if (data->use_xrender) {
+        XRenderColor foreground;
+        foreground = xrenderdrawcolor(renderer);
+        if (xcount == 1) {
+            XRenderFillRectangle(data->display, data->blend_op, data->drawable_pict,
+                                 &foreground, xrects[0].x, xrects[0].y,
+                                 xrects[0].width, xrects[0].height);
         }
-
-        xrect->x = (short)rect.x;
-        xrect->y = (short)rect.y;
-        xrect->width = (unsigned short)rect.w;
-        xrect->height = (unsigned short)rect.h;
-        ++xrect;
-        ++xcount;
-
-        if (data->makedirty) {
-            SDL_AddDirtyRect(&data->dirty, &rect);
+        else if (xcount > 1) {
+            XRenderFillRectangles(data->display, data->blend_op, data->drawable_pict,
+                                  &foreground, xrects, xcount);
         }
     }
-    if (xcount > 0) {
+    else
+#endif
+    {
+        unsigned long foreground;
+        
+        foreground = renderdrawcolor(renderer, 1);
+        XSetForeground(data->display, data->gc, foreground);
+ 
         XFillRectangles(data->display, data->drawable, data->gc,
                         xrects, xcount);
     }
-    SDL_stack_free(xpoints);
 
+    SDL_stack_free(xrects);
     return 0;
 }
 
@@ -890,103 +1838,206 @@
     if (data->makedirty) {
         SDL_AddDirtyRect(&data->dirty, dstrect);
     }
-    if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) {
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    if (data->use_xrender) {
+        if(texture->access == SDL_TEXTUREACCESS_STREAMING) {
 #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, texturedata->pixmap, texturedata->gc,
+                             texturedata->image, srcrect->x, srcrect->y,
+                             srcrect->x, srcrect->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, texturedata->pixmap, texturedata->gc,
+                          texturedata->image, srcrect->x, srcrect->y, srcrect->x,
+                          srcrect->y, srcrect->w, srcrect->h);
+            }
+            XSync(data->display, False);
+        }
+        Picture src, mask;
+        XRenderPictureAttributes attr;
+        const SDL_Rect *mrect;
+
+        if (texture->modMode == SDL_TEXTUREMODULATE_NONE) {
+            src = texturedata->picture;
+        }
+        else {
+            src = texturedata->modulated_picture;
+        }
+
+        if(texture->blendMode == SDL_BLENDMODE_NONE) 
+        {
+            mask = None;
+            mrect = srcrect;
+        }
+        else if (texture->blendMode == SDL_BLENDMODE_MOD)
+        {
+            mask = data->stencil_pict;
+            mrect = dstrect;
+        }
+        else
+        {
+            mask = texturedata->picture;
+            mrect = srcrect;
+        }
+
+        if(srcrect->w == dstrect->w && srcrect->h == dstrect->h) {
+            if (texture->blendMode == SDL_BLENDMODE_MOD) {
+                XRenderComposite(data->display, PictOpSrc, data->drawable_pict,
+                             src, data->stencil_pict,
+                             dstrect->x, dstrect->y, srcrect->x, srcrect->y,
+                             dstrect->x, dstrect->y, dstrect->w, dstrect->h);
+                attr.component_alpha = True;
+                XRenderChangePicture(data->display, data->stencil_pict,
+                                     CPComponentAlpha, &attr);
+            }
+            XRenderComposite(data->display, texturedata->blend_op,
+                            src, mask, data->drawable_pict, srcrect->x, srcrect->y,
+                            mrect->x, mrect->y, 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, dstrect->x, dstrect->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) {
-            void *pixels;
-            int pitch;
-
-            pitch = dstrect->w * SDL_BYTESPERPIXEL(texturedata->format);
-            pixels = SDL_malloc(dstrect->h * pitch);
-            if (!pixels) {
-                SDL_OutOfMemory();
-                return -1;
+            double xscale = ((double) dstrect->w) / srcrect->w;
+            double yscale = ((double) dstrect->h) / srcrect->h;
+            XTransform xform = {{
+                    {XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0)},
+                    {XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0)},
+                    {XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(xscale * yscale)}}};
+            XRenderSetPictureTransform(data->display, src, &xform);
+            
+            if (texture->blendMode == SDL_BLENDMODE_MOD) {
+                XRenderComposite(data->display, PictOpSrc, data->drawable_pict,
+                             src, data->stencil_pict,
+                             dstrect->x, dstrect->y, srcrect->x, srcrect->y,
+                             dstrect->x, dstrect->y, dstrect->w, dstrect->h);
+                attr.component_alpha = True;
+                XRenderChangePicture(data->display, data->stencil_pict,
+                                     CPComponentAlpha, &attr);
             }
 
-            image =
-                XCreateImage(data->display, data->visual, data->depth,
-                             ZPixmap, 0, pixels, dstrect->w, dstrect->h,
-                             SDL_BYTESPERPIXEL(texturedata->format) * 8,
-                             pitch);
+            XRenderSetPictureFilter(data->display, src,
+                                    texturedata->filter, 0, 0);
+
+            XRenderComposite(data->display, texturedata->blend_op,
+                             src, mask, data->drawable_pict,
+                             srcrect->x, srcrect->y, mrect->x, mrect->y,
+                             dstrect->x, dstrect->y, dstrect->w, dstrect->h);
+            
+            XTransform identity = {{
+                    {XDoubleToFixed(1), XDoubleToFixed(0), XDoubleToFixed(0)},
+                    {XDoubleToFixed(0), XDoubleToFixed(1), XDoubleToFixed(0)},
+                    {XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1)}}};
+            XRenderSetPictureTransform(data->display, src, &identity);
+        }
+        if (renderer->blendMode == SDL_BLENDMODE_MOD) {
+            attr.component_alpha = False;
+            XRenderChangePicture(data->display, data->stencil_pict,
+                                 CPComponentAlpha, &attr);
+        }
+    }
+    else
+#endif
+    {
+        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
+#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);
+            } else {
+                XCopyArea(data->display, texturedata->pixmap, data->drawable,
+                          data->gc, srcrect->x, srcrect->y, dstrect->w,
+                          dstrect->h, dstrect->x, dstrect->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) {
-                SDL_SetError("XCreateImage() failed");
+                void *pixels;
+                int pitch;
+
+                pitch = dstrect->w * SDL_BYTESPERPIXEL(texturedata->format);
+                pixels = SDL_malloc(dstrect->h * pitch);
+                if (!pixels) {
+                    SDL_OutOfMemory();
+                    return -1;
+                }
+
+                image =
+                    XCreateImage(data->display, data->visual, data->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() */
+            SDL_zero(src);
+            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;
+
+            SDL_zero(dst);
+            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;
             }
-            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;
-            }
+            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,
+                      srcrect->x, srcrect->y);
         }
-
-        /* Set up fake surfaces for SDL_SoftStretch() */
-        SDL_zero(src);
-        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;
-
-        SDL_zero(dst);
-        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,
-                  srcrect->x, srcrect->y);
     }
     return 0;
 }
@@ -1065,9 +2116,26 @@
     if (!(renderer->info.flags & SDL_RENDERER_SINGLEBUFFER)) {
         for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
             const SDL_Rect *rect = &dirty->rect;
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+            if (data->use_xrender)
+            {
+                XRenderComposite(data->display,
+                                 data->blend_op,
+                                 data->drawable_pict,
+                                 None,
+                                 data->xwindow_pict,
+                                 rect->x, rect->y,
+                                 0, 0,
+                                 rect->x, rect->y,
+                                 rect->w, rect->h);
+            }
+            else
+#endif
+            {
             XCopyArea(data->display, data->drawable, data->xwindow,
                       data->gc, rect->x, rect->y, rect->w, rect->h,
                       rect->x, rect->y);
+            }
         }
         SDL_ClearDirtyRects(&data->dirty);
     }
@@ -1077,9 +2145,15 @@
     if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
         data->current_pixmap = (data->current_pixmap + 1) % 2;
         data->drawable = data->pixmaps[data->current_pixmap];
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        data->drawable_pict = data->pixmap_picts[data->current_pixmap];
+#endif
     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
         data->current_pixmap = (data->current_pixmap + 1) % 3;
         data->drawable = data->pixmaps[data->current_pixmap];
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        data->drawable_pict = data->pixmap_picts[data->current_pixmap];
+#endif
     }
 }
 
@@ -1110,6 +2184,19 @@
         data->pixels = NULL;
     }
 #endif
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+    if (renderdata->use_xrender) {
+        if (data->picture) {
+            XRenderFreePicture(renderdata->display, data->picture);
+        }
+        if (data->modulated_pixmap) {
+            XFreePixmap(renderdata->display, data->modulated_pixmap);
+        }
+        if (data->modulated_picture) {
+            XRenderFreePicture(renderdata->display, data->modulated_picture);
+        }
+    }
+#endif
     if (data->scaling_image) {
         SDL_free(data->scaling_image->data);
         data->scaling_image->data = NULL;
@@ -1133,10 +2220,36 @@
             if (data->pixmaps[i] != None) {
                 XFreePixmap(data->display, data->pixmaps[i]);
             }
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+            if (data->use_xrender && data->pixmap_picts[i]) {
+                XRenderFreePicture(data->display, data->pixmap_picts[i]);
+            }
+#endif
         }
         if (data->gc) {
             XFreeGC(data->display, data->gc);
         }
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+        if (data->use_xrender) {
+            if (data->stencil_gc) {
+                XFreeGC(data->display, data->stencil_gc);
+            }
+            if (data->stencil) {
+                XFreePixmap(data->display, data->stencil);
+            }
+            if (data->stencil_pict) {
+                XRenderFreePicture(data->display, data->stencil_pict);
+            }
+            if (data->xwindow_pict) {
+                XRenderFreePicture(data->display, data->xwindow_pict);
+            }
+#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE
+            if (data->use_xdamage && data->stencil_damage) {
+                XDamageDestroy(data->display, data->stencil_damage);
+            }
+#endif
+        }
+#endif
         SDL_FreeDirtyRects(&data->dirty);
         SDL_free(data);
     }