[PATCHv9 4/5] dri2: Support the DRI2InvalidateBuffers event.

Francisco Jerez currojerez at riseup.net
Wed Feb 24 14:18:02 PST 2010


Bumps the supported DRI2 protocol version.

Signed-off-by: Francisco Jerez <currojerez at riseup.net>
---
v9: Use a separate resource type to track client refs, let the caller
    specify an opaque closure and pass it to the invalidate handler
    instead of the resource ID, don't call the invalidate hooks on
    drawable destruction, use the linked list implementation borrowed
    from the intel DDX.

    Among other things it should fix the leak pointed out by
    Michel Dänzer.

 configure.ac                |    2 +-
 hw/xfree86/dri2/dri2.c      |  138 +++++++++++++++++++++++++++++++++++++++++++
 hw/xfree86/dri2/dri2.h      |    5 ++
 hw/xfree86/dri2/dri2ext.c   |   24 ++++++++
 include/protocol-versions.h |    2 +-
 5 files changed, 169 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index b9c7574..39ff132 100644
--- a/configure.ac
+++ b/configure.ac
@@ -759,7 +759,7 @@ RECORDPROTO="recordproto >= 1.13.99.1"
 SCRNSAVERPROTO="scrnsaverproto >= 1.1"
 RESOURCEPROTO="resourceproto"
 DRIPROTO="xf86driproto >= 2.1.0"
-DRI2PROTO="dri2proto >= 2.2"
+DRI2PROTO="dri2proto >= 2.3"
 XINERAMAPROTO="xineramaproto"
 BIGFONTPROTO="xf86bigfontproto >= 1.2.0"
 XCALIBRATEPROTO="xcalibrateproto"
diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index 48618e1..60dbf2b 100644
--- a/hw/xfree86/dri2/dri2.c
+++ b/hw/xfree86/dri2/dri2.c
@@ -42,9 +42,12 @@
 #include "dixstruct.h"
 #include "dri2.h"
 #include "xf86VGAarbiter.h"
+#include "list.h"
 
 #include "xf86.h"
 
+static RESTYPE dri2ClientRefRes;
+
 static int dri2ScreenPrivateKeyIndex;
 static DevPrivateKey dri2ScreenPrivateKey = &dri2ScreenPrivateKeyIndex;
 static int dri2WindowPrivateKeyIndex;
@@ -52,6 +55,13 @@ static DevPrivateKey dri2WindowPrivateKey = &dri2WindowPrivateKeyIndex;
 static int dri2PixmapPrivateKeyIndex;
 static DevPrivateKey dri2PixmapPrivateKey = &dri2PixmapPrivateKeyIndex;
 
+typedef struct {
+    struct list		 head;
+    XID			 resource;
+    void	       (*invalidate)(DrawablePtr, void *);
+    void		*priv;
+} DRI2ClientRefRec, *DRI2ClientRefPtr;
+
 typedef struct _DRI2Drawable {
     unsigned int	 refCount;
     int			 width;
@@ -65,6 +75,8 @@ typedef struct _DRI2Drawable {
     CARD64		 target_sbc; /* -1 means no SBC wait outstanding */
     CARD64		 last_swap_target; /* most recently queued swap target */
     int			 swap_limit; /* for N-buffering */
+    struct list		 track_clients; /* Clients to notify on drawable changes. */
+
 } DRI2DrawableRec, *DRI2DrawablePtr;
 
 typedef struct _DRI2Screen *DRI2ScreenPtr;
@@ -84,6 +96,8 @@ typedef struct _DRI2Screen {
     DRI2ScheduleWaitMSCProcPtr	 ScheduleWaitMSC;
 
     HandleExposuresProcPtr       HandleExposures;
+
+    ConfigNotifyProcPtr		 ConfigNotify;
 } DRI2ScreenRec;
 
 static DRI2ScreenPtr
@@ -143,6 +157,7 @@ DRI2CreateDrawable(DrawablePtr pDraw)
     pPriv->swap_interval = 1;
     pPriv->last_swap_target = -1;
     pPriv->swap_limit = 1; /* default to double buffering */
+    list_init(&pPriv->track_clients);
 
     if (pDraw->type == DRAWABLE_WINDOW)
     {
@@ -406,6 +421,87 @@ DRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
 }
 
 int
+DRI2TrackClient(DrawablePtr pDraw, int id,
+		void (*invalidate)(DrawablePtr, void *),
+		void *priv)
+{
+    DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
+    DRI2ClientRefPtr ref;
+
+    if (!dd)
+	return BadDrawable;
+
+    /* Check if the client is already in. */
+    list_for_each_entry(ref, &dd->track_clients, head) {
+	if (CLIENT_ID(ref->resource) == id)
+	    return Success;
+    }
+
+    /* Allocate a client ref. */
+    ref = xalloc(sizeof(*ref));
+    if (!ref)
+	return BadAlloc;
+
+    /* Allocate a resource for it. */
+    ref->resource = FakeClientID(id);
+    if (!AddResource(ref->resource, dri2ClientRefRes, pDraw)) {
+	xfree(ref);
+	return BadAlloc;
+    }
+
+    ref->invalidate = invalidate;
+    ref->priv = priv;
+    list_add(&ref->head, &dd->track_clients);
+
+    return Success;
+}
+
+void
+DRI2UntrackClient(DrawablePtr pDraw, int id)
+{
+    DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
+    DRI2ClientRefPtr ref;
+
+    if (!dd)
+	return;
+
+    list_for_each_entry(ref, &dd->track_clients, head) {
+        if (CLIENT_ID(ref->resource) == id) {
+            list_del(&ref->head);
+
+            FreeResource(ref->resource, dri2ClientRefRes);
+            xfree(ref);
+            break;
+        }
+    }
+}
+
+static void
+DRI2InvalidateDrawable(DrawablePtr pDraw)
+{
+    DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
+    DRI2ClientRefPtr ref;
+
+    if (!dd)
+        return;
+
+    while (!list_is_empty(&dd->track_clients)) {
+        ref = list_first_entry(&dd->track_clients,
+                               DRI2ClientRefRec, head);
+
+        ref->invalidate(pDraw, ref->priv);
+        DRI2UntrackClient(pDraw, CLIENT_ID(ref->resource));
+    }
+}
+
+static int
+DRI2ClientRefGone(pointer p, XID id)
+{
+    DRI2UntrackClient(p, CLIENT_ID(id));
+    return Success;
+}
+
+int
 DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
 	       unsigned int dest, unsigned int src)
 {
@@ -659,6 +755,8 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
     pPriv->swapsPending++;
     pPriv->last_swap_target = *swap_target;
 
+    DRI2InvalidateDrawable(pDraw);
+
     return Success;
 }
 
@@ -758,6 +856,7 @@ DRI2DestroyDrawable(DrawablePtr pDraw)
 {
     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
     DRI2DrawablePtr pPriv;
+    DRI2ClientRefPtr ref;
 
     pPriv = DRI2GetDrawable(pDraw);
     if (pPriv == NULL)
@@ -776,6 +875,13 @@ DRI2DestroyDrawable(DrawablePtr pDraw)
 	xfree(pPriv->buffers);
     }
 
+    while (!list_is_empty(&pPriv->track_clients)) {
+        ref = list_first_entry(&pPriv->track_clients,
+                               DRI2ClientRefRec, head);
+
+        DRI2UntrackClient(pDraw, CLIENT_ID(ref->resource));
+    }
+
     /* If the window is destroyed while we have a swap pending, don't
      * actually free the priv yet.  We'll need it in the DRI2SwapComplete()
      * callback and we'll free it there once we're done. */
@@ -811,6 +917,30 @@ DRI2Authenticate(ScreenPtr pScreen, drm_magic_t magic)
     return TRUE;
 }
 
+static void
+DRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw,
+		 WindowPtr pSib)
+{
+    DrawablePtr pDraw = (DrawablePtr)pWin;
+    ScreenPtr pScreen = pDraw->pScreen;
+    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
+    DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
+
+    if (ds->ConfigNotify) {
+	pScreen->ConfigNotify = ds->ConfigNotify;
+
+	(*pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib);
+
+	ds->ConfigNotify = pScreen->ConfigNotify;
+	pScreen->ConfigNotify = DRI2ConfigNotify;
+    }
+
+    if (!dd || (dd->width == w && dd->height == h))
+	return;
+
+    DRI2InvalidateDrawable(pDraw);
+}
+
 Bool
 DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
 {
@@ -830,6 +960,11 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
         return FALSE;
     }
 
+    dri2ClientRefRes =
+	CreateNewResourceType(DRI2ClientRefGone, "DRI2ClientRef");
+    if (!dri2ClientRefRes)
+	return FALSE;
+
     ds = xcalloc(1, sizeof *ds);
     if (!ds)
 	return FALSE;
@@ -869,6 +1004,9 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
 
     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
 
+    ds->ConfigNotify = pScreen->ConfigNotify;
+    pScreen->ConfigNotify = DRI2ConfigNotify;
+
     xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n");
     for (i = 0; i < sizeof(driverTypeNames) / sizeof(driverTypeNames[0]); i++) {
 	if (i < ds->numDrivers && ds->driverNames[i]) {
diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h
index 1c8626b..518d18a 100644
--- a/hw/xfree86/dri2/dri2.h
+++ b/hw/xfree86/dri2/dri2.h
@@ -265,4 +265,9 @@ extern _X_EXPORT void DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw,
 					  int frame, unsigned int tv_sec,
 					  unsigned int tv_usec);
 
+extern _X_EXPORT int DRI2TrackClient(DrawablePtr pDraw, int id,
+				     void (*invalidate)(DrawablePtr, void *),
+				     void *priv);
+extern _X_EXPORT void DRI2UntrackClient(DrawablePtr pDraw, int id);
+
 #endif
diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c
index 3e6b03e..992df68 100644
--- a/hw/xfree86/dri2/dri2ext.c
+++ b/hw/xfree86/dri2/dri2ext.c
@@ -197,6 +197,21 @@ ProcDRI2DestroyDrawable(ClientPtr client)
     return client->noClientException;
 }
 
+static void
+DRI2InvalidateBuffersEvent(DrawablePtr pDraw, void *priv)
+{
+    xDRI2InvalidateBuffers event;
+    ClientPtr client = priv;
+
+    if (client->clientGone)
+	return;
+
+    event.type = DRI2EventBase + DRI2_InvalidateBuffers;
+    event.sequenceNumber = client->sequence;
+    event.drawable = pDraw->id;
+
+    WriteEventsToClient(client, 1, (xEvent *)&event);
+}
 
 static void
 send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
@@ -266,6 +281,10 @@ ProcDRI2GetBuffers(ClientPtr client)
     buffers = DRI2GetBuffers(pDrawable, &width, &height,
 			     attachments, stuff->count, &count);
 
+    status = DRI2TrackClient(pDrawable, client->index,
+			     DRI2InvalidateBuffersEvent, client);
+    if (status)
+	return status;
 
     send_buffers_reply(client, pDrawable, buffers, count, width, height);
 
@@ -293,6 +312,11 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client)
     buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
 				       attachments, stuff->count, &count);
 
+    status = DRI2TrackClient(pDrawable, client->index,
+			     DRI2InvalidateBuffersEvent, client);
+    if (status)
+	return status;
+
     send_buffers_reply(client, pDrawable, buffers, count, width, height);
 
     return client->noClientException;
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index c74b7fa..c425eef 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -53,7 +53,7 @@
 
 /* DRI2 */
 #define SERVER_DRI2_MAJOR_VERSION		1
-#define SERVER_DRI2_MINOR_VERSION		2
+#define SERVER_DRI2_MINOR_VERSION		3
 
 /* Generic event extension */
 #define SERVER_GE_MAJOR_VERSION                 1
-- 
1.6.4.4



More information about the xorg-devel mailing list