[PATCHv10 4/5] dri2: Support the DRI2InvalidateBuffers event.
Francisco Jerez
currojerez at riseup.net
Mon Mar 1 11:19:44 PST 2010
Bumps the supported DRI2 protocol version.
Signed-off-by: Francisco Jerez <currojerez at riseup.net>
---
v10: Move resource allocation to dri2ext.c.
configure.ac | 2 +-
hw/xfree86/dri2/dri2.c | 122 +++++++++++++++++++++++++++++++++++++++++++
hw/xfree86/dri2/dri2.h | 6 ++
hw/xfree86/dri2/dri2ext.c | 75 ++++++++++++++++++++++++++-
include/protocol-versions.h | 2 +-
5 files changed, 204 insertions(+), 3 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..a637da1 100644
--- a/hw/xfree86/dri2/dri2.c
+++ b/hw/xfree86/dri2/dri2.c
@@ -42,6 +42,7 @@
#include "dixstruct.h"
#include "dri2.h"
#include "xf86VGAarbiter.h"
+#include "list.h"
#include "xf86.h"
@@ -52,6 +53,14 @@ static DevPrivateKey dri2WindowPrivateKey = &dri2WindowPrivateKeyIndex;
static int dri2PixmapPrivateKeyIndex;
static DevPrivateKey dri2PixmapPrivateKey = &dri2PixmapPrivateKeyIndex;
+typedef struct {
+ struct list head;
+ int id;
+ void (*invalidate)(DrawablePtr, void *);
+ void (*destroy)(DrawablePtr, void *);
+ void *priv;
+} DRI2ClientRefRec, *DRI2ClientRefPtr;
+
typedef struct _DRI2Drawable {
unsigned int refCount;
int width;
@@ -65,6 +74,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,8 +95,19 @@ typedef struct _DRI2Screen {
DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC;
HandleExposuresProcPtr HandleExposures;
+
+ ConfigNotifyProcPtr ConfigNotify;
} DRI2ScreenRec;
+#define WRAP(real, save, hook, f) do { \
+ save->hook = real->hook; \
+ real->hook = f; \
+ } while (0)
+
+#define UNWRAP(real, save, hook) do { \
+ real->hook = save->hook; \
+ } while (0)
+
static DRI2ScreenPtr
DRI2GetScreen(ScreenPtr pScreen)
{
@@ -143,6 +165,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 +429,74 @@ DRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
}
int
+DRI2TrackClient(DrawablePtr pDraw, int id,
+ void (*invalidate)(DrawablePtr, void *),
+ void (*destroy)(DrawablePtr, void *),
+ void *priv)
+{
+ DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
+ DRI2ClientRefPtr ref;
+
+ if (!dd)
+ return BadDrawable;
+
+ /* Make sure the client isn't already in. */
+ DRI2UntrackClient(pDraw, id);
+
+ /* Allocate a client ref. */
+ ref = xalloc(sizeof(*ref));
+ if (!ref)
+ return BadAlloc;
+
+ ref->id = id;
+ ref->invalidate = invalidate;
+ ref->destroy = destroy;
+ 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 (ref->id == id) {
+ if (ref->destroy)
+ ref->destroy(pDraw, ref->priv);
+
+ list_del(&ref->head);
+ 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, ref->id);
+ }
+}
+
+int
DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
unsigned int dest, unsigned int src)
{
@@ -659,6 +750,8 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
pPriv->swapsPending++;
pPriv->last_swap_target = *swap_target;
+ DRI2InvalidateDrawable(pDraw);
+
return Success;
}
@@ -758,6 +851,7 @@ DRI2DestroyDrawable(DrawablePtr pDraw)
{
DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
DRI2DrawablePtr pPriv;
+ DRI2ClientRefPtr ref;
pPriv = DRI2GetDrawable(pDraw);
if (pPriv == NULL)
@@ -776,6 +870,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, ref->id);
+ }
+
/* 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 +912,25 @@ 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) {
+ UNWRAP(pScreen, ds, ConfigNotify);
+ (*pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib);
+ WRAP(pScreen, ds, ConfigNotify, DRI2ConfigNotify);
+ }
+
+ if (dd && (dd->width != w || dd->height != h))
+ DRI2InvalidateDrawable(pDraw);
+}
+
Bool
DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
{
@@ -869,6 +989,8 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
+ WRAP(pScreen, ds, 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..1d5190f 100644
--- a/hw/xfree86/dri2/dri2.h
+++ b/hw/xfree86/dri2/dri2.h
@@ -265,4 +265,10 @@ 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 (*destroy)(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 bd92fd3..5644fe5 100644
--- a/hw/xfree86/dri2/dri2ext.c
+++ b/hw/xfree86/dri2/dri2ext.c
@@ -52,6 +52,7 @@
static ExtensionEntry *dri2Extension;
static RESTYPE dri2DrawableRes;
+static RESTYPE dri2ClientRefRes;
static Bool
validDrawable(ClientPtr client, XID drawable, Mask access_mode,
@@ -197,6 +198,60 @@ ProcDRI2DestroyDrawable(ClientPtr client)
return client->noClientException;
}
+static void
+DRI2InvalidateEvent(DrawablePtr pDraw, void *priv)
+{
+ XID *id = priv;
+ ClientPtr client = clients[CLIENT_ID(*id)];
+ xDRI2InvalidateBuffers event;
+
+ if (!client || client->clientGone)
+ return;
+
+ event.type = DRI2EventBase + DRI2_InvalidateBuffers;
+ event.sequenceNumber = client->sequence;
+ event.drawable = pDraw->id;
+
+ WriteEventsToClient(client, 1, (xEvent *)&event);
+}
+
+static void
+DRI2InvalidateDestroy(DrawablePtr pDraw, void *priv)
+{
+ XID *id = priv;
+
+ FreeResource(*id, dri2ClientRefRes);
+ xfree(id);
+}
+
+static int
+track_client(ClientPtr client, DrawablePtr pDraw)
+{
+ XID *id;
+ int ret = BadAlloc;
+
+ id = xalloc(sizeof(*id));
+ if (!id)
+ goto fail;
+
+ /* Allocate a new resource for the client. */
+ *id = FakeClientID(client->index);
+ if (!AddResource(*id, dri2ClientRefRes, pDraw))
+ goto fail;
+
+ ret = DRI2TrackClient(pDraw, client->index, DRI2InvalidateEvent,
+ DRI2InvalidateDestroy, id);
+ if (ret)
+ goto fail;
+
+ return Success;
+
+fail:
+ if (id)
+ DRI2InvalidateDestroy(pDraw, id);
+
+ return ret;
+}
static void
send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
@@ -266,6 +321,9 @@ ProcDRI2GetBuffers(ClientPtr client)
buffers = DRI2GetBuffers(pDrawable, &width, &height,
attachments, stuff->count, &count);
+ status = track_client(client, pDrawable);
+ if (status)
+ return status;
send_buffers_reply(client, pDrawable, buffers, count, width, height);
@@ -293,6 +351,10 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client)
buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
attachments, stuff->count, &count);
+ status = track_client(client, pDrawable);
+ if (status)
+ return status;
+
send_buffers_reply(client, pDrawable, buffers, count, width, height);
return client->noClientException;
@@ -629,16 +691,27 @@ static int DRI2DrawableGone(pointer p, XID id)
return Success;
}
+static int
+DRI2ClientRefGone(pointer p, XID id)
+{
+ DRI2UntrackClient(p, CLIENT_ID(id));
+ return Success;
+}
+
int DRI2EventBase;
static void
DRI2ExtensionInit(void)
{
dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable");
-
if (!dri2DrawableRes)
return;
+ dri2ClientRefRes =
+ CreateNewResourceType(DRI2ClientRefGone, "DRI2ClientRef");
+ if (!dri2ClientRefRes)
+ return;
+
dri2Extension = AddExtension(DRI2_NAME,
DRI2NumberEvents,
DRI2NumberErrors,
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