dri2: Avoid round-tripping on DRI2GetBuffers for the same set of buffers.
authorEric Anholt <eric@anholt.net>
Fri, 30 Jan 2009 21:23:12 +0000 (13:23 -0800)
committerEric Anholt <eric@anholt.net>
Mon, 2 Feb 2009 20:00:39 +0000 (12:00 -0800)
We only wanted to request when asked for the same set of buffers when a resize
has happened.  We can just watch the protocol stream for a ConfigureNotify
and flag to do it then.

This is about a 5% win from doing two glViewport()s per frame in openarena.

src/glx/x11/dri2_glx.c
src/glx/x11/glxclient.h

index d16f809..41861d5 100644 (file)
@@ -60,6 +60,9 @@ struct __GLXDRIdisplayPrivateRec {
     int driMajor;
     int driMinor;
     int driPatch;
+
+    unsigned long configureSeqno;
+    Bool (*oldConfigProc)(Display *, XEvent *, xEvent *);
 };
 
 struct __GLXDRIcontextPrivateRec {
@@ -73,6 +76,7 @@ struct __GLXDRIdrawablePrivateRec {
     __DRIbuffer buffers[5];
     int bufferCount;
     int width, height;
+    unsigned long configureSeqno;
 };
 
 static void dri2DestroyContext(__GLXDRIcontext *context,
@@ -166,6 +170,7 @@ static __GLXDRIdrawable *dri2CreateDrawable(__GLXscreenConfigs *psc,
     pdraw->base.xDrawable = xDrawable;
     pdraw->base.drawable = drawable;
     pdraw->base.psc = psc;
+    pdraw->configureSeqno = ~0;
 
     DRI2CreateDrawable(psc->dpy, xDrawable);
 
@@ -223,9 +228,30 @@ dri2GetBuffers(__DRIdrawable *driDrawable,
               int *out_count, void *loaderPrivate)
 {
     __GLXDRIdrawablePrivate *pdraw = loaderPrivate;
+    __GLXdisplayPrivate *dpyPriv = __glXInitialize(pdraw->base.psc->dpy);
+    __GLXDRIdisplayPrivate *pdp = (__GLXDRIdisplayPrivate *)dpyPriv->dri2Display;
     DRI2Buffer *buffers;
     int i;
 
+    /**
+     * Check if a ConfigureNotify has come in since we last asked for the
+     * buffers associated with this drawable.  If not, we can assume that they're
+     * the same set at glViewport time, and save a synchronous round-trip to the
+     * X Server.
+     */
+    if (pdraw->configureSeqno == pdp->configureSeqno &&
+       count == pdraw->bufferCount) {
+       for (i = 0; i < count; i++) {
+           if (pdraw->buffers[i].attachment != attachments[i])
+               break;
+       }
+       if (i == count) {
+           *out_count = pdraw->bufferCount;
+           return pdraw->buffers;
+       }
+    }
+    pdraw->configureSeqno = pdp->configureSeqno;
+
     buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
                             width, height, attachments, count, out_count);
     if (buffers == NULL)
@@ -233,6 +259,7 @@ dri2GetBuffers(__DRIdrawable *driDrawable,
 
     pdraw->width = *width;
     pdraw->height = *height;
+    pdraw->bufferCount = *out_count;
 
     /* This assumes the DRI2 buffer attachment tokens matches the
      * __DRIbuffer tokens. */
@@ -365,6 +392,28 @@ static void dri2DestroyDisplay(__GLXDRIdisplay *dpy)
     Xfree(dpy);
 }
 
+/**
+ * Makes a note on receiving ConfigureNotify that we need to re-check the
+ * DRI2 buffers, as window sizes may have resulted in reallocation.
+ */
+static Bool dri2ConfigureNotifyProc(Display *dpy, XEvent *re, xEvent *event)
+{
+    __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy);
+    __GLXDRIdisplayPrivate *pdp;
+    Bool ret;
+
+    /* We should always be able to find our pdp, as it only gets torn down
+     * when the Display is torn down.
+     */
+    pdp = (__GLXDRIdisplayPrivate *)dpyPriv->dri2Display;
+
+    ret = pdp->oldConfigProc(dpy, re, event);
+
+    pdp->configureSeqno = re->xconfigure.serial;
+
+    return ret;
+}
+
 /*
  * Allocate, initialize and return a __DRIdisplayPrivate object.
  * This is called from __glXInitialize() when we are given a new
@@ -387,6 +436,9 @@ _X_HIDDEN __GLXDRIdisplay *dri2CreateDisplay(Display *dpy)
        return NULL;
     }
 
+    pdp->oldConfigProc = XESetWireToEvent(dpy, ConfigureNotify,
+                                         dri2ConfigureNotifyProc);
+
     pdp->driPatch = 0;
 
     pdp->base.destroyDisplay = dri2DestroyDisplay;
index 16f6074..bdc6287 100644 (file)
@@ -602,6 +602,7 @@ extern void __glXSendLargeCommand(__GLXcontext *, const GLvoid *, GLint,
                                  const GLvoid *, GLint);
 
 /* Initialize the GLX extension for dpy */
+extern __GLXdisplayPrivate * __glXGetPrivateFromDisplay(Display *dpy);
 extern __GLXdisplayPrivate *__glXInitialize(Display*);
 
 /************************************************************************/