The current dri context unbind logic will leak drawables until the process
dies (they will then get released by the GEM code). There are two ways to fix
this: either always call driReleaseDrawables every time we unbind a context
(but that costs us round trips to the X server at getbuffers() time) or
implement proper drawable refcounting. This patch implements the latter.

Signed-off-by: Antoine Labour <pi...@chromium.org>
Signed-off-by: Stéphane Marchesin <marc...@chromium.org>
---
 src/glx/dri2_glx.c   |    5 ++---
 src/glx/dri_common.c |   26 +++++++++++++++++++-------
 src/glx/dri_glx.c    |    6 ++++--
 src/glx/drisw_glx.c  |    6 ++++--
 src/glx/glxclient.h  |    1 +
 src/glx/glxcurrent.c |   14 +++++++-------
 6 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/src/glx/dri2_glx.c b/src/glx/dri2_glx.c
index 506754c..e7c18ff 100644
--- a/src/glx/dri2_glx.c
+++ b/src/glx/dri2_glx.c
@@ -143,6 +143,8 @@ dri2_bind_context(struct glx_context *context, struct 
glx_context *old,
    pdraw = (struct dri2_drawable *) driFetchDrawable(context, draw);
    pread = (struct dri2_drawable *) driFetchDrawable(context, read);
 
+   driReleaseDrawables(&pcp->base);
+
    if (pdraw == NULL || pread == NULL)
       return GLXBadDrawable;
 
@@ -170,9 +172,6 @@ dri2_unbind_context(struct glx_context *context, struct 
glx_context *new)
    struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
 
    (*psc->core->unbindContext) (pcp->driContext);
-
-   if (context == new)
-      driReleaseDrawables(&pcp->base);
 }
 
 static struct glx_context *
diff --git a/src/glx/dri_common.c b/src/glx/dri_common.c
index 06a73e4..bac0c9e 100644
--- a/src/glx/dri_common.c
+++ b/src/glx/dri_common.c
@@ -369,8 +369,10 @@ driFetchDrawable(struct glx_context *gc, GLXDrawable 
glxDrawable)
    if (priv->drawHash == NULL)
       return NULL;
 
-   if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0)
+   if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) {
+      pdraw->refcount ++;
       return pdraw;
+   }
 
    pdraw = psc->driScreen->createDrawable(psc, glxDrawable,
                                           glxDrawable, gc->config);
@@ -378,6 +380,7 @@ driFetchDrawable(struct glx_context *gc, GLXDrawable 
glxDrawable)
       (*pdraw->destroyDrawable) (pdraw);
       return NULL;
    }
+   pdraw->refcount = 1;
 
    return pdraw;
 }
@@ -394,19 +397,28 @@ driReleaseDrawables(struct glx_context *gc)
    if (__glxHashLookup(priv->drawHash,
                       gc->currentDrawable, (void *) &pdraw) == 0) {
       if (pdraw->drawable == pdraw->xDrawable) {
-        (*pdraw->destroyDrawable)(pdraw);
-        __glxHashDelete(priv->drawHash, gc->currentDrawable);
+        pdraw->refcount --;
+        if (pdraw->refcount == 0) {
+           (*pdraw->destroyDrawable)(pdraw);
+           __glxHashDelete(priv->drawHash, gc->currentDrawable);
+        }
       }
    }
 
-   if (gc->currentDrawable != gc->currentReadable &&
-       __glxHashLookup(priv->drawHash,
+   if (__glxHashLookup(priv->drawHash,
                       gc->currentReadable, (void *) &pdraw) == 0) {
       if (pdraw->drawable == pdraw->xDrawable) {
-        (*pdraw->destroyDrawable)(pdraw);
-        __glxHashDelete(priv->drawHash, gc->currentReadable);
+        pdraw->refcount --;
+        if (pdraw->refcount == 0) {
+           (*pdraw->destroyDrawable)(pdraw);
+           __glxHashDelete(priv->drawHash, gc->currentReadable);
+        }
       }
    }
+
+   gc->currentDrawable = None;
+   gc->currentReadable = None;
+
 }
 
 #endif /* GLX_DIRECT_RENDERING */
diff --git a/src/glx/dri_glx.c b/src/glx/dri_glx.c
index ff027dc..d59784c 100644
--- a/src/glx/dri_glx.c
+++ b/src/glx/dri_glx.c
@@ -503,6 +503,8 @@ dri_destroy_context(struct glx_context * context)
    struct dri_context *pcp = (struct dri_context *) context;
    struct dri_screen *psc = (struct dri_screen *) context->psc;
 
+   driReleaseDrawables(&pcp->base);
+
    if (context->xid)
       glx_send_destroy_context(psc->base.dpy, context->xid);
 
@@ -526,6 +528,8 @@ dri_bind_context(struct glx_context *context, struct 
glx_context *old,
    pdraw = (struct dri_drawable *) driFetchDrawable(context, draw);
    pread = (struct dri_drawable *) driFetchDrawable(context, read);
 
+   driReleaseDrawables(&pcp->base);
+
    if (pdraw == NULL || pread == NULL)
       return GLXBadDrawable;
 
@@ -543,8 +547,6 @@ dri_unbind_context(struct glx_context *context, struct 
glx_context *new)
    struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
 
    (*psc->core->unbindContext) (pcp->driContext);
-
-   driReleaseDrawables(&pcp->base);
 }
 
 static const struct glx_context_vtable dri_context_vtable = {
diff --git a/src/glx/drisw_glx.c b/src/glx/drisw_glx.c
index 2eaa3c5..0075695 100644
--- a/src/glx/drisw_glx.c
+++ b/src/glx/drisw_glx.c
@@ -242,6 +242,8 @@ drisw_destroy_context(struct glx_context *context)
    struct drisw_context *pcp = (struct drisw_context *) context;
    struct drisw_screen *psc = (struct drisw_screen *) context->psc;
 
+   driReleaseDrawables(&pcp->base);
+
    if (context->xid)
       glx_send_destroy_context(psc->base.dpy, context->xid);
 
@@ -264,6 +266,8 @@ drisw_bind_context(struct glx_context *context, struct 
glx_context *old,
    pdraw = (struct drisw_drawable *) driFetchDrawable(context, draw);
    pread = (struct drisw_drawable *) driFetchDrawable(context, read);
 
+   driReleaseDrawables(&pcp->base);
+
    if (pdraw == NULL || pread == NULL)
       return GLXBadDrawable;
 
@@ -281,8 +285,6 @@ drisw_unbind_context(struct glx_context *context, struct 
glx_context *new)
    struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
 
    (*psc->core->unbindContext) (pcp->driContext);
-
-   driReleaseDrawables(&pcp->base);
 }
 
 static const struct glx_context_vtable drisw_context_vtable = {
diff --git a/src/glx/glxclient.h b/src/glx/glxclient.h
index fa2e2d3..88a6edd 100644
--- a/src/glx/glxclient.h
+++ b/src/glx/glxclient.h
@@ -138,6 +138,7 @@ struct __GLXDRIdrawableRec
    GLenum textureTarget;
    GLenum textureFormat;        /* EXT_texture_from_pixmap support */
    unsigned long eventMask;
+   int refcount;
 };
 
 /*
diff --git a/src/glx/glxcurrent.c b/src/glx/glxcurrent.c
index 064fd71..9eb7d5a 100644
--- a/src/glx/glxcurrent.c
+++ b/src/glx/glxcurrent.c
@@ -255,8 +255,6 @@ MakeContextCurrent(Display * dpy, GLXDrawable draw,
       if (--oldGC->thread_refcount == 0) {
         oldGC->vtable->unbind(oldGC, gc);
         oldGC->currentDpy = 0;
-        oldGC->currentDrawable = None;
-        oldGC->currentReadable = None;
 
         if (oldGC->xid == None && oldGC != gc) {
            /* We are switching away from a context that was
@@ -268,13 +266,15 @@ MakeContextCurrent(Display * dpy, GLXDrawable draw,
    }
 
    if (gc) {
-      if (gc->thread_refcount++ == 0) {
-        gc->currentDpy = dpy;
-        gc->currentDrawable = draw;
-        gc->currentReadable = read;
-      }
+      if (gc->thread_refcount == 0)
+         gc->currentDpy = dpy;
       __glXSetCurrentContext(gc);
       ret = gc->vtable->bind(gc, oldGC, draw, read);
+      if (gc->thread_refcount == 0) {
+         gc->currentDrawable = draw;
+         gc->currentReadable = read;
+      }
+      gc->thread_refcount++;
    } else {
       __glXSetCurrentContextNull();
    }
-- 
1.7.5.3.367.ga9930

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to