xget_image() wrapper to catch BadMatch errors
authorBrian <brian.paul@tungstengraphics.com>
Thu, 1 Nov 2007 18:54:30 +0000 (12:54 -0600)
committerBrian <brian.paul@tungstengraphics.com>
Thu, 1 Nov 2007 18:54:30 +0000 (12:54 -0600)
src/mesa/pipe/xlib/xm_surface.c

index 50180679061ac0c45ea40460313e06302199738b..1ac96513d8a1194ad594b2915756a29f371c34de 100644 (file)
@@ -79,6 +79,93 @@ const int xmesa_kernel1[16] = {
    } while(0)
 
 
+
+/*
+ * The following functions are used to trap XGetImage() calls which
+ * generate BadMatch errors if the drawable isn't mapped.
+ */
+
+#ifndef XFree86Server
+static int caught_xgetimage_error = 0;
+static int (*old_xerror_handler)( XMesaDisplay *dpy, XErrorEvent *ev );
+static unsigned long xgetimage_serial;
+
+/*
+ * This is the error handler which will be called if XGetImage fails.
+ */
+static int xgetimage_error_handler( XMesaDisplay *dpy, XErrorEvent *ev )
+{
+   if (ev->serial==xgetimage_serial && ev->error_code==BadMatch) {
+      /* caught the expected error */
+      caught_xgetimage_error = 0;
+   }
+   else {
+      /* call the original X error handler, if any.  otherwise ignore */
+      if (old_xerror_handler) {
+         (*old_xerror_handler)( dpy, ev );
+      }
+   }
+   return 0;
+}
+
+
+/*
+ * Call this right before XGetImage to setup error trap.
+ */
+static void catch_xgetimage_errors( XMesaDisplay *dpy )
+{
+   xgetimage_serial = NextRequest( dpy );
+   old_xerror_handler = XSetErrorHandler( xgetimage_error_handler );
+   caught_xgetimage_error = 0;
+}
+
+
+/*
+ * Call this right after XGetImage to check if an error occured.
+ */
+static int check_xgetimage_errors( void )
+{
+   /* restore old handler */
+   (void) XSetErrorHandler( old_xerror_handler );
+   /* return 0=no error, 1=error caught */
+   return caught_xgetimage_error;
+}
+#endif
+
+
+/**
+ * Wrapper for XGetImage() that catches BadMatch errors that can occur
+ * when the window is unmapped or the x/y/w/h extend beyond the window
+ * bounds.
+ * If build into xserver, wrap the internal GetImage method.
+ */
+static XMesaImage *
+xget_image(XMesaDisplay *dpy, Drawable d, int x, int y, uint w, uint h)
+{
+#ifdef XFree86Server
+   uint bpp = 4; /* XXX fix this */
+   XMesaImage *ximage = (XMesaImage *) malloc(sizeof(XMesaImage));
+   if (ximage) {
+      ximage->data = malloc(width * height * bpp);
+   }
+   (*dpy->GetImage)(d, x, y, w, h, ZPixmap, ~0L, (pointer)ximage->data);
+   ximage->width = w;
+   ximage->height = h;
+   ximage->bytes_per_row = w * bpp;
+   return ximage;
+#else
+   int error;
+   XMesaImage *ximage;
+   catch_xgetimage_errors(dpy);
+   ximage = XGetImage(dpy, d, x, y, w, h, AllPlanes, ZPixmap);
+   error = check_xgetimage_errors();
+   return ximage;
+#endif
+}
+
+
+
+
 static INLINE struct xmesa_renderbuffer *
 xmesa_rb(struct pipe_surface *ps)
 {
@@ -90,6 +177,7 @@ xmesa_rb(struct pipe_surface *ps)
 #define FLIP(Y) Y = xrb->St.Base.Height - (Y) - 1;
 
 
+
 /**
  * Return raw pixels from pixmap or XImage.
  */
@@ -114,8 +202,9 @@ xmesa_get_tile(struct pipe_context *pipe, struct pipe_surface *ps,
    if (!xms->ximage) {
       /* XImage = pixmap data */
       assert(xms->drawable);
-      ximage = XGetImage(xms->display, xms->drawable, x, y, w, h,
-                         AllPlanes, ZPixmap);
+      ximage = xget_image(xms->display, xms->drawable, x, y, w, h);
+      if (!ximage)
+         return;
       x = y = 0;
    }
    else {
@@ -254,8 +343,9 @@ xmesa_get_tile_rgba(struct pipe_context *pipe, struct pipe_surface *ps,
    if (!xms->ximage) {
       /* XImage = pixmap data */
       assert(xms->drawable);
-      ximage = XGetImage(xms->display, xms->drawable, x, y, w, h,
-                         AllPlanes, ZPixmap);
+      ximage = xget_image(xms->display, xms->drawable, x, y, w, h);
+      if (!ximage)
+         return;
       x = y = 0;
    }
    else {