glx: Make drawables persistent untill they are changed by glXMakeCurrent
authorPauli Nieminen <suokkos@gmail.com>
Mon, 3 Aug 2009 22:39:37 +0000 (01:39 +0300)
committerPauli Nieminen <suokkos@gmail.com>
Fri, 21 Aug 2009 16:12:28 +0000 (19:12 +0300)
This fixes bug that xdemos/manywin would segfault if it was run with command
./manywin 2. Demo is tring to call glXSwapBuffers while another context was
bind using glXMakeCurrent.

Fix is simple makes drawable and readable persistent untill they change or
context is destroyed.

I found a logic error when same dri context is used for multiple drawables
which caused readable and drawable to fall out of sync in special case. Fix
is simple just updating  drawables more often than in original patch.

Signed-off-by: Pauli Nieminen <suokkos@gmail.com>
src/mesa/drivers/dri/common/dri_util.c

index e48e10d7c061f6e73ea70cbf4bcbe689e92e2ef9..d7bcd565d73cde7e8e083b4cacef8c5ef31b505c 100644 (file)
@@ -82,6 +82,46 @@ driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 )
    return (rect1.x2 - rect1.x1) * (rect1.y2 - rect1.y1);
 }
 
+static int driFreeDrawable(__DRIcontext *pcp)
+{
+    __DRIdrawable *pdp;
+    __DRIdrawable *prp;
+
+       if (pcp == NULL)
+               return GL_FALSE;
+
+    pdp = pcp->driDrawablePriv;
+    prp = pcp->driReadablePriv;
+
+    /* already unbound */
+    if (!pdp && !prp)
+      return GL_TRUE;
+
+    if (pdp->refcount == 0) {
+       /* ERROR!!! */
+       return GL_FALSE;
+    }
+
+    dri_put_drawable(pdp);
+
+    if (prp != pdp) {
+        if (prp->refcount == 0) {
+           /* ERROR!!! */
+           return GL_FALSE;
+       }
+
+    dri_put_drawable(prp);
+    }
+
+
+    /* XXX this is disabled so that if we call SwapBuffers on an unbound
+     * window we can determine the last context bound to the window and
+     * use that context's lock. (BrianP, 2-Dec-2000)
+     */
+    pcp->driDrawablePriv = pcp->driReadablePriv = NULL;
+       return GL_TRUE;
+}
+
 /*****************************************************************/
 /** \name Context (un)binding functions                          */
 /*****************************************************************/
@@ -106,8 +146,6 @@ driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 )
 static int driUnbindContext(__DRIcontext *pcp)
 {
     __DRIscreen *psp;
-    __DRIdrawable *pdp;
-    __DRIdrawable *prp;
 
     /*
     ** Assume error checking is done properly in glXMakeCurrent before
@@ -118,38 +156,10 @@ static int driUnbindContext(__DRIcontext *pcp)
         return GL_FALSE;
 
     psp = pcp->driScreenPriv;
-    pdp = pcp->driDrawablePriv;
-    prp = pcp->driReadablePriv;
 
-    /* already unbound */
-    if (!pdp && !prp)
-      return GL_TRUE;
-    /* Let driver unbind drawable from context */
+       /* Let driver unbind drawable from context */
     (*psp->DriverAPI.UnbindContext)(pcp);
 
-    if (pdp->refcount == 0) {
-       /* ERROR!!! */
-       return GL_FALSE;
-    }
-
-    dri_put_drawable(pdp);
-
-    if (prp != pdp) {
-        if (prp->refcount == 0) {
-           /* ERROR!!! */
-           return GL_FALSE;
-       }
-
-       dri_put_drawable(prp);
-    }
-
-
-    /* XXX this is disabled so that if we call SwapBuffers on an unbound
-     * window we can determine the last context bound to the window and
-     * use that context's lock. (BrianP, 2-Dec-2000)
-     */
-    pcp->driDrawablePriv = pcp->driReadablePriv = NULL;
-
 #if 0
     /* Unbind the drawable */
     pdp->driContextPriv = &psp->dummyContextPriv;
@@ -171,17 +181,44 @@ static int driBindContext(__DRIcontext *pcp,
 
     /* Bind the drawable to the context */
 
-    if (pcp) {
-       pcp->driDrawablePriv = pdp;
-       pcp->driReadablePriv = prp;
-       if (pdp) {
-           pdp->driContextPriv = pcp;
-           dri_get_drawable(pdp);
-       }
-       if ( prp && pdp != prp ) {
-           dri_get_drawable(prp);
+       if (pcp) {
+
+               if (pcp->driDrawablePriv != pdp 
+                       || pcp->driReadablePriv != prp)
+               {
+                       /* first increment ref count for new drawables */
+
+                       if (pdp)
+                       {
+                               pdp->driContextPriv = pcp;
+                               dri_get_drawable(pdp);
+                       }
+
+                       if (prp && prp != pdp)
+                       {
+                               dri_get_drawable(prp);
+                       }
+
+                       /* free old drawables */ 
+
+                       if (pcp->driReadablePriv 
+                               && pcp->driReadablePriv != pcp->driDrawablePriv)
+                       {
+                               dri_put_drawable(pcp->driReadablePriv);
+                       }
+
+                       if (pcp->driDrawablePriv)
+                       {
+                               dri_put_drawable(pcp->driDrawablePriv);
+                       }
+
+                       /* assign new drawables to context */
+
+                       pcp->driDrawablePriv = pdp;
+                       pcp->driReadablePriv = prp;
+
+               }
        }
-    }
 
     /*
     ** Now that we have a context associated with this drawable, we can
@@ -542,6 +579,7 @@ static void
 driDestroyContext(__DRIcontext *pcp)
 {
     if (pcp) {
+       driFreeDrawable(pcp);
        (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
        _mesa_free(pcp);
     }
@@ -579,6 +617,7 @@ driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config,
 
     pcp->driScreenPriv = psp;
     pcp->driDrawablePriv = NULL;
+    pcp->driReadablePriv = NULL;
 
     /* When the first context is created for a screen, initialize a "dummy"
      * context.