[Mesa-dev] [mesa 9/9] glx/dri2: Implement getBufferAge
Ian Romanick
idr at freedesktop.org
Tue Jan 20 12:35:05 PST 2015
On 01/19/2015 03:00 AM, Chris Wilson wrote:
> Within the DRI2GetBuffers return packet there is a 4-byte field that is
> currently unused by any driver, i.e. flags. With the co-operation of a
> suitably modified X server, we can pass the last SBC on which the buffer
> was defined (i.e. the last SwapBuffers for which it was used) and 0 if
> it is fresh (with a slight loss of precision). We can then compare the
> flags field of the DRIBuffer against the current swap buffers count and
> so compute the age of the back buffer (thus satisfying
> GLX_EXT_buffer_age).
>
> As we reuse a driver specific field within the DRI2GetBuffers packet, we
> first query whether the X/DDX are ready to supply the new value using a
> DRI2GetParam request.
>
> Another caveat is that we need to complete the SwapBuffers/GetBuffers
> roundtrip before reporting the back buffer age so that it tallies
> against the buffer used for rendering. As with all things X, there is a
> race between the query and the rendering where the buffer may be
> invalidated by the server. However, for the primary usecase (that of a
> compositing manager), the DRI2Drawable is only accessible to a single
> client mitigating the impact of the issue.
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
> configure.ac | 2 +-
> src/glx/dri2_glx.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 66 insertions(+), 1 deletion(-)
>
> diff --git a/configure.ac b/configure.ac
> index 870435c..ca1da86 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -65,7 +65,7 @@ LIBDRM_INTEL_REQUIRED=2.4.52
> LIBDRM_NVVIEUX_REQUIRED=2.4.33
> LIBDRM_NOUVEAU_REQUIRED="2.4.33 libdrm >= 2.4.41"
> LIBDRM_FREEDRENO_REQUIRED=2.4.57
> -DRI2PROTO_REQUIRED=2.6
> +DRI2PROTO_REQUIRED=2.9
> DRI3PROTO_REQUIRED=1.0
> PRESENTPROTO_REQUIRED=1.0
> LIBUDEV_REQUIRED=151
> diff --git a/src/glx/dri2_glx.c b/src/glx/dri2_glx.c
> index 0577804..b43f115 100644
> --- a/src/glx/dri2_glx.c
> +++ b/src/glx/dri2_glx.c
> @@ -917,6 +917,67 @@ dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
> }
>
> static int
> +dri2HasBufferAge(int screen, struct glx_display * priv)
> +{
> + const struct dri2_display *const pdp =
> + (struct dri2_display *)priv->dri2Display;
> + CARD64 value;
> +
> + if (pdp->driMajor <= 1 && pdp->driMinor < 4)
> + return 0;
> +
> + value = 0;
> + if (!DRI2GetParam(priv->dpy, RootWindow(priv->dpy, screen),
> + DRI2ParamXHasBufferAge, &value))
> + return 0;
> +
> + return value;
> +}
> +
> +static int
> +dri2GetBufferAge(__GLXDRIdrawable *pdraw)
> +{
> + struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
> + int i, age = 0;
> +
> + if (priv->swap_pending) {
> + unsigned int attachments[5];
I see other callers that have attachments of at least 8 (although it
appears that intel_query_dri2_buffers only needs 2). Could we at least
get an assertion or something that priv->bufferCount <=
ARRAY_SIZE(attachments)? A (hypothetical) driver doing stereo rendering
with separate, DDX managed, depth and stencil buffers would need 6. A
(again, hypothetical) driver with AUX buffers could need... more.
> + DRI2Buffer *buffers;
> +
> + for (i = 0; i < priv->bufferCount; i++)
> + attachments[i] = priv->buffers[i].attachment;
> +
> + buffers = DRI2GetBuffers(priv->base.psc->dpy, priv->base.xDrawable,
> + &priv->width, &priv->height,
> + attachments, i, &i);
Most drivers prefer DRI2GetBuffersWithFormat, and some drivers only use
DRI2GetBuffersWithFormat. Is mixing DRI2GetBuffersWithFormat and
DRI2GetBuffers going to cause problems or unexpected behavior changes?
> + if (buffers == NULL)
> + return 0;
> +
> + process_buffers(priv, buffers, i);
> + free(buffers);
> +
> + dri2XcbSwapBuffersComplete(priv);
> + }
> +
> + if (!priv->have_back)
> + return 0;
> +
> + for (i = 0; i < priv->bufferCount; i++) {
> + if (priv->buffers[i].attachment != __DRI_BUFFER_BACK_LEFT)
> + continue;
> +
> + if (priv->buffers[i].flags == 0)
> + continue;
> +
> + age = priv->last_swap_sbc - priv->buffers[i].flags + 1;
> + if (age < 0)
> + age = 0;
I was going to comment that this looked like it calculated age wrong
when the buffers had different ages. Then I realized that age should
only be calculated once. I think this would be more obvious if the body
of the loop were:
if (priv->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT &&
priv->buffers[i].flags != 0) {
age = priv->last_swap_sbc - priv->buffers[i].flags + 1;
if (age < 0)
age = 0;
break;
}
I also just noticed that your patches are mixing tabs and spaces (use
spaces only) and are using a mix of 3-space and 8-space (maybe?) indents
(use 3 spaces only).
> + }
> +
> + return age;
> +}
> +
> +static int
> dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
> {
> xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
> @@ -1290,6 +1351,10 @@ dri2CreateScreen(int screen, struct glx_display * priv)
> psp->setSwapInterval = NULL;
> psp->getSwapInterval = NULL;
> psp->getBufferAge = NULL;
Blank line here.
> + if (dri2HasBufferAge(screen, priv)) {
> + psp->getBufferAge = dri2GetBufferAge;
> + __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age");
> + }
>
> if (pdp->driMinor >= 2) {
> psp->getDrawableMSC = dri2DrawableGetMSC;
>
More information about the mesa-dev
mailing list