Eric,

your mesa commit dd1c68f15123a889a3ce9d2afe724e272d163e32 ('dri2: Avoid
round-tripping on DRI2GetBuffers for the same set of buffers.') breaks
when the display connection doesn't receive ConfigureNotify events. This
can be reproduced by running a 3D application in a guest operating
system in VMware Workstation, which calls

        XSelectInput(..., ExposureMask);

on the child window used for GL rendering. The GL driver ends up using
stale buffers / window size, so the output is cropped and misplaced.

I wrote up the attached patch to fix this by adding StructureNotifyMask
to the event mask of the DRI2 display connection; this fixes the problem
above, but on second thought I'm concerned about potential side effects
of this approach on display connections which are otherwise not
interested in ConfigureNotify events. If I'm reading the libX11 event
queue management code correctly, this could result in an unlimited
number of ConfigureNotify events queueing up on the client side. In
practice the number may usually be low, but there could be more subtle
side effects, e.g. because the queue would not empty up anymore.

So for Mesa 7.4, I suspect the safest course of action is to revert
dd1c68f15123a889a3ce9d2afe724e272d163e32. Something like the change
below could be used to at least limit the number of additional X server
round-trips to one per frame.

What do you think?


commit 31cc890207e18f7f538502cca0b9492b4938b7e7
Author: Michel Dänzer <[email protected]>
Date:   Tue Mar 24 17:35:29 2009 +0100

    DRI2: Avoid changing buffers in the middle of a frame.

diff --git a/src/glx/x11/dri2_glx.c b/src/glx/x11/dri2_glx.c
index 9c8f110..de187f9 100644
--- a/src/glx/x11/dri2_glx.c
+++ b/src/glx/x11/dri2_glx.c
@@ -76,6 +76,7 @@ struct __GLXDRIdrawablePrivateRec {
     int have_back;
     int have_front;
     int have_fake_front;
+    GLboolean buffers_cached;
 };
 
 static void dri2DestroyContext(__GLXDRIcontext *context,
@@ -170,6 +171,7 @@ static __GLXDRIdrawable 
*dri2CreateDrawable(__GLXscreenConfigs *psc,
     pdraw->base.drawable = drawable;
     pdraw->base.psc = psc;
     pdraw->bufferCount = 0;
+    pdraw->buffers_cached = GL_FALSE;
 
     DRI2CreateDrawable(psc->dpy, xDrawable);
 
@@ -194,6 +196,8 @@ static void dri2CopySubBuffer(__GLXDRIdrawable *pdraw,
     XRectangle xrect;
     XserverRegion region;
 
+    priv->buffers_cached = GL_FALSE;
+
     /* Check we have the right attachments */
     if (!(priv->have_front && priv->have_back))
        return;
@@ -228,6 +232,8 @@ static void dri2WaitX(__GLXDRIdrawable *pdraw)
     XRectangle xrect;
     XserverRegion region;
 
+    priv->buffers_cached = GL_FALSE;
+
     /* Check we have the right attachments */
     if (!(priv->have_fake_front && priv->have_front))
        return;
@@ -254,6 +260,8 @@ static void dri2WaitGL(__GLXDRIdrawable *pdraw)
     XRectangle xrect;
     XserverRegion region;
 
+    priv->buffers_cached = GL_FALSE;
+
     if (!(priv->have_fake_front && priv->have_front))
        return;
 
@@ -291,6 +299,22 @@ dri2GetBuffers(__DRIdrawable *driDrawable,
     DRI2Buffer *buffers;
     int i;
 
+    /**
+     * We want to avoid changing the buffers in the middle of a frame.
+     */
+    if (pdraw->buffers_cached && count == pdraw->bufferCount) {
+       for (i = 0; i < count; i++) {
+           if (pdraw->buffers[i].attachment != attachments[i])
+               break;
+       }
+       if (i == count) {
+           *width = pdraw->width;
+           *height = pdraw->height;
+           *out_count = pdraw->bufferCount;
+           return pdraw->buffers;
+       }
+    }
+
     buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
                             width, height, attachments, count, out_count);
     if (buffers == NULL)
@@ -321,6 +345,8 @@ dri2GetBuffers(__DRIdrawable *driDrawable,
 
     Xfree(buffers);
 
+    pdraw->buffers_cached = GL_TRUE;
+
     return pdraw->buffers;
 }
 


-- 
Earthling Michel Dänzer           |                http://www.vmware.com
Libre software enthusiast         |          Debian, X and DRI developer
commit 29cd508ed55b9cccd617c1c447573d9798e9d142
Author: Michel Dänzer <[email protected]>
Date:   Fri Mar 20 17:39:42 2009 +0100

    DRI2: Fixes for dri2GetBuffers X server round-trip avoidance.
    
    * Attempt to make sure we receive ConfigureNotify events for windows. Otherwise
      we won't know when the window size changes and will return stale buffers.
      This could be reproduced by running a 3D application in a VMware Workstation
      guest.
    * Return the current width and height to the dri2GetBuffers caller even if
      we're using cached values. Otherwise the caller may end up using
      stale or even uninitialized values.

diff --git a/src/glx/x11/dri2_glx.c b/src/glx/x11/dri2_glx.c
index 0ef5d3a..89e1def 100644
--- a/src/glx/x11/dri2_glx.c
+++ b/src/glx/x11/dri2_glx.c
@@ -157,6 +157,18 @@ static void dri2DestroyDrawable(__GLXDRIdrawable *pdraw)
     Xfree(pdraw);
 }
 
+
+static Bool isWindow;
+
+/* Temporary X error handler for changing window event mask */
+static int isWindowXErrorHandler(Display *dpy, XErrorEvent *xerr)
+{
+    if (xerr->error_code == BadWindow)
+	isWindow = False;
+
+    return 0;
+}
+
 static __GLXDRIdrawable *dri2CreateDrawable(__GLXscreenConfigs *psc,
 					    XID xDrawable,
 					    GLXDrawable drawable,
@@ -164,6 +176,8 @@ static __GLXDRIdrawable *dri2CreateDrawable(__GLXscreenConfigs *psc,
 {
     __GLXDRIdrawablePrivate *pdraw;
     __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
+    int (*oldXErrorHandler)(Display *, XErrorEvent *);
+    XWindowAttributes xwa;
 
     pdraw = Xmalloc(sizeof(*pdraw));
     if (!pdraw)
@@ -189,6 +203,22 @@ static __GLXDRIdrawable *dri2CreateDrawable(__GLXscreenConfigs *psc,
 	return NULL;
     }
 
+    /* If the drawable is a window, attempt to ensure we'll receive
+     * ConfigureNotify events for it.
+     */
+    isWindow = True;
+
+    XSync(psc->dpy, GL_FALSE);
+    oldXErrorHandler = XSetErrorHandler(isWindowXErrorHandler);
+    XGetWindowAttributes(psc->dpy, xDrawable, &xwa);
+
+    if (isWindow && !(xwa.your_event_mask & StructureNotifyMask))
+	XSelectInput(psc->dpy, xDrawable,
+		     xwa.your_event_mask | StructureNotifyMask);
+
+    XSync(psc->dpy, GL_FALSE);
+    XSetErrorHandler(oldXErrorHandler);
+
     return &pdraw->base;
 }
 
@@ -311,6 +341,8 @@ dri2GetBuffers(__DRIdrawable *driDrawable,
 		break;
 	}
 	if (i == count) {
+	    *width = pdraw->width;
+	    *height = pdraw->height;
 	    *out_count = pdraw->bufferCount;
 	    return pdraw->buffers;
 	}
------------------------------------------------------------------------------
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
_______________________________________________
Mesa3d-dev mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev

Reply via email to