diff src/video/x11/SDL_x11render.c @ 4593:3892fe2f6537

Fixed so many things. See the changelog listed below. 1. Use SDL_X11_HAVE_XRENDER to check for RENDER at runtime. 2. Added lots of comments. 3. Added checks and lots of calls to SDL_SetError(). 4. Fixed X11_CreateTexture() so that the pixmap and image created are for the format specified by the user and not the window format. This is only for the RENDER case. 5. The above change required that functions to convert SDL pixel format enums to Visuals and XRenderPictFormats be added. 6. Fixed lots of 'style' issues.
author Sunny Sachanandani <sunnysachanandani@gmail.com>
date Sat, 17 Jul 2010 15:38:24 +0530
parents 1e998db9b597
children f28c23cc1a08
line wrap: on
line diff
--- a/src/video/x11/SDL_x11render.c	Sat Jul 17 11:41:43 2010 +0530
+++ b/src/video/x11/SDL_x11render.c	Sat Jul 17 15:38:24 2010 +0530
@@ -120,6 +120,9 @@
     SDL_SW_YUVTexture *yuv;
     Uint32 format;
     Pixmap pixmap;
+    int depth;
+    Visual *visual;
+    GC gc;
 #ifdef SDL_VIDEO_DRIVER_X11_XRENDER
     Picture picture;
     XRenderPictFormat* picture_fmt;
@@ -243,17 +246,32 @@
     renderer->info.flags = SDL_RENDERER_ACCELERATED;
 
 #ifdef SDL_VIDEO_DRIVER_X11_XRENDER
-    int event_basep, error_basep;
-    if(XRenderQueryExtension(data->display,
-                             &event_basep,
-                             &error_basep) == True) {
-        data->use_xrender = SDL_TRUE;
+    data->use_xrender = SDL_FALSE;
+    if (SDL_X11_HAVE_XRENDER) {
+        // Query the extension. This is the server runtime check.
+        int event_basep, error_basep;
+        if(XRenderQueryExtension(data->display,
+                                 &event_basep, &error_basep) == True)
+            data->use_xrender = SDL_TRUE;
+    }
+    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,
@@ -263,27 +281,39 @@
                          0, 0,
                          0, 0,
                          window->w, window->h);
+        // Add some blending modes to the list of supported blending modes
         renderer->info.blend_modes |=
             (SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MASK);
-        // Create a 1 bit depth mask
+        // Create a clip mask that is used for rendering primitives.
         data->mask = XCreatePixmap(data->display, data->xwindow,
                                    window->w, window->h, 1);
+        if (!data->mask) {
+            SDL_SetError("XCreatePixmap() failed");
+            return NULL;
+        }
         data->mask_pict =
             XRenderCreatePicture(data->display, data->mask,
                                  XRenderFindStandardFormat(data->display,
                                                            PictStandardA1),
                                  0, NULL);
+        if (!data->mask_pict) {
+            SDL_SetError("XRenderCreatePicture() failed");
+            return NULL;
+        }
+        // Create the GC for the clip mask.
         XGCValues gcv_mask;
         gcv_mask.foreground = 1;
         gcv_mask.background = 0;
         data->mask_gc = XCreateGC(data->display, data->mask,
                                   GCBackground | GCForeground, &gcv_mask);
+        if (!data->mask_gc) {
+            SDL_SetError("XCreateGC() failed");
+            return NULL;
+        }
+        // Set the default blending mode.
         renderer->blendMode = SDL_BLENDMODE_BLEND;
         data->blend_op = PictOpOver;
     }
-    else {
-        data->use_xrender = SDL_FALSE;
-    }
 #endif
     
     if (flags & SDL_RENDERER_SINGLEBUFFER) {
@@ -322,23 +352,29 @@
             return NULL;
         }
 #ifdef SDL_VIDEO_DRIVER_X11_XRENDER
-        if(data->use_xrender == SDL_TRUE) {
+        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);
-                XRenderComposite(data->display,
-                                 PictOpClear,
-                                 data->pixmap_picts[i],
-                                 None,
-                                 data->pixmap_picts[i],
-                                 0, 0,
-                                 0, 0,
-                                 0, 0,
-                                 window->w, window->h);
+            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
     }
@@ -429,13 +465,17 @@
             return -1;
         }
 #ifdef SDL_VIDEO_DRIVER_X11_XRENDER
-        if(data->use_xrender == SDL_TRUE) {
+        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],
@@ -460,6 +500,84 @@
     return 0;
 }
 
+#ifdef SDL_VIDEO_DRIVER_X11_XRENDER
+static void
+SDLMaskToXRenderMask(Uint32 sdl_mask, short *comp, short *compMask) {
+    (*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;
+        SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask);
+
+        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;
+}
+#endif
+
 static int
 X11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
 {
@@ -468,12 +586,16 @@
     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)) {
@@ -494,6 +616,11 @@
                 SDL_SetError("Texture format doesn't match window format");
                 return -1;
             }
+        } else {
+            Uint32 Amask, Rmask, Gmask, Bmask;
+            SDL_PixelFormatEnumToMasks(texture->format, &(data->depth),
+                                       &Rmask, &Gmask, &Bmask, &Amask);
+            data->visual = PixelFormatEnumToVisual(renderer, texture->format);
         }
 #else
         /* The image/pixmap depth must be the same as the window or you
@@ -540,16 +667,15 @@
             data->pixels = shminfo->shmaddr;
             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 =
-                XShmCreateImage(renderdata->display, renderdata->visual,
-                                renderdata->depth, ZPixmap, shminfo->shmaddr,
+                XShmCreateImage(renderdata->display, data->visual,
+                                data->depth, ZPixmap, shminfo->shmaddr,
                                 shminfo, texture->w, texture->h);
 
             if (!data->image) {
@@ -582,15 +708,15 @@
 
             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, data->pixels,
+                XCreateImage(renderdata->display, data->visual,
+                             data->depth, ZPixmap, 0, data->pixels,
                              texture->w, texture->h,
                              SDL_BYTESPERPIXEL(data->format) * 8,
                              data->pitch);
@@ -604,15 +730,15 @@
     else {
         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,
+            XCreateImage(renderdata->display, data->visual,
+                         data->depth, ZPixmap, 0, NULL,
                          texture->w, texture->h,
                          SDL_BYTESPERPIXEL(data->format) * 8,
                          data->pitch);
@@ -624,21 +750,29 @@
     }
 #ifdef SDL_VIDEO_DRIVER_X11_XRENDER
     if(renderdata->use_xrender) {
-        data->picture_fmt = renderdata->xwindow_pict_fmt;
+        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("Texture format not supported by driver");
+            return -1;
+        }
         data->picture =
             XRenderCreatePicture(renderdata->display, data->pixmap,
                                  data->picture_fmt, 0, NULL);
-    }
-    /* We thought we could render the texture with Xrender but this was
-        not possible for some reason. Now we must ensure that texture  
-        format and window format match to avoid a BadMatch error when
-        rendering using the old pipeline.
-    if(data->use_xrender == SDL_FALSE) {
-        if (texture->format != display->current_mode.format) {
-            SDL_SetError("Texture format doesn't match window format");
+        if (!data->picture) {
+            X11_DestroyTexture(renderer, texture);
+            SDL_SetError("XRenderCreatePicture() failed");
             return -1;
         }
-    }*/
+    }
 #endif
     return 0;
 }
@@ -742,7 +876,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;
@@ -913,6 +1047,10 @@
         XRenderChangePicture(data->display, data->drawable_pict, valuemask, &attributes);
         Picture fill =
             XRenderCreateSolidFill(data->display, &foreground);
+        if (!fill) {
+            SDL_SetError("XRenderCreateSolidFill() failed");
+            return -1;
+        }
 
         XRenderComposite(data->display, data->blend_op, fill, data->mask_pict,
                          data->drawable_pict, 0, 0, 0, 0, 0, 0, window->w, window->h);
@@ -1097,6 +1235,10 @@
         unsigned long valuemask = CPClipMask;
         XRenderChangePicture(data->display, data->drawable_pict, valuemask, &attributes);
         Picture fill = XRenderCreateSolidFill(data->display, &xrforeground);
+        if (!fill) {
+            SDL_SetError("XRenderCreateSolidFill() failed");
+            return -1;
+        }
         XRenderComposite(data->display, data->blend_op, fill, data->mask_pict,
                          data->drawable_pict, 0, 0, 0, 0, 0, 0, window->w, window->h);
         attributes.clip_mask = None;
@@ -1158,6 +1300,10 @@
         XRenderChangePicture(data->display, data->drawable_pict, valuemask, &attributes);
         Picture fill =
             XRenderCreateSolidFill(data->display, &foreground);
+        if (!fill) {
+            SDL_SetError("XRenderCreateSolidFill() failed");
+            return -1;
+        }
         XRenderComposite(data->display, data->blend_op, fill, data->mask_pict,
                          data->drawable_pict, 0, 0, 0, 0, 0, 0, window->w, window->h);
         attributes.clip_mask = None;
@@ -1229,13 +1375,17 @@
                         xrects, xcount);
 
         XRenderChangePicture(data->display, data->drawable_pict, CPClipMask, &attributes);
-        Picture fill_pict = XRenderCreateSolidFill(data->display,
-                                                   &foreground);
-        XRenderComposite(data->display, data->blend_op, fill_pict, None,
+        Picture fill = XRenderCreateSolidFill(data->display,
+                                              &foreground);
+        if (!fill) {
+            SDL_SetError("XRenderCreateSolidFill() failed");
+            return -1;
+        }
+        XRenderComposite(data->display, data->blend_op, fill, None,
                          data->drawable_pict, 0, 0, 0, 0, 0, 0, window->w, window->h);
         attributes.clip_mask = None;
         XRenderChangePicture(data->display, data->drawable_pict, CPClipMask, &attributes);
-        XRenderFreePicture(data->display, fill_pict);
+        XRenderFreePicture(data->display, fill);
     }
     else
 #endif
@@ -1293,27 +1443,45 @@
                          srcrect->x, srcrect->y, dstrect->x, dstrect->y,
                          srcrect->w, srcrect->h);
         } else {
-            Pixmap scaling_pixmap = 
+            /*Pixmap scaling_pixmap = 
                 XCreatePixmap(data->display, texturedata->pixmap, dstrect->w, dstrect->h,
                               data->depth);
+            if (!scaling_pixmap) {
+                SDL_SetError("XCreatePixmap() failed");
+                return -1;
+            }
             Picture scaling_picture =
                 XRenderCreatePicture(data->display, scaling_pixmap, texturedata->picture_fmt,
                                      0, NULL);
+            if (!scaling_picture) {
+                SDL_SetError("XRenderCreatePicture() failed");
+                return -1;
+            }
             XRenderComposite(data->display, PictOpClear, scaling_picture, None, scaling_picture,
                              0, 0, 0, 0, 0, 0, dstrect->w, dstrect->h);
             XRenderComposite(data->display, PictOpSrc, texturedata->picture, pict, scaling_picture,
-                             srcrect->x, srcrect->y, 0, 0, 0, 0, srcrect->w, srcrect->h);
+                             srcrect->x, srcrect->y, 0, 0, 0, 0, srcrect->w, srcrect->h);*/
             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, scaling_picture, &xform);
-            XRenderComposite(data->display, texturedata->blend_op, scaling_picture, None, data->drawable_pict,
-                             0, 0, 0, 0, dstrect->x, dstrect->y, dstrect->w, dstrect->h);
-            XRenderFreePicture(data->display, scaling_picture);
-            XFreePixmap(data->display, scaling_pixmap);
+            XTransform xform = {{
+                    {XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0)},
+                    {XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0)},
+                    {XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(xscale * yscale)}}};
+            XRenderSetPictureTransform(data->display, texturedata->picture, &xform);
+
+            XRenderComposite(data->display, texturedata->blend_op,
+                             texturedata->picture, None, data->drawable_pict,
+                             0, 0, 0, 0, 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, texturedata->picture, &identity);
+
+            /*XRenderFreePicture(data->display, scaling_picture);
+            XFreePixmap(data->display, scaling_pixmap);*/
         }
     }
     else