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