17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
47117f1b4Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
57117f1b4Smrg *
67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
87117f1b4Smrg * to deal in the Software without restriction, including without limitation
97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
117117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
127117f1b4Smrg *
137117f1b4Smrg * The above copyright notice and this permission notice shall be included
147117f1b4Smrg * in all copies or substantial portions of the Software.
157117f1b4Smrg *
167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
257117f1b4Smrg
267117f1b4Smrg/**
277117f1b4Smrg * \file xm_buffer.h
287117f1b4Smrg * Framebuffer and renderbuffer-related functions.
297117f1b4Smrg */
307117f1b4Smrg
317117f1b4Smrg
327117f1b4Smrg#include "glxheader.h"
337117f1b4Smrg#include "xmesaP.h"
3401e04c3fSmrg#include "main/errors.h"
354a49301eSmrg#include "main/formats.h"
36c1f859d4Smrg#include "main/framebuffer.h"
37c1f859d4Smrg#include "main/renderbuffer.h"
38af69d88dSmrg#include "swrast/s_renderbuffer.h"
391463c08dSmrg#include "util/u_memory.h"
40af69d88dSmrg
41af69d88dSmrg
42af69d88dSmrg#define XMESA_RENDERBUFFER 0x1234
437117f1b4Smrg
447117f1b4Smrg
451463c08dSmrg#if defined(USE_XSHM)
467117f1b4Smrgstatic volatile int mesaXErrorFlag = 0;
477117f1b4Smrg
487117f1b4Smrg/**
497117f1b4Smrg * Catches potential Xlib errors.
507117f1b4Smrg */
517117f1b4Smrgstatic int
527117f1b4SmrgmesaHandleXError(XMesaDisplay *dpy, XErrorEvent *event)
537117f1b4Smrg{
547117f1b4Smrg   (void) dpy;
557117f1b4Smrg   (void) event;
567117f1b4Smrg   mesaXErrorFlag = 1;
577117f1b4Smrg   return 0;
587117f1b4Smrg}
597117f1b4Smrg
607117f1b4Smrg/**
617117f1b4Smrg * Allocate a shared memory XImage back buffer for the given XMesaBuffer.
627117f1b4Smrg * Return:  GL_TRUE if success, GL_FALSE if error
637117f1b4Smrg */
647117f1b4Smrgstatic GLboolean
657117f1b4Smrgalloc_back_shm_ximage(XMesaBuffer b, GLuint width, GLuint height)
667117f1b4Smrg{
677117f1b4Smrg   /*
687117f1b4Smrg    * We have to do a _lot_ of error checking here to be sure we can
697117f1b4Smrg    * really use the XSHM extension.  It seems different servers trigger
707117f1b4Smrg    * errors at different points if the extension won't work.  Therefore
717117f1b4Smrg    * we have to be very careful...
727117f1b4Smrg    */
737117f1b4Smrg   GC gc;
747117f1b4Smrg   int (*old_handler)(XMesaDisplay *, XErrorEvent *);
757117f1b4Smrg
767117f1b4Smrg   if (width == 0 || height == 0) {
777117f1b4Smrg      /* this will be true the first time we're called on 'b' */
787117f1b4Smrg      return GL_FALSE;
797117f1b4Smrg   }
807117f1b4Smrg
817117f1b4Smrg   b->backxrb->ximage = XShmCreateImage(b->xm_visual->display,
827117f1b4Smrg                                        b->xm_visual->visinfo->visual,
837117f1b4Smrg                                        b->xm_visual->visinfo->depth,
847117f1b4Smrg                                        ZPixmap, NULL, &b->shminfo,
857117f1b4Smrg                                        width, height);
867117f1b4Smrg   if (b->backxrb->ximage == NULL) {
877117f1b4Smrg      _mesa_warning(NULL, "alloc_back_buffer: Shared memory error (XShmCreateImage), disabling.\n");
887117f1b4Smrg      b->shm = 0;
897117f1b4Smrg      return GL_FALSE;
907117f1b4Smrg   }
917117f1b4Smrg
92d7cb65e3Smaya   /* 0600 = user read+write */
937117f1b4Smrg   b->shminfo.shmid = shmget(IPC_PRIVATE, b->backxrb->ximage->bytes_per_line
94d7cb65e3Smaya                             * b->backxrb->ximage->height, IPC_CREAT | 0600);
957117f1b4Smrg   if (b->shminfo.shmid < 0) {
967117f1b4Smrg      _mesa_warning(NULL, "shmget failed while allocating back buffer.\n");
977117f1b4Smrg      XDestroyImage(b->backxrb->ximage);
987117f1b4Smrg      b->backxrb->ximage = NULL;
997117f1b4Smrg      _mesa_warning(NULL, "alloc_back_buffer: Shared memory error (shmget), disabling.\n");
1007117f1b4Smrg      b->shm = 0;
1017117f1b4Smrg      return GL_FALSE;
1027117f1b4Smrg   }
1037117f1b4Smrg
1047117f1b4Smrg   b->shminfo.shmaddr = b->backxrb->ximage->data
1057117f1b4Smrg                      = (char*)shmat(b->shminfo.shmid, 0, 0);
1067117f1b4Smrg   if (b->shminfo.shmaddr == (char *) -1) {
1077117f1b4Smrg      _mesa_warning(NULL, "shmat() failed while allocating back buffer.\n");
1087117f1b4Smrg      XDestroyImage(b->backxrb->ximage);
1097117f1b4Smrg      shmctl(b->shminfo.shmid, IPC_RMID, 0);
1107117f1b4Smrg      b->backxrb->ximage = NULL;
1117117f1b4Smrg      _mesa_warning(NULL, "alloc_back_buffer: Shared memory error (shmat), disabling.\n");
1127117f1b4Smrg      b->shm = 0;
1137117f1b4Smrg      return GL_FALSE;
1147117f1b4Smrg   }
1157117f1b4Smrg
1167117f1b4Smrg   b->shminfo.readOnly = False;
1177117f1b4Smrg   mesaXErrorFlag = 0;
1187117f1b4Smrg   old_handler = XSetErrorHandler(mesaHandleXError);
1197117f1b4Smrg   /* This may trigger the X protocol error we're ready to catch: */
1207117f1b4Smrg   XShmAttach(b->xm_visual->display, &b->shminfo);
1217117f1b4Smrg   XSync(b->xm_visual->display, False);
1227117f1b4Smrg
1237117f1b4Smrg   if (mesaXErrorFlag) {
1247117f1b4Smrg      /* we are on a remote display, this error is normal, don't print it */
1257117f1b4Smrg      XFlush(b->xm_visual->display);
1267117f1b4Smrg      mesaXErrorFlag = 0;
1277117f1b4Smrg      XDestroyImage(b->backxrb->ximage);
1287117f1b4Smrg      shmdt(b->shminfo.shmaddr);
1297117f1b4Smrg      shmctl(b->shminfo.shmid, IPC_RMID, 0);
1307117f1b4Smrg      b->backxrb->ximage = NULL;
1317117f1b4Smrg      b->shm = 0;
1327117f1b4Smrg      (void) XSetErrorHandler(old_handler);
1337117f1b4Smrg      return GL_FALSE;
1347117f1b4Smrg   }
1357117f1b4Smrg
1367117f1b4Smrg   shmctl(b->shminfo.shmid, IPC_RMID, 0); /* nobody else needs it */
1377117f1b4Smrg
1387117f1b4Smrg   /* Finally, try an XShmPutImage to be really sure the extension works */
1397117f1b4Smrg   gc = XCreateGC(b->xm_visual->display, b->frontxrb->drawable, 0, NULL);
1407117f1b4Smrg   XShmPutImage(b->xm_visual->display, b->frontxrb->drawable, gc,
1417117f1b4Smrg		 b->backxrb->ximage, 0, 0, 0, 0, 1, 1 /*one pixel*/, False);
1427117f1b4Smrg   XSync(b->xm_visual->display, False);
1437117f1b4Smrg   XFreeGC(b->xm_visual->display, gc);
1447117f1b4Smrg   (void) XSetErrorHandler(old_handler);
1457117f1b4Smrg   if (mesaXErrorFlag) {
1467117f1b4Smrg      XFlush(b->xm_visual->display);
1477117f1b4Smrg      mesaXErrorFlag = 0;
1487117f1b4Smrg      XDestroyImage(b->backxrb->ximage);
1497117f1b4Smrg      shmdt(b->shminfo.shmaddr);
1507117f1b4Smrg      shmctl(b->shminfo.shmid, IPC_RMID, 0);
1517117f1b4Smrg      b->backxrb->ximage = NULL;
1527117f1b4Smrg      b->shm = 0;
1537117f1b4Smrg      return GL_FALSE;
1547117f1b4Smrg   }
1557117f1b4Smrg
1567117f1b4Smrg   return GL_TRUE;
1577117f1b4Smrg}
1587117f1b4Smrg#else
1597117f1b4Smrgstatic GLboolean
1607117f1b4Smrgalloc_back_shm_ximage(XMesaBuffer b, GLuint width, GLuint height)
1617117f1b4Smrg{
1627117f1b4Smrg   /* Can't compile XSHM support */
1637117f1b4Smrg   return GL_FALSE;
1647117f1b4Smrg}
1657117f1b4Smrg#endif
1667117f1b4Smrg
1677117f1b4Smrg
1687117f1b4Smrg
1697117f1b4Smrg/**
1707117f1b4Smrg * Setup an off-screen pixmap or Ximage to use as the back buffer.
1717117f1b4Smrg * Input:  b - the X/Mesa buffer
1727117f1b4Smrg */
1737117f1b4Smrgstatic void
1747117f1b4Smrgalloc_back_buffer(XMesaBuffer b, GLuint width, GLuint height)
1757117f1b4Smrg{
1767117f1b4Smrg   if (b->db_mode == BACK_XIMAGE) {
1777117f1b4Smrg      /* Deallocate the old backxrb->ximage, if any */
1787117f1b4Smrg      if (b->backxrb->ximage) {
1791463c08dSmrg#if defined(USE_XSHM)
1807117f1b4Smrg	 if (b->shm) {
1817117f1b4Smrg	    XShmDetach(b->xm_visual->display, &b->shminfo);
1827117f1b4Smrg	    XDestroyImage(b->backxrb->ximage);
1837117f1b4Smrg	    shmdt(b->shminfo.shmaddr);
1847117f1b4Smrg	 }
1857117f1b4Smrg	 else
1867117f1b4Smrg#endif
1877117f1b4Smrg	   XMesaDestroyImage(b->backxrb->ximage);
1887117f1b4Smrg	 b->backxrb->ximage = NULL;
1897117f1b4Smrg      }
1907117f1b4Smrg
1917117f1b4Smrg      if (width == 0 || height == 0)
1927117f1b4Smrg         return;
1937117f1b4Smrg
1947117f1b4Smrg      /* Allocate new back buffer */
1957117f1b4Smrg      if (b->shm == 0 || !alloc_back_shm_ximage(b, width, height)) {
1967117f1b4Smrg	 /* Allocate a regular XImage for the back buffer. */
1977117f1b4Smrg	 b->backxrb->ximage = XCreateImage(b->xm_visual->display,
1987117f1b4Smrg                                      b->xm_visual->visinfo->visual,
1997117f1b4Smrg                                      GET_VISUAL_DEPTH(b->xm_visual),
2007117f1b4Smrg				      ZPixmap, 0,   /* format, offset */
2017117f1b4Smrg				      NULL,
2027117f1b4Smrg                                      width, height,
2037117f1b4Smrg				      8, 0);  /* pad, bytes_per_line */
2047117f1b4Smrg	 if (!b->backxrb->ximage) {
2057117f1b4Smrg	    _mesa_warning(NULL, "alloc_back_buffer: XCreateImage failed.\n");
2067117f1b4Smrg            return;
2077117f1b4Smrg	 }
208af69d88dSmrg         b->backxrb->ximage->data = malloc(b->backxrb->ximage->height
2097117f1b4Smrg                                        * b->backxrb->ximage->bytes_per_line);
2107117f1b4Smrg         if (!b->backxrb->ximage->data) {
2117117f1b4Smrg            _mesa_warning(NULL, "alloc_back_buffer: MALLOC failed.\n");
2127117f1b4Smrg            XMesaDestroyImage(b->backxrb->ximage);
2137117f1b4Smrg            b->backxrb->ximage = NULL;
2147117f1b4Smrg         }
2157117f1b4Smrg      }
2167117f1b4Smrg      b->backxrb->pixmap = None;
2177117f1b4Smrg   }
2187117f1b4Smrg   else if (b->db_mode == BACK_PIXMAP) {
2197117f1b4Smrg      /* Free the old back pixmap */
2207117f1b4Smrg      if (b->backxrb->pixmap) {
2217117f1b4Smrg         XMesaFreePixmap(b->xm_visual->display, b->backxrb->pixmap);
2227117f1b4Smrg         b->backxrb->pixmap = 0;
2237117f1b4Smrg      }
2247117f1b4Smrg
2257117f1b4Smrg      if (width > 0 && height > 0) {
2267117f1b4Smrg         /* Allocate new back pixmap */
2277117f1b4Smrg         b->backxrb->pixmap = XMesaCreatePixmap(b->xm_visual->display,
2287117f1b4Smrg                                                b->frontxrb->drawable,
2297117f1b4Smrg                                                width, height,
2307117f1b4Smrg                                                GET_VISUAL_DEPTH(b->xm_visual));
2317117f1b4Smrg      }
2327117f1b4Smrg
2337117f1b4Smrg      b->backxrb->ximage = NULL;
234c1f859d4Smrg      b->backxrb->drawable = b->backxrb->pixmap;
2357117f1b4Smrg   }
2367117f1b4Smrg}
2377117f1b4Smrg
2387117f1b4Smrg
2397117f1b4Smrgstatic void
240af69d88dSmrgxmesa_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
2417117f1b4Smrg{
2427117f1b4Smrg   /* XXX Note: the ximage or Pixmap attached to this renderbuffer
2437117f1b4Smrg    * should probably get freed here, but that's currently done in
2447117f1b4Smrg    * XMesaDestroyBuffer().
2457117f1b4Smrg    */
246cdc920a0Smrg   free(rb);
2477117f1b4Smrg}
2487117f1b4Smrg
2497117f1b4Smrg
2507117f1b4Smrg/**
2517117f1b4Smrg * Reallocate renderbuffer storage for front color buffer.
2527117f1b4Smrg * Called via gl_renderbuffer::AllocStorage()
2537117f1b4Smrg */
2547117f1b4Smrgstatic GLboolean
2553464ebd5Sriastradhxmesa_alloc_front_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
2567117f1b4Smrg                          GLenum internalFormat, GLuint width, GLuint height)
2577117f1b4Smrg{
2587117f1b4Smrg   struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb);
2597117f1b4Smrg
2607117f1b4Smrg   /* just clear these to be sure we don't accidentally use them */
2617117f1b4Smrg   xrb->origin2 = NULL;
2627117f1b4Smrg   xrb->origin3 = NULL;
2637117f1b4Smrg   xrb->origin4 = NULL;
2647117f1b4Smrg
2657117f1b4Smrg   /* for the FLIP macro: */
2667117f1b4Smrg   xrb->bottom = height - 1;
2677117f1b4Smrg
2687117f1b4Smrg   rb->Width = width;
2697117f1b4Smrg   rb->Height = height;
2707117f1b4Smrg   rb->InternalFormat = internalFormat;
2717117f1b4Smrg
2727117f1b4Smrg   return GL_TRUE;
2737117f1b4Smrg}
2747117f1b4Smrg
2757117f1b4Smrg
2767117f1b4Smrg/**
2777117f1b4Smrg * Reallocate renderbuffer storage for back color buffer.
2787117f1b4Smrg * Called via gl_renderbuffer::AllocStorage()
2797117f1b4Smrg */
2807117f1b4Smrgstatic GLboolean
2813464ebd5Sriastradhxmesa_alloc_back_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
2827117f1b4Smrg                         GLenum internalFormat, GLuint width, GLuint height)
2837117f1b4Smrg{
2847117f1b4Smrg   struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb);
2857117f1b4Smrg
2867117f1b4Smrg   /* reallocate the back buffer XImage or Pixmap */
2877117f1b4Smrg   assert(xrb->Parent);
2887117f1b4Smrg   alloc_back_buffer(xrb->Parent, width, height);
2897117f1b4Smrg
2907117f1b4Smrg   /* same as front buffer */
2917117f1b4Smrg   /* XXX why is this here? */
2927117f1b4Smrg   (void) xmesa_alloc_front_storage(ctx, rb, internalFormat, width, height);
2937117f1b4Smrg
2947117f1b4Smrg   /* plus... */
2957117f1b4Smrg   if (xrb->ximage) {
2967117f1b4Smrg      /* Needed by PIXELADDR2 macro */
2977117f1b4Smrg      xrb->width2 = xrb->ximage->bytes_per_line / 2;
2987117f1b4Smrg      xrb->origin2 = (GLushort *) xrb->ximage->data + xrb->width2 * (height - 1);
2997117f1b4Smrg
3007117f1b4Smrg      /* Needed by PIXELADDR3 macro */
3017117f1b4Smrg      xrb->width3 = xrb->ximage->bytes_per_line;
3027117f1b4Smrg      xrb->origin3 = (GLubyte *) xrb->ximage->data + xrb->width3 * (height - 1);
3037117f1b4Smrg
3047117f1b4Smrg      /* Needed by PIXELADDR4 macro */
3057117f1b4Smrg      xrb->width4 = xrb->ximage->width;
3067117f1b4Smrg      xrb->origin4 = (GLuint *) xrb->ximage->data + xrb->width4 * (height - 1);
3077117f1b4Smrg   }
3087117f1b4Smrg   else {
3097117f1b4Smrg      /* out of memory or buffer size is 0 x 0 */
310af69d88dSmrg      xrb->width2 = xrb->width3 = xrb->width4 = 0;
3117117f1b4Smrg      xrb->origin2 = NULL;
3127117f1b4Smrg      xrb->origin3 = NULL;
3137117f1b4Smrg      xrb->origin4 = NULL;
3147117f1b4Smrg   }
3157117f1b4Smrg
3167117f1b4Smrg   return GL_TRUE;
3177117f1b4Smrg}
3187117f1b4Smrg
3197117f1b4Smrg
320af69d88dSmrg/**
321af69d88dSmrg * Used for allocating front/back renderbuffers for an X window.
322af69d88dSmrg */
3237117f1b4Smrgstruct xmesa_renderbuffer *
324af69d88dSmrgxmesa_new_renderbuffer(struct gl_context *ctx, GLuint name,
325af69d88dSmrg                       const struct xmesa_visual *xmvis,
3267117f1b4Smrg                       GLboolean backBuffer)
3277117f1b4Smrg{
3287117f1b4Smrg   struct xmesa_renderbuffer *xrb = CALLOC_STRUCT(xmesa_renderbuffer);
3297117f1b4Smrg   if (xrb) {
3307117f1b4Smrg      GLuint name = 0;
331af69d88dSmrg      _mesa_init_renderbuffer(&xrb->Base.Base, name);
3327117f1b4Smrg
333af69d88dSmrg      xrb->Base.Base.Delete = xmesa_delete_renderbuffer;
3347117f1b4Smrg      if (backBuffer)
335af69d88dSmrg         xrb->Base.Base.AllocStorage = xmesa_alloc_back_storage;
3367117f1b4Smrg      else
337af69d88dSmrg         xrb->Base.Base.AllocStorage = xmesa_alloc_front_storage;
338af69d88dSmrg
339af69d88dSmrg      xrb->Base.Base.InternalFormat = GL_RGBA;
340af69d88dSmrg      xrb->Base.Base._BaseFormat = GL_RGBA;
341af69d88dSmrg      xrb->Base.Base.ClassID = XMESA_RENDERBUFFER;
342af69d88dSmrg
343af69d88dSmrg      switch (xmvis->undithered_pf) {
344af69d88dSmrg      case PF_8R8G8B:
345af69d88dSmrg         /* This will really only happen for pixmaps.  We'll access the
346af69d88dSmrg          * pixmap via a temporary XImage which will be 32bpp.
347af69d88dSmrg          */
348af69d88dSmrg         xrb->Base.Base.Format = MESA_FORMAT_B8G8R8X8_UNORM;
349af69d88dSmrg         break;
350af69d88dSmrg      case PF_8A8R8G8B:
351af69d88dSmrg         xrb->Base.Base.Format = MESA_FORMAT_B8G8R8A8_UNORM;
352af69d88dSmrg         break;
353af69d88dSmrg      case PF_8A8B8G8R:
354af69d88dSmrg         xrb->Base.Base.Format = MESA_FORMAT_R8G8B8A8_UNORM;
355af69d88dSmrg         break;
356af69d88dSmrg      case PF_5R6G5B:
357af69d88dSmrg         xrb->Base.Base.Format = MESA_FORMAT_B5G6R5_UNORM;
358af69d88dSmrg         break;
359af69d88dSmrg      default:
360af69d88dSmrg         _mesa_warning(ctx, "Bad pixel format in xmesa_new_renderbuffer");
361af69d88dSmrg         xrb->Base.Base.Format = MESA_FORMAT_B8G8R8A8_UNORM;
362af69d88dSmrg         break;
363af69d88dSmrg      }
3647117f1b4Smrg
3657117f1b4Smrg      /* only need to set Red/Green/EtcBits fields for user-created RBs */
3667117f1b4Smrg   }
3677117f1b4Smrg   return xrb;
3687117f1b4Smrg}
3697117f1b4Smrg
3707117f1b4Smrg
3717117f1b4Smrg/**
3727117f1b4Smrg * Called via gl_framebuffer::Delete() method when this buffer
3737117f1b4Smrg * is _really_ being deleted.
3747117f1b4Smrg */
3757117f1b4Smrgvoid
3767117f1b4Smrgxmesa_delete_framebuffer(struct gl_framebuffer *fb)
3777117f1b4Smrg{
3787117f1b4Smrg   XMesaBuffer b = XMESA_BUFFER(fb);
3797117f1b4Smrg
3807117f1b4Smrg   if (b->num_alloced > 0) {
3817117f1b4Smrg      /* If no other buffer uses this X colormap then free the colors. */
3827117f1b4Smrg      if (!xmesa_find_buffer(b->display, b->cmap, b)) {
3837117f1b4Smrg         XFreeColors(b->display, b->cmap,
3847117f1b4Smrg                     b->alloced_colors, b->num_alloced, 0);
3857117f1b4Smrg      }
3867117f1b4Smrg   }
3877117f1b4Smrg
3887117f1b4Smrg   if (b->gc)
3897117f1b4Smrg      XMesaFreeGC(b->display, b->gc);
3907117f1b4Smrg   if (b->cleargc)
3917117f1b4Smrg      XMesaFreeGC(b->display, b->cleargc);
3927117f1b4Smrg   if (b->swapgc)
3937117f1b4Smrg      XMesaFreeGC(b->display, b->swapgc);
3947117f1b4Smrg
3957117f1b4Smrg   if (fb->Visual.doubleBufferMode) {
3967117f1b4Smrg      /* free back ximage/pixmap/shmregion */
3977117f1b4Smrg      if (b->backxrb->ximage) {
3981463c08dSmrg#if defined(USE_XSHM)
3997117f1b4Smrg         if (b->shm) {
4007117f1b4Smrg            XShmDetach( b->display, &b->shminfo );
4017117f1b4Smrg            XDestroyImage( b->backxrb->ximage );
4027117f1b4Smrg            shmdt( b->shminfo.shmaddr );
4037117f1b4Smrg         }
4047117f1b4Smrg         else
4057117f1b4Smrg#endif
4067117f1b4Smrg            XMesaDestroyImage( b->backxrb->ximage );
4077117f1b4Smrg         b->backxrb->ximage = NULL;
4087117f1b4Smrg      }
4097117f1b4Smrg      if (b->backxrb->pixmap) {
4107117f1b4Smrg         XMesaFreePixmap( b->display, b->backxrb->pixmap );
411af69d88dSmrg      }
412af69d88dSmrg   }
413af69d88dSmrg
414af69d88dSmrg   _mesa_free_framebuffer_data(fb);
415af69d88dSmrg   free(fb);
416af69d88dSmrg}
417af69d88dSmrg
418af69d88dSmrg
419af69d88dSmrg/**
420af69d88dSmrg * Called via ctx->Driver.MapRenderbuffer()
421af69d88dSmrg */
422af69d88dSmrgvoid
423af69d88dSmrgxmesa_MapRenderbuffer(struct gl_context *ctx,
424af69d88dSmrg                      struct gl_renderbuffer *rb,
425af69d88dSmrg                      GLuint x, GLuint y, GLuint w, GLuint h,
426af69d88dSmrg                      GLbitfield mode,
42701e04c3fSmrg                      GLubyte **mapOut, GLint *rowStrideOut,
42801e04c3fSmrg                      bool flip_y)
429af69d88dSmrg{
430af69d88dSmrg   struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb);
431af69d88dSmrg
432af69d88dSmrg   if (xrb->Base.Base.ClassID == XMESA_RENDERBUFFER) {
433af69d88dSmrg      XImage *ximage = xrb->ximage;
434af69d88dSmrg
435af69d88dSmrg      assert(!xrb->map_mode); /* only a single mapping allowed */
436af69d88dSmrg
437af69d88dSmrg      xrb->map_mode = mode;
438af69d88dSmrg      xrb->map_x = x;
439af69d88dSmrg      xrb->map_y = y;
440af69d88dSmrg      xrb->map_w = w;
441af69d88dSmrg      xrb->map_h = h;
442af69d88dSmrg
443af69d88dSmrg      if (ximage) {
444af69d88dSmrg         int y2 = rb->Height - y - 1;
445af69d88dSmrg
446af69d88dSmrg         *mapOut = (GLubyte *) ximage->data
447af69d88dSmrg            + y2 * ximage->bytes_per_line
448af69d88dSmrg            + x * ximage->bits_per_pixel / 8;
449af69d88dSmrg      }
450af69d88dSmrg      else {
451af69d88dSmrg         /* this must be a pixmap/window renderbuffer */
452af69d88dSmrg         int (*old_handler)(XMesaDisplay *, XErrorEvent *);
453af69d88dSmrg         int y2 = rb->Height - y - h;
454af69d88dSmrg
455af69d88dSmrg         assert(xrb->pixmap);
456af69d88dSmrg
45701e04c3fSmrg         /* Install error handler for XGetImage() in case the window
458af69d88dSmrg          * isn't mapped.  If we fail we'll create a temporary XImage.
459af69d88dSmrg          */
460af69d88dSmrg         mesaXErrorFlag = 0;
461af69d88dSmrg         old_handler = XSetErrorHandler(mesaHandleXError);
462af69d88dSmrg
463af69d88dSmrg         /* read pixel data out of the pixmap/window into an XImage */
464af69d88dSmrg         ximage = XGetImage(xrb->Parent->display,
465af69d88dSmrg                            xrb->pixmap, x, y2, w, h,
466af69d88dSmrg                            AllPlanes, ZPixmap);
467af69d88dSmrg
468af69d88dSmrg         XSetErrorHandler(old_handler);
469af69d88dSmrg
470af69d88dSmrg         if (mesaXErrorFlag) {
471af69d88dSmrg            /* create new, temporary XImage */
472af69d88dSmrg            int bytes_per_line =
473af69d88dSmrg               _mesa_format_row_stride(xrb->Base.Base.Format,
474af69d88dSmrg                                       xrb->Base.Base.Width);
475af69d88dSmrg            char *image = malloc(bytes_per_line *
476af69d88dSmrg                                          xrb->Base.Base.Height);
477af69d88dSmrg            ximage = XCreateImage(xrb->Parent->display,
478af69d88dSmrg                                  xrb->Parent->xm_visual->visinfo->visual,
479af69d88dSmrg                                  xrb->Parent->xm_visual->visinfo->depth,
480af69d88dSmrg                                  ZPixmap, /* format */
481af69d88dSmrg                                  0, /* offset */
482af69d88dSmrg                                  image, /* data */
483af69d88dSmrg                                  xrb->Base.Base.Width,
484af69d88dSmrg                                  xrb->Base.Base.Height,
485af69d88dSmrg                                  8, /* pad */
486af69d88dSmrg                                  bytes_per_line);
487af69d88dSmrg         }
488af69d88dSmrg
489af69d88dSmrg         if (!ximage) {
490af69d88dSmrg            *mapOut = NULL;
491af69d88dSmrg            *rowStrideOut = 0;
492af69d88dSmrg            return;
4937117f1b4Smrg         }
494af69d88dSmrg
495af69d88dSmrg         xrb->map_ximage = ximage;
496af69d88dSmrg
497af69d88dSmrg         /* the first row of the OpenGL image is last row of the XImage */
498af69d88dSmrg         *mapOut = (GLubyte *) ximage->data
499af69d88dSmrg            + (h - 1) * ximage->bytes_per_line;
5007117f1b4Smrg      }
501af69d88dSmrg
502af69d88dSmrg      /* We return a negative stride here since XImage data is upside down
503af69d88dSmrg       * with respect to OpenGL images.
504af69d88dSmrg       */
505af69d88dSmrg      *rowStrideOut = -ximage->bytes_per_line;
506af69d88dSmrg      return;
5077117f1b4Smrg   }
5087117f1b4Smrg
509af69d88dSmrg   /* otherwise, this is an ordinary malloc-based renderbuffer */
510af69d88dSmrg   _swrast_map_soft_renderbuffer(ctx, rb, x, y, w, h, mode,
51101e04c3fSmrg                                 mapOut, rowStrideOut, false);
512af69d88dSmrg}
513af69d88dSmrg
514af69d88dSmrg
515af69d88dSmrg/**
516af69d88dSmrg * Called via ctx->Driver.UnmapRenderbuffer()
517af69d88dSmrg */
518af69d88dSmrgvoid
519af69d88dSmrgxmesa_UnmapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
520af69d88dSmrg{
521af69d88dSmrg   struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb);
522af69d88dSmrg
523af69d88dSmrg   if (xrb->Base.Base.ClassID == XMESA_RENDERBUFFER) {
524af69d88dSmrg      XImage *ximage = xrb->ximage;
525af69d88dSmrg
526af69d88dSmrg      if (!ximage) {
527af69d88dSmrg         /* this must be a pixmap/window renderbuffer */
528af69d88dSmrg         assert(xrb->pixmap);
529af69d88dSmrg         assert(xrb->map_ximage);
530af69d88dSmrg         if (xrb->map_ximage) {
531af69d88dSmrg            if (xrb->map_mode & GL_MAP_WRITE_BIT) {
532af69d88dSmrg               /* put modified ximage data back into the pixmap/window */
533af69d88dSmrg               int y2 = rb->Height - xrb->map_y - xrb->map_h;
534af69d88dSmrg               GC gc = XCreateGC(xrb->Parent->display, xrb->pixmap, 0, NULL);
535af69d88dSmrg
536af69d88dSmrg               XPutImage(xrb->Parent->display,
537af69d88dSmrg                         xrb->pixmap,              /* dest */
538af69d88dSmrg                         gc,
539af69d88dSmrg                         xrb->map_ximage,          /* source */
540af69d88dSmrg                         0, 0,                     /* src x, y */
541af69d88dSmrg                         xrb->map_x, y2,           /* dest x, y */
542af69d88dSmrg                         xrb->map_w, xrb->map_h);  /* size */
543af69d88dSmrg
544af69d88dSmrg               XFreeGC(xrb->Parent->display, gc);
545af69d88dSmrg            }
546af69d88dSmrg            XMesaDestroyImage(xrb->map_ximage);
547af69d88dSmrg            xrb->map_ximage = NULL;
548af69d88dSmrg         }
549af69d88dSmrg      }
550af69d88dSmrg
551af69d88dSmrg      xrb->map_mode = 0x0;
552af69d88dSmrg
553af69d88dSmrg      return;
5547117f1b4Smrg   }
5557117f1b4Smrg
556af69d88dSmrg   /* otherwise, this is an ordinary malloc-based renderbuffer */
557af69d88dSmrg   _swrast_unmap_soft_renderbuffer(ctx, rb);
5587117f1b4Smrg}
559af69d88dSmrg
560af69d88dSmrg
561