[PATCH] DRI2: Free DRI2 drawable references in DRI2DestroyDrawable

Kristian Høgsberg krh at bitplanet.net
Fri Oct 29 12:49:58 PDT 2010


On Mon, Oct 25, 2010 at 9:55 AM, Pauli Nieminen
<ext-pauli.nieminen at nokia.com> wrote:
> If client calls DRI2CreateDrawable multiple times for same drawable
> DRI2 creates multiple references. Multiple references cause DRI2 send
> multiple invalidate events for same client.

Yup, there is a leak, but I think we should implement
DRI2DestroyDrawable by looking up the first DRI2DrawableRef where with
a dri2_id matching the client id and then call FreeResource(id, FALSE)
on that.

Kristian

> Problem is easy to spot from xtrace. For example following filtered
> snippet from problematic client:
>
> 000:<:0b85: 16: DRI2-Request(132,5): GetBuffers drawable=0x00800011
> attachments={attachment=BackLeft(0x00000001)};
> 000:<:0b89: 32: DRI2-Request(132,8): SwapBuffers drawable=0x00800011
> target_msc_hi=0 target_msc_lo=0 divisor_hi=0 divisor_lo=0 remainder_hi=0
> remainder_lo=0
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b89: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:<:0b8e: 16: DRI2-Request(132,5): GetBuffers drawable=0x00800011
> attachments={attachment=BackLeft(0x00000001)};
> 000:<:0b8f: 32: DRI2-Request(132,8): SwapBuffers drawable=0x00800011
> target_msc_hi=0 target_msc_lo=0 divisor_hi=0 divisor_lo=0 remainder_hi=0
> remainder_lo=0
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:>:0b8f: Event DRI2-InvalidateBuffers(67) drawable=0x00800011
> 000:<:0bc4: 16: DRI2-Request(132,5): GetBuffers drawable=0x00800011
> attachments={attachment=BackLeft(0x00000001)};
> 000:<:0bc5: 32: DRI2-Request(132,8): SwapBuffers drawable=0x00800011
> target_msc_hi=0 target_msc_lo=0 divisor_hi=0 divisor_lo=0 remainder_hi=0
> remainder_lo=0
>
> Problem is triggered because client side EGL implementation is using
> DRI2 directly.
>
> DRI2 code in server doesn't handle DRI2DestroyDrawable that leaks
> references. If client recreates rendering target EGL destroys and
> creates DRI2 drawable. In that case DRI2DestroyDrawable leaks DRI2
> drawable references.
>
> To fix this memory leak/performance problem server has to free the
> reference when client requests for it.
>
> If client calls DRI2CreateDrawable twice for same drawable same
> reference is reused and reference count is incremented.
>
> Signed-off-by: Pauli Nieminen <ext-pauli.nieminen at nokia.com>
> CC: Kristian Høgsberg <krh at bitplanet.net>
>
> ---
>  hw/xfree86/dri2/dri2.c    |  100 +++++++++++++++++++++++++++++++++++---------
>  hw/xfree86/dri2/dri2.h    |    4 +-
>  hw/xfree86/dri2/dri2ext.c |    2 +-
>  3 files changed, 83 insertions(+), 23 deletions(-)
>
> diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
> index 34f735f..103db1a 100644
> --- a/hw/xfree86/dri2/dri2.c
> +++ b/hw/xfree86/dri2/dri2.c
> @@ -193,6 +193,7 @@ DRI2AllocateDrawable(DrawablePtr pDraw)
>  typedef struct DRI2DrawableRefRec {
>     XID                  id;
>     XID                  dri2_id;
> +    int                  refcnt;
>     DRI2InvalidateProcPtr      invalidate;
>     void        *priv;
>     struct list          link;
> @@ -229,6 +230,7 @@ DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id,
>
>     ref->id = id;
>     ref->dri2_id = dri2_id;
> +    ref->refcnt = 1;
>     ref->invalidate = invalidate;
>     ref->priv = priv;
>     list_add(&ref->link, &pPriv->reference_list);
> @@ -236,11 +238,24 @@ DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id,
>     return Success;
>  }
>
> +static DRI2DrawableRefPtr
> +DRI2FindClientDrawableRef(ClientPtr client, DRI2DrawablePtr pPriv)
> +{
> +       DRI2DrawableRefPtr ref;
> +
> +       list_for_each_entry(ref, &pPriv->reference_list, link) {
> +               if (CLIENT_ID(ref->dri2_id) == client->index)
> +                       return ref;
> +       }
> +       return NULL;
> +}
> +
>  int
>  DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
>                   DRI2InvalidateProcPtr invalidate, void *priv)
>  {
>     DRI2DrawablePtr pPriv;
> +    DRI2DrawableRefPtr ref;
>     XID dri2_id;
>     int rc;
>
> @@ -249,6 +264,11 @@ DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
>        pPriv = DRI2AllocateDrawable(pDraw);
>     if (pPriv == NULL)
>        return BadAlloc;
> +    ref = DRI2FindClientDrawableRef(client, pPriv);
> +    if (ref) {
> +           ref->refcnt++;
> +           return Success;
> +    }
>
>     dri2_id = FakeClientID(client->index);
>     rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv);
> @@ -258,34 +278,15 @@ DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
>     return Success;
>  }
>
> -static int DRI2DrawableGone(pointer p, XID id)
> +static int
> +DRI2CleanupDrawable(DRI2DrawablePtr pPriv)
>  {
> -    DRI2DrawablePtr pPriv = p;
>     DRI2ScreenPtr   ds = pPriv->dri2_screen;
> -    DRI2DrawableRefPtr ref, next;
>     WindowPtr pWin;
>     PixmapPtr pPixmap;
>     DrawablePtr pDraw;
>     int i;
>
> -    list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
> -       if (ref->dri2_id == id) {
> -           list_del(&ref->link);
> -           /* If this was the last ref under this X drawable XID,
> -            * unregister the X drawable resource. */
> -           if (!DRI2LookupDrawableRef(pPriv, ref->id))
> -               FreeResourceByType(ref->id, dri2DrawableRes, TRUE);
> -           free(ref);
> -           break;
> -       }
> -
> -       if (ref->id == id) {
> -           list_del(&ref->link);
> -           FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE);
> -           free(ref);
> -       }
> -    }
> -
>     if (!list_is_empty(&pPriv->reference_list))
>        return Success;
>
> @@ -310,6 +311,63 @@ static int DRI2DrawableGone(pointer p, XID id)
>     return Success;
>  }
>
> +int
> +DRI2DestroyDrawable(ClientPtr client, DrawablePtr pDraw, XID id)
> +{
> +    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
> +    DRI2DrawableRefPtr ref, next;
> +    Bool found = FALSE;
> +
> +    if (!pPriv)
> +       return BadDrawable;
> +
> +    list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
> +       if (CLIENT_ID(ref->dri2_id) == client->index) {
> +           found = TRUE;
> +           if (--ref->refcnt > 0)
> +               break;
> +           list_del(&ref->link);
> +           FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE);
> +           /* If this was the last ref under this X drawable XID,
> +            * unregister the X drawable resource. */
> +           if (!DRI2LookupDrawableRef(pPriv, ref->id))
> +               FreeResourceByType(ref->id, dri2DrawableRes, TRUE);
> +           free(ref);
> +           break;
> +       }
> +    }
> +
> +    if (!found)
> +       return BadDrawable;
> +
> +    return DRI2CleanupDrawable(pPriv);
> +}
> +
> +static int DRI2DrawableGone(pointer p, XID id)
> +{
> +    DRI2DrawablePtr pPriv = p;
> +    DRI2DrawableRefPtr ref, next;
> +
> +    list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
> +       if (ref->dri2_id == id) {
> +           list_del(&ref->link);
> +           /* If this was the last ref under this X drawable XID,
> +            * unregister the X drawable resource. */
> +           if (!DRI2LookupDrawableRef(pPriv, ref->id))
> +               FreeResourceByType(ref->id, dri2DrawableRes, TRUE);
> +           free(ref);
> +           break;
> +       }
> +
> +       if (ref->id == id) {
> +           list_del(&ref->link);
> +           FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE);
> +           free(ref);
> +       }
> +    }
> +    return DRI2CleanupDrawable(pPriv);
> +}
> +
>  static int
>  find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
>  {
> diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h
> index fe0bf6c..dd63c30 100644
> --- a/hw/xfree86/dri2/dri2.h
> +++ b/hw/xfree86/dri2/dri2.h
> @@ -214,7 +214,9 @@ extern _X_EXPORT int DRI2CreateDrawable(ClientPtr client,
>                                        DRI2InvalidateProcPtr invalidate,
>                                        void *priv);
>
> -extern _X_EXPORT void DRI2DestroyDrawable(DrawablePtr pDraw);
> +extern _X_EXPORT int DRI2DestroyDrawable(ClientPtr client,
> +                                         DrawablePtr pDraw,
> +                                         XID id);
>
>  extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffers(DrawablePtr pDraw,
>                             int *width,
> diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c
> index 4e48e65..c7e6be1 100644
> --- a/hw/xfree86/dri2/dri2ext.c
> +++ b/hw/xfree86/dri2/dri2ext.c
> @@ -200,7 +200,7 @@ ProcDRI2DestroyDrawable(ClientPtr client)
>                       &pDrawable, &status))
>        return status;
>
> -    return Success;
> +    return DRI2DestroyDrawable(client, pDrawable, stuff->drawable);
>  }
>
>
> --
> 1.7.0.4
>
>


More information about the xorg-devel mailing list