diff mbox

[mesa,8/9] glx/dri2: Move the wait after SwapBuffers into the next GetBuffers

Message ID 1421665245-5994-9-git-send-email-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson Jan. 19, 2015, 11 a.m. UTC
As the SBC from the reply from SwapBuffers is not used immediately and
can be easily determined by counting the new of SwapBuffers requests
made by the client, we can defer the synchronisation point to the
pending GetBuffers round trip. (We force the invalidation event in order
to require the GetBuffers round trip - we know that all X servers will
send the invalidation after SwapBuffers and that invalidation will
arrive before the SwapBuffers reply, so no extra roundtrips are forced.)

An important side-effect is demonstrated in the next patch where we can
detect when the buffers are stale before querying properties.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 src/glx/dri2_glx.c | 73 ++++++++++++++++++++++++++++--------------------------
 1 file changed, 38 insertions(+), 35 deletions(-)

Comments

Ian Romanick Jan. 20, 2015, 8:03 p.m. UTC | #1
On 01/19/2015 03:00 AM, Chris Wilson wrote:
> As the SBC from the reply from SwapBuffers is not used immediately and
> can be easily determined by counting the new of SwapBuffers requests
> made by the client, we can defer the synchronisation point to the
> pending GetBuffers round trip. (We force the invalidation event in order
> to require the GetBuffers round trip - we know that all X servers will
> send the invalidation after SwapBuffers and that invalidation will
> arrive before the SwapBuffers reply, so no extra roundtrips are forced.)

This is a pretty big change in behavior.  How much testing has it
received?  I'm nervous that applications that "work fine" today could
misbehave in subtle ways.  How much work would it be to add a way to
disable the new behavior, perhaps via an environment variable, at
run-time?  That would make it much easier for users to determine whether
this change was responsible for a problem in some game we don't have.

Additional comments in-line below.

> An important side-effect is demonstrated in the next patch where we can
> detect when the buffers are stale before querying properties.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  src/glx/dri2_glx.c | 73 ++++++++++++++++++++++++++++--------------------------
>  1 file changed, 38 insertions(+), 35 deletions(-)
> 
> diff --git a/src/glx/dri2_glx.c b/src/glx/dri2_glx.c
> index 462d560..0577804 100644
> --- a/src/glx/dri2_glx.c
> +++ b/src/glx/dri2_glx.c
> @@ -93,6 +93,10 @@ struct dri2_drawable
>     int have_back;
>     int have_fake_front;
>     int swap_interval;
> +   int swap_pending;
> +
> +   xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie;
> +   int64_t last_swap_sbc;
>  
>     uint64_t previous_time;
>     unsigned frames;
> @@ -778,50 +782,51 @@ static void show_fps(struct dri2_drawable *draw)
>     }
>  }
>  
> -static int64_t
> -dri2XcbSwapBuffers(Display *dpy,
> -                  __GLXDRIdrawable *pdraw,
> +static void
> +dri2XcbSwapBuffers(struct dri2_drawable *priv,
>                    int64_t target_msc,
>                    int64_t divisor,
>                    int64_t remainder)
>  {
> -   xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie;
> -   xcb_dri2_swap_buffers_reply_t *swap_buffers_reply;
> +   xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
>     uint32_t target_msc_hi, target_msc_lo;
>     uint32_t divisor_hi, divisor_lo;
>     uint32_t remainder_hi, remainder_lo;
> -   int64_t ret = 0;
> -   xcb_connection_t *c = XGetXCBConnection(dpy);
>  
>     split_counter(target_msc, &target_msc_hi, &target_msc_lo);
>     split_counter(divisor, &divisor_hi, &divisor_lo);
>     split_counter(remainder, &remainder_hi, &remainder_lo);
>  
> -   swap_buffers_cookie =
> -      xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable,
> +   priv->swap_buffers_cookie =
> +      xcb_dri2_swap_buffers_unchecked(c, priv->base.xDrawable,
>                                        target_msc_hi, target_msc_lo,
>                                        divisor_hi, divisor_lo,
>                                        remainder_hi, remainder_lo);
> +   xcb_flush(c);
> +   priv->swap_pending++;
>  
> -   /* Immediately wait on the swapbuffers reply.  If we didn't, we'd have
> -    * to do so some time before reusing a (non-pageflipped) backbuffer.
> -    * Otherwise, the new rendering could get ahead of the X Server's
> -    * dispatch of the swapbuffer and you'd display garbage.
> -    *
> -    * We use XSync() first to reap the invalidate events through the event
> -    * filter, to ensure that the next drawing doesn't use an invalidated
> -    * buffer.
> -    */
> -   XSync(dpy, False);
> +   /* Force a synchronous completion prior to the next rendering */
> +   dri2InvalidateBuffers(priv->base.psc->dpy, priv->base.xDrawable);
> +}
> +
> +static void dri2XcbSwapBuffersComplete(struct dri2_drawable *priv)

static void
dri2XcbSwapBuffersComplete(struct dri2_drawable *priv)

> +{
> +   xcb_dri2_swap_buffers_reply_t *swap_buffers_reply;
> +
> +   if (!priv->swap_pending)
> +      return;
> +
> +   priv->swap_pending = 0;

Is this actually right?  dri2XcbSwapBuffers increments the count, do we
know the single reply will be for all pending swaps?

>  
>     swap_buffers_reply =
> -      xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL);
> -   if (swap_buffers_reply) {
> -      ret = merge_counter(swap_buffers_reply->swap_hi,
> -                          swap_buffers_reply->swap_lo);
> -      free(swap_buffers_reply);
> -   }
> -   return ret;
> +        xcb_dri2_swap_buffers_reply(XGetXCBConnection(priv->base.psc->dpy),
> +				    priv->swap_buffers_cookie, NULL);
> +   if (swap_buffers_reply == NULL)
> +      return;
> +
> +   priv->last_swap_sbc = merge_counter(swap_buffers_reply->swap_hi,
> +                                       swap_buffers_reply->swap_lo);
> +   free(swap_buffers_reply);
>  }
>  
>  static int64_t
> @@ -833,11 +838,10 @@ dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
>      struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
>      struct dri2_display *pdp =
>  	(struct dri2_display *)dpyPriv->dri2Display;
> -    int64_t ret = 0;
>  
>      /* Check we have the right attachments */
>      if (!priv->have_back)
> -	return ret;
> +	return 0;
>  
>      /* Old servers can't handle swapbuffers */
>      if (!pdp->swapAvailable) {
> @@ -850,19 +854,14 @@ dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
>            flags |= __DRI2_FLUSH_CONTEXT;
>         dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
>  
> -       ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw,
> -                                target_msc, divisor, remainder);
> +       dri2XcbSwapBuffers(priv, target_msc, divisor, remainder);
>      }
>  
>      if (psc->show_fps_interval) {
>         show_fps(priv);
>      }
>  
> -    /* Old servers don't send invalidate events */
> -    if (!pdp->invalidateAvailable)
> -       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable);

It seems like this should still happen somewhere, right?  Or are we
assuming there are no more old servers anywhere (that will be used with
this)?

> -
> -    return ret;
> +    return priv->last_swap_sbc + priv->swap_pending;
>  }
>  
>  static __DRIbuffer *
> @@ -885,6 +884,8 @@ dri2GetBuffers(__DRIdrawable * driDrawable,
>  
>     free(buffers);
>  
> +   dri2XcbSwapBuffersComplete(pdraw);
> +

Are there other places that need this?  It seems like all the important
paths will eventually hit this or dri2GetBuffersWithFormat.  Will
glFinish always hit this?  Like:

    glXSwapBuffers();
    glFinish();

Hmm... that case may not even matter.

>     return pdraw->buffers;
>  }
>  
> @@ -910,6 +911,8 @@ dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
>  
>     free(buffers);
>  
> +   dri2XcbSwapBuffersComplete(pdraw);
> +
>     return pdraw->buffers;
>  }
>
diff mbox

Patch

diff --git a/src/glx/dri2_glx.c b/src/glx/dri2_glx.c
index 462d560..0577804 100644
--- a/src/glx/dri2_glx.c
+++ b/src/glx/dri2_glx.c
@@ -93,6 +93,10 @@  struct dri2_drawable
    int have_back;
    int have_fake_front;
    int swap_interval;
+   int swap_pending;
+
+   xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie;
+   int64_t last_swap_sbc;
 
    uint64_t previous_time;
    unsigned frames;
@@ -778,50 +782,51 @@  static void show_fps(struct dri2_drawable *draw)
    }
 }
 
-static int64_t
-dri2XcbSwapBuffers(Display *dpy,
-                  __GLXDRIdrawable *pdraw,
+static void
+dri2XcbSwapBuffers(struct dri2_drawable *priv,
                   int64_t target_msc,
                   int64_t divisor,
                   int64_t remainder)
 {
-   xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie;
-   xcb_dri2_swap_buffers_reply_t *swap_buffers_reply;
+   xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
    uint32_t target_msc_hi, target_msc_lo;
    uint32_t divisor_hi, divisor_lo;
    uint32_t remainder_hi, remainder_lo;
-   int64_t ret = 0;
-   xcb_connection_t *c = XGetXCBConnection(dpy);
 
    split_counter(target_msc, &target_msc_hi, &target_msc_lo);
    split_counter(divisor, &divisor_hi, &divisor_lo);
    split_counter(remainder, &remainder_hi, &remainder_lo);
 
-   swap_buffers_cookie =
-      xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable,
+   priv->swap_buffers_cookie =
+      xcb_dri2_swap_buffers_unchecked(c, priv->base.xDrawable,
                                       target_msc_hi, target_msc_lo,
                                       divisor_hi, divisor_lo,
                                       remainder_hi, remainder_lo);
+   xcb_flush(c);
+   priv->swap_pending++;
 
-   /* Immediately wait on the swapbuffers reply.  If we didn't, we'd have
-    * to do so some time before reusing a (non-pageflipped) backbuffer.
-    * Otherwise, the new rendering could get ahead of the X Server's
-    * dispatch of the swapbuffer and you'd display garbage.
-    *
-    * We use XSync() first to reap the invalidate events through the event
-    * filter, to ensure that the next drawing doesn't use an invalidated
-    * buffer.
-    */
-   XSync(dpy, False);
+   /* Force a synchronous completion prior to the next rendering */
+   dri2InvalidateBuffers(priv->base.psc->dpy, priv->base.xDrawable);
+}
+
+static void dri2XcbSwapBuffersComplete(struct dri2_drawable *priv)
+{
+   xcb_dri2_swap_buffers_reply_t *swap_buffers_reply;
+
+   if (!priv->swap_pending)
+      return;
+
+   priv->swap_pending = 0;
 
    swap_buffers_reply =
-      xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL);
-   if (swap_buffers_reply) {
-      ret = merge_counter(swap_buffers_reply->swap_hi,
-                          swap_buffers_reply->swap_lo);
-      free(swap_buffers_reply);
-   }
-   return ret;
+        xcb_dri2_swap_buffers_reply(XGetXCBConnection(priv->base.psc->dpy),
+				    priv->swap_buffers_cookie, NULL);
+   if (swap_buffers_reply == NULL)
+      return;
+
+   priv->last_swap_sbc = merge_counter(swap_buffers_reply->swap_hi,
+                                       swap_buffers_reply->swap_lo);
+   free(swap_buffers_reply);
 }
 
 static int64_t
@@ -833,11 +838,10 @@  dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
     struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
     struct dri2_display *pdp =
 	(struct dri2_display *)dpyPriv->dri2Display;
-    int64_t ret = 0;
 
     /* Check we have the right attachments */
     if (!priv->have_back)
-	return ret;
+	return 0;
 
     /* Old servers can't handle swapbuffers */
     if (!pdp->swapAvailable) {
@@ -850,19 +854,14 @@  dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
           flags |= __DRI2_FLUSH_CONTEXT;
        dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
 
-       ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw,
-                                target_msc, divisor, remainder);
+       dri2XcbSwapBuffers(priv, target_msc, divisor, remainder);
     }
 
     if (psc->show_fps_interval) {
        show_fps(priv);
     }
 
-    /* Old servers don't send invalidate events */
-    if (!pdp->invalidateAvailable)
-       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable);
-
-    return ret;
+    return priv->last_swap_sbc + priv->swap_pending;
 }
 
 static __DRIbuffer *
@@ -885,6 +884,8 @@  dri2GetBuffers(__DRIdrawable * driDrawable,
 
    free(buffers);
 
+   dri2XcbSwapBuffersComplete(pdraw);
+
    return pdraw->buffers;
 }
 
@@ -910,6 +911,8 @@  dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
 
    free(buffers);
 
+   dri2XcbSwapBuffersComplete(pdraw);
+
    return pdraw->buffers;
 }