Rewrite code related to buffer destruction.
authorBrian <brian@yutani.localnet.net>
Mon, 26 Feb 2007 18:39:17 +0000 (11:39 -0700)
committerBrian <brian@yutani.localnet.net>
Mon, 26 Feb 2007 18:39:17 +0000 (11:39 -0700)
Do proper reference counting so that we don't wind up with dangling
references to deleted windows/framebuffers.  Should help with bug 7205.

src/mesa/drivers/x11/xm_api.c
src/mesa/drivers/x11/xm_buffer.c
src/mesa/drivers/x11/xmesaP.h

index b0ef422de2ea5e16e94a6b6e7d0cb9f0342fab26..2cd7d8a6ca1832528b6d5634520b07525ed070dd 100644 (file)
@@ -345,7 +345,7 @@ xmesa_get_window_size(XMesaDisplay *dpy, XMesaBuffer b,
 /*****                Linked list of XMesaBuffers                 *****/
 /**********************************************************************/
 
-static XMesaBuffer XMesaBufferList = NULL;
+XMesaBuffer XMesaBufferList = NULL;
 
 
 /**
@@ -378,6 +378,7 @@ create_xmesa_buffer(XMesaDrawable d, BufferType type,
    b->cmap = cmap;
 
    _mesa_initialize_framebuffer(&b->mesa_buffer, &vis->mesa_visual);
+   b->mesa_buffer.Delete = xmesa_delete_framebuffer;
 
    /*
     * Front renderbuffer
@@ -451,8 +452,8 @@ create_xmesa_buffer(XMesaDrawable d, BufferType type,
  * Find an XMesaBuffer by matching X display and colormap but NOT matching
  * the notThis buffer.
  */
-static XMesaBuffer
-find_xmesa_buffer(XMesaDisplay *dpy, XMesaColormap cmap, XMesaBuffer notThis)
+XMesaBuffer
+xmesa_find_buffer(XMesaDisplay *dpy, XMesaColormap cmap, XMesaBuffer notThis)
 {
    XMesaBuffer b;
    for (b=XMesaBufferList; b; b=b->Next) {
@@ -465,38 +466,27 @@ find_xmesa_buffer(XMesaDisplay *dpy, XMesaColormap cmap, XMesaBuffer notThis)
 
 
 /**
- * Free an XMesaBuffer, remove from linked list, perhaps free X colormap
- * entries.
+ * Remove buffer from linked list, delete if no longer referenced.
  */
 static void
-free_xmesa_buffer(int client, XMesaBuffer buffer)
+xmesa_free_buffer(XMesaBuffer buffer)
 {
    XMesaBuffer prev = NULL, b;
-   (void) client;
-   for (b=XMesaBufferList; b; b=b->Next) {
-      if (b==buffer) {
-         /* unlink bufer from list */
+
+   for (b = XMesaBufferList; b; b = b->Next) {
+      if (b == buffer) {
+         struct gl_framebuffer *fb = &buffer->mesa_buffer;
+
+         /* unlink buffer from list */
          if (prev)
             prev->Next = buffer->Next;
          else
             XMesaBufferList = buffer->Next;
-         /* Check to free X colors */
-         if (buffer->num_alloced>0) {
-            /* If no other buffer uses this X colormap then free the colors. */
-            if (!find_xmesa_buffer(buffer->display, buffer->cmap, buffer)) {
-#ifdef XFree86Server
-               (void)FreeColors(buffer->cmap, client,
-                               buffer->num_alloced, buffer->alloced_colors,
-                               0);
-#else
-               XFreeColors(buffer->display, buffer->cmap,
-                           buffer->alloced_colors, buffer->num_alloced, 0);
-#endif
-            }
-         }
 
-         _mesa_free_framebuffer_data(&buffer->mesa_buffer);
-         _mesa_free(buffer);
+         /* mark as delete pending */
+         fb->DeletePending = GL_TRUE;
+         /* Dereference.  If count = zero we'll really delete the buffer */
+         _mesa_dereference_framebuffer(&fb);
 
          return;
       }
@@ -504,7 +494,7 @@ free_xmesa_buffer(int client, XMesaBuffer buffer)
       prev = b;
    }
    /* buffer not found in XMesaBufferList */
-   _mesa_problem(NULL,"free_xmesa_buffer() - buffer not found\n");
+   _mesa_problem(NULL,"xmesa_free_buffer() - buffer not found\n");
 }
 
 
@@ -686,7 +676,7 @@ setup_grayscale(int client, XMesaVisual v,
          return GL_FALSE;
       }
 
-      prevBuffer = find_xmesa_buffer(v->display, cmap, buffer);
+      prevBuffer = xmesa_find_buffer(v->display, cmap, buffer);
       if (prevBuffer &&
           (buffer->xm_visual->mesa_visual.rgbMode ==
            prevBuffer->xm_visual->mesa_visual.rgbMode)) {
@@ -775,7 +765,7 @@ setup_dithered_color(int client, XMesaVisual v,
          return GL_FALSE;
       }
 
-      prevBuffer = find_xmesa_buffer(v->display, cmap, buffer);
+      prevBuffer = xmesa_find_buffer(v->display, cmap, buffer);
       if (prevBuffer &&
           (buffer->xm_visual->mesa_visual.rgbMode ==
            prevBuffer->xm_visual->mesa_visual.rgbMode)) {
@@ -1666,7 +1656,7 @@ XMesaCreateWindowBuffer2(XMesaVisual v, XMesaWindow w, XMesaContext c)
 
    if (!initialize_visual_and_buffer( client, v, b, v->mesa_visual.rgbMode,
                                       (XMesaDrawable) w, cmap )) {
-      free_xmesa_buffer(client, b);
+      xmesa_free_buffer(b);
       return NULL;
    }
 
@@ -1787,7 +1777,7 @@ XMesaCreatePixmapBuffer(XMesaVisual v, XMesaPixmap p, XMesaColormap cmap)
 
    if (!initialize_visual_and_buffer(client, v, b, v->mesa_visual.rgbMode,
                                     (XMesaDrawable) p, cmap)) {
-      free_xmesa_buffer(client, b);
+      xmesa_free_buffer(b);
       return NULL;
    }
 
@@ -1821,7 +1811,7 @@ XMesaCreatePBuffer(XMesaVisual v, XMesaColormap cmap,
 
    if (!initialize_visual_and_buffer(client, v, b, v->mesa_visual.rgbMode,
                                     drawable, cmap)) {
-      free_xmesa_buffer(client, b);
+      xmesa_free_buffer(b);
       return NULL;
    }
 
@@ -1834,48 +1824,10 @@ XMesaCreatePBuffer(XMesaVisual v, XMesaColormap cmap,
 /*
  * Deallocate an XMesaBuffer structure and all related info.
  */
-void XMesaDestroyBuffer( XMesaBuffer b )
+void
+XMesaDestroyBuffer(XMesaBuffer b)
 {
-   int client = 0;
-
-#ifdef XFree86Server
-   if (b->frontxrb->drawable)
-       client = CLIENT_ID(b->frontxrb->drawable->id);
-#endif
-
-   if (b->gc)  XMesaFreeGC( b->xm_visual->display, b->gc );
-   if (b->cleargc)  XMesaFreeGC( b->xm_visual->display, b->cleargc );
-   if (b->swapgc)  XMesaFreeGC( b->xm_visual->display, b->swapgc );
-
-   if (b->xm_visual->mesa_visual.doubleBufferMode)
-   {
-      if (b->backxrb->ximage) {
-#if defined(USE_XSHM) && !defined(XFree86Server)
-         if (b->shm) {
-            XShmDetach( b->xm_visual->display, &b->shminfo );
-            XDestroyImage( b->backxrb->ximage );
-            shmdt( b->shminfo.shmaddr );
-         }
-         else
-#endif
-            XMesaDestroyImage( b->backxrb->ximage );
-      }
-      if (b->backxrb->pixmap) {
-         XMesaFreePixmap( b->xm_visual->display, b->backxrb->pixmap );
-         if (b->xm_visual->hpcr_clear_flag) {
-            XMesaFreePixmap( b->xm_visual->display,
-                             b->xm_visual->hpcr_clear_pixmap );
-            XMesaDestroyImage( b->xm_visual->hpcr_clear_ximage );
-         }
-      }
-   }
-   if (b->rowimage) {
-      _mesa_free( b->rowimage->data );
-      b->rowimage->data = NULL;
-      XMesaDestroyImage( b->rowimage );
-   }
-
-   free_xmesa_buffer(client, b);
+   xmesa_free_buffer(b);
 }
 
 
@@ -2436,7 +2388,7 @@ void xmesa_destroy_buffers_on_display(XMesaDisplay *dpy)
    for (b = XMesaBufferList; b; b = next) {
       next = b->Next;
       if (b->display == dpy) {
-         free_xmesa_buffer(0, b);
+         xmesa_free_buffer(b);
       }
    }
 }
index 490c4796767eb08af5fae5341568ca7471eaddfc..187ae516cf261cbea2fbe8601cff9e7513f2f4cf 100644 (file)
@@ -33,6 +33,7 @@
 #include "GL/xmesa.h"
 #include "xmesaP.h"
 #include "imports.h"
+#include "framebuffer.h"
 #include "renderbuffer.h"
 
 
@@ -352,5 +353,72 @@ xmesa_new_renderbuffer(GLcontext *ctx, GLuint name, const GLvisual *visual,
 }
 
 
+/**
+ * Called via gl_framebuffer::Delete() method when this buffer
+ * is _really_ being
+ * deleted.
+ */
+void
+xmesa_delete_framebuffer(struct gl_framebuffer *fb)
+{
+   XMesaBuffer b = XMESA_BUFFER(fb);
 
+#ifdef XFree86Server
+   int client = 0;
+   if (b->frontxrb->drawable)
+       client = CLIENT_ID(b->frontxrb->drawable->id);
+#endif
 
+   if (b->num_alloced > 0) {
+      /* If no other buffer uses this X colormap then free the colors. */
+      if (!xmesa_find_buffer(b->display, b->cmap, b)) {
+#ifdef XFree86Server
+         (void)FreeColors(b->cmap, client,
+                          b->num_alloced, b->alloced_colors, 0);
+#else
+         XFreeColors(b->display, b->cmap,
+                     b->alloced_colors, b->num_alloced, 0);
+#endif
+      }
+   }
+
+   if (b->gc)
+      XMesaFreeGC(b->xm_visual->display, b->gc);
+   if (b->cleargc)
+      XMesaFreeGC(b->xm_visual->display, b->cleargc);
+   if (b->swapgc)
+      XMesaFreeGC(b->xm_visual->display, b->swapgc);
+
+   if (b->xm_visual->mesa_visual.doubleBufferMode) {
+      /* free back ximage/pixmap/shmregion */
+      if (b->backxrb->ximage) {
+#if defined(USE_XSHM) && !defined(XFree86Server)
+         if (b->shm) {
+            XShmDetach( b->xm_visual->display, &b->shminfo );
+            XDestroyImage( b->backxrb->ximage );
+            shmdt( b->shminfo.shmaddr );
+         }
+         else
+#endif
+            XMesaDestroyImage( b->backxrb->ximage );
+         b->backxrb->ximage = NULL;
+      }
+      if (b->backxrb->pixmap) {
+         XMesaFreePixmap( b->xm_visual->display, b->backxrb->pixmap );
+         if (b->xm_visual->hpcr_clear_flag) {
+            XMesaFreePixmap( b->xm_visual->display,
+                             b->xm_visual->hpcr_clear_pixmap );
+            XMesaDestroyImage( b->xm_visual->hpcr_clear_ximage );
+         }
+      }
+   }
+
+   if (b->rowimage) {
+      _mesa_free( b->rowimage->data );
+      b->rowimage->data = NULL;
+      XMesaDestroyImage( b->rowimage );
+   }
+
+   _mesa_free_framebuffer_data(fb);
+   _mesa_free(fb);
+}
index e332fb5480c52f07b1e1822df056f3834cddffab..5516031ffe7f0a61f3825cade8fec1f50ba68007 100644 (file)
@@ -42,6 +42,7 @@
 
 extern _glthread_Mutex _xmesa_lock;
 
+extern XMesaBuffer XMesaBufferList;
 
 /* for PF_8R8G8B24 pixel format */
 typedef struct {
@@ -489,6 +490,12 @@ extern struct xmesa_renderbuffer *
 xmesa_new_renderbuffer(GLcontext *ctx, GLuint name, const GLvisual *visual,
                        GLboolean backBuffer);
 
+extern void
+xmesa_delete_framebuffer(struct gl_framebuffer *fb);
+
+extern XMesaBuffer
+xmesa_find_buffer(XMesaDisplay *dpy, XMesaColormap cmap, XMesaBuffer notThis);
+
 extern unsigned long
 xmesa_color_to_pixel( GLcontext *ctx,
                       GLubyte r, GLubyte g, GLubyte b, GLubyte a,