[Mesa-dev] [PATCH 5/6] dri3: Add DRI3 support to GLX, DRI common and Intel driver

Kristian Høgsberg hoegsberg at gmail.com
Fri Nov 1 22:31:54 PDT 2013


I sent a reply to the sourceforge addresses in the original emails,
but I didn't see it show up in the archives.  Trying again with the
freedesktop addresses.

On Thu, Oct 31, 2013 at 04:13:15PM -0700, Keith Packard wrote:
> This hooks DRI3 support into the GLX layer, the DRI common layer and the Intel
> driver.
> 
> Signed-off-by: Keith Packard <keithp at keithp.com>
> ---
>  configure.ac                                  |   10 +-
>  include/GL/internal/dri_interface.h           |  158 +++
>  src/glx/Makefile.am                           |    2 +
>  src/glx/dri3_common.c                         |  146 +++
>  src/glx/dri3_glx.c                            | 1539 +++++++++++++++++++++++++
>  src/glx/dri3_priv.h                           |  128 ++
>  src/glx/glxclient.h                           |    2 +
>  src/glx/glxext.c                              |    6 +-
>  src/mesa/drivers/dri/common/dri_util.c        |  163 ++-
>  src/mesa/drivers/dri/common/dri_util.h        |   23 +
>  src/mesa/drivers/dri/i915/intel_context.c     |  109 +-
>  src/mesa/drivers/dri/i915/intel_mipmap_tree.c |   33 +
>  src/mesa/drivers/dri/i915/intel_mipmap_tree.h |    8 +
>  src/mesa/drivers/dri/i965/brw_context.c       |  110 +-
>  src/mesa/drivers/dri/i965/intel_mipmap_tree.c |   61 +
>  src/mesa/drivers/dri/i965/intel_mipmap_tree.h |    8 +
>  src/mesa/drivers/dri/i965/intel_screen.c      |  107 +-
>  17 files changed, 2594 insertions(+), 19 deletions(-)
>  create mode 100644 src/glx/dri3_common.c
>  create mode 100644 src/glx/dri3_glx.c
>  create mode 100644 src/glx/dri3_priv.h
> 
> diff --git a/configure.ac b/configure.ac
> index f94c9b9..b6158d9 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -38,6 +38,8 @@ LIBDRM_NVVIEUX_REQUIRED=2.4.33
>  LIBDRM_NOUVEAU_REQUIRED="2.4.33 libdrm >= 2.4.41"
>  LIBDRM_FREEDRENO_REQUIRED=2.4.39
>  DRI2PROTO_REQUIRED=2.6
> +DRI3PROTO_REQUIRED=1.0
> +LIBUDEV_REQUIRED=151
>  GLPROTO_REQUIRED=1.4.14
>  LIBDRM_XORG_REQUIRED=2.4.24
>  LIBKMS_XORG_REQUIRED=1.0.0
> @@ -820,10 +822,12 @@ xyesno)
>          fi
>          PKG_CHECK_MODULES([DRI2PROTO], [dri2proto >= $DRI2PROTO_REQUIRED])
>          GL_PC_REQ_PRIV="$GL_PC_REQ_PRIV libdrm >= $LIBDRM_REQUIRED"
> +        PKG_CHECK_MODULES([DRI3PROTO], [dri3proto >= $DRI3PROTO_REQUIRED])
> +        PKG_CHECK_MODULES([LIBUDEV], [libudev >= $LIBUDEV_REQUIRED])
>      fi
>  
>      # find the DRI deps for libGL
> -    dri_modules="x11 xext xdamage xfixes x11-xcb xcb-glx >= 1.8.1 xcb-dri2 >= 1.8"
> +    dri_modules="x11 xext xdamage xfixes x11-xcb xcb-glx >= 1.8.1 xcb-dri2 >= 1.8 xcb-dri3 xcb-sync xshmfence"
>  
>      # add xf86vidmode if available
>      PKG_CHECK_MODULES([XF86VIDMODE], [xxf86vm], HAVE_XF86VIDMODE=yes, HAVE_XF86VIDMODE=no)
> @@ -833,8 +837,8 @@ xyesno)
>  
>      PKG_CHECK_MODULES([DRIGL], [$dri_modules])
>      GL_PC_REQ_PRIV="$GL_PC_REQ_PRIV $dri_modules"
> -    X11_INCLUDES="$X11_INCLUDES $DRIGL_CFLAGS"
> -    GL_LIB_DEPS="$DRIGL_LIBS"
> +    X11_INCLUDES="$X11_INCLUDES $DRIGL_CFLAGS $LIBUDEV_CFLAGS"
> +    GL_LIB_DEPS="$DRIGL_LIBS $LIBUDEV_LIBS"
>  
>      # need DRM libs, $PTHREAD_LIBS, etc.
>      GL_LIB_DEPS="$GL_LIB_DEPS $LIBDRM_LIBS -lm $PTHREAD_LIBS $DLOPEN_LIBS"
> diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h
> index 48993b9..b06ad8d 100644
> --- a/include/GL/internal/dri_interface.h
> +++ b/include/GL/internal/dri_interface.h
> @@ -86,6 +86,11 @@ typedef struct __DRIdri2LoaderExtensionRec	__DRIdri2LoaderExtension;
>  typedef struct __DRI2flushExtensionRec	__DRI2flushExtension;
>  typedef struct __DRI2throttleExtensionRec	__DRI2throttleExtension;
>  
> +
> +typedef struct __DRIdri3BufferRec               __DRIdri3Buffer;
> +typedef struct __DRIdri3ExtensionRec            __DRIdri3Extension;
> +typedef struct __DRIdri3LoaderExtensionRec      __DRIdri3LoaderExtension;
> +
>  /*@}*/
>  
>  
> @@ -966,6 +971,159 @@ struct __DRIdri2ExtensionRec {
>  
>  
>  /**
> + * DRI3 Loader extension.
> + */
> +
> +#define __DRI3_DRIVER_EXTENSIONS "__dri3DriverExtensions"
> +
> +enum __DRI3bufferType {
> +   __DRI3_BUFFER_BACK = 0,
> +   __DRI3_BUFFER_FRONT = 1
> +};
> +
> +struct __DRIdri3BufferRec {
> +   unsigned int size;
> +   unsigned int pitch;
> +   unsigned int cpp;
> +   unsigned int flags;
> +   unsigned int width, height;
> +   enum __DRI3bufferType buffer_type;
> +   uint32_t pixmap;
> +   uint32_t sync_fence;
> +   int32_t *shm_fence;
> +   void *driverPrivate;
> +};

My main concern with this patch is that I'd like to use __DRIimage for
the color buffers instead of this new __DRIdri3Buffer.  __DRIimage is
an opaque structure which we introduced for EGLImage support.  It
essentially wraps an intel_region, so it's similar to __DRI3buffer,
except it's all opaque.  __DRIimage is essentially *the* color buffer
abstraction in the DRI driver interface now and we're already using it
for color buffers in GBM and Wayland.

The intel version of __DRIimage is defined in intel_regions.h.  It's
more complicated than __DRIdri3Buffer since it supports planar
buffers, but at the end of the day it's the same idea.

The pixmap, sync_fence and shm_fence fields above should move to a new
dri3_buffer struct in dri3_glx.c:

   struct dri3_buffer {
      __DRIimage *image;
      uint32_t pixmap;
      uint32_t sync_fence;
      int32_t *shm_fence;
   };

They are only used by the glx integration and the DRI driver doesn't
need to see them.  We could also include widht and height height here
for convenience, but there is a getter that will return the dimensions
of a __DRIimage (queryImage).

> +#define __DRI_DRI3_LOADER "DRI_DRI3Loader"
> +#define __DRI_DRI3_LOADER_VERSION 1
> +
> +struct __DRIdri3LoaderExtensionRec {
> +    __DRIextension base;
> +
> +   int (*getBuffers)(__DRIdrawable *driDrawable,
> +                     int *width, int *height,
> +                     unsigned int format,
> +                     void *loaderPrivate,
> +                     int need_front,
> +                     int need_back,
> +                     __DRIdri3Buffer **front,
> +                     __DRIdri3Buffer **back);

This function would then not have width and height, since they're part
of __DRIimage and instead of the two __DRIdri3Buffer ** args, it would
have two __DRIimage ** args.

> +    /**
> +     * Flush pending front-buffer rendering
> +     *
> +     * Any rendering that has been performed to the
> +     * \c __DRI3_BUFFER_FAKE_FRONT_LEFT will be flushed to the
> +     * \c __DRI3_BUFFER_FRONT_LEFT.
> +     *
> +     * \param driDrawable    Drawable whose front-buffer is to be flushed
> +     * \param loaderPrivate  Loader's private data that was previously passed
> +     *                       into __DRIdri2ExtensionRec::createNewDrawable
> +     */
> +    void (*flushFrontBuffer)(__DRIdrawable *driDrawable, void *loaderPrivate);
> +};
> +
> +/**
> + * DRI3 extension.
> + */
> +
> +struct gl_context;
> +struct dd_function_table;

(these two seem out of place)

> +typedef __DRIscreen *
> +(*__DRIcreateNewScreen2)(int screen, int fd,
> +                         const __DRIextension **extensions,
> +                         const __DRIextension **driver_extensions,
> +                         const __DRIconfig ***driver_configs,
> +                         void *loaderPrivate);
> +
> +typedef __DRIdrawable *
> +(*__DRIcreateNewDrawable)(__DRIscreen *screen,
> +                          const __DRIconfig *config,
> +                          void *loaderPrivate);
> +
> +typedef __DRIcontext *
> +(*__DRIcreateNewContext)(__DRIscreen *screen,
> +                         const __DRIconfig *config,
> +                         __DRIcontext *shared,
> +                         void *loaderPrivate);
> +
> +typedef __DRIcontext *
> +(*__DRIcreateContextAttribs)(__DRIscreen *screen,
> +                             int api,
> +                             const __DRIconfig *config,
> +                             __DRIcontext *shared,
> +                             unsigned num_attribs,
> +                             const uint32_t *attribs,
> +                             unsigned *error,
> +                             void *loaderPrivate);
> +
> +typedef unsigned int
> +(*__DRIgetAPIMask)(__DRIscreen *screen);
> +
> +typedef __DRIdri3Buffer *
> +(*__DRIdri3AllocateBuffer)(__DRIscreen *screen,
> +                           unsigned int bpp,
> +                           int width,
> +                           int height);

Instead of this, we can call

  __DRIimage->createImage(screen, width, height, format,
                          use, loader_priv);

where format is one of the __DRI_IMAGE_FORMAT_* codes and use is one
of the __DRI_IMAGE_USE_* flags.

> +typedef void
> +(*__DRIdri3ReleaseBuffer)(__DRIscreen *screen,
> +                          __DRIdri3Buffer *buffer);

to destroy a __DRIimage, call

  __DRIimage->destroyImage(image);


> +typedef int
> +(*__DRIdri3BufferToFd)(__DRIscreen *screen,
> +                       __DRIdri3Buffer *buffer);

to get an fd from a __DRIimage call

  __DRIimage->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd)

> +typedef __DRIdri3Buffer *
> +(*__DRIdri3FdToBuffer)(__DRIscreen *screen,
> +                       int fd, unsigned int bpp,
> +                       int width, int height, int stride,
> +                       unsigned int size);

use __DRIimage->createImageFromFDs for this.  This entry point can
take multiple fds for the case of a planar image that's laid out over
multiple BOs.

> +typedef uint32_t *
> +(*__DRIdri3Stamp)(__DRIdrawable *drawable);

This looks OK, as long as it's not tied into the xcb special_event
semantics.  From the way it's used, it looks like a loader can just
increment this uint32_t when it needs to invalidate the buffer.  Still
seems like an odd API - a invalidate function would be simpler, but
I'm guessing it's limited by what you can do if you receive the
special event in a different thread.

With those changes, we can reuse __DRIimage for DRI3 which makes a lot
of sense.  The GBM and Wayland backends already use __DRIimage for
color buffers, but convert them to __DRI2buffer to be able to pass
them into the DRI driver.  Being able to pass a __DRIimage into the
driver in getBuffers will simplify those backends, and it should be
fairly simple to port them to the dri3 driver interface.

> +#define __DRI_DRI3              "DRI_DRI3"
> +#define __DRI_DRI3_VERSION      1
> +
> +struct __DRIdri3ExtensionRec {
> +   __DRIextension               base;
> +
> +   /* Common DRI functions, shared with DRI2 */
> +   __DRIcreateNewScreen2        createNewScreen2;
> +   __DRIcreateNewDrawable       createNewDrawable;
> +   __DRIcreateNewContext        createNewContext;
> +   __DRIcreateContextAttribs    createContextAttribs;
> +   __DRIgetAPIMask              getAPIMask;
> +
> +   /* DRI3-specific functions*/
> +
> +   /* Allocate color buffer for front/back of windows and pixmaps
> +    */
> +   __DRIdri3AllocateBuffer      allocateBuffer;
> +
> +   /* Release color buffer
> +    */
> +   __DRIdri3ReleaseBuffer       releaseBuffer;
> +
> +   /* Given a buffer, wrap it in a DMA-BUF file descriptor
> +    */
> +   __DRIdri3BufferToFd          bufferToFd;
> +
> +   /* Given a DMA-BUF file descriptor, construct a suitable
> +    * color buffer
> +    */
> +   __DRIdri3FdToBuffer          fdToBuffer;
> +
> +   /* Ask the driver for a pointer to an integer which
> +    * can be incremented when the drawable needs to be
> +    * revalidated
> +    */
> +   __DRIdri3Stamp               stamp;
> +};
> +
> +/**
>   * This extension provides functionality to enable various EGLImage
>   * extensions.
>   */
> diff --git a/src/glx/Makefile.am b/src/glx/Makefile.am
> index f01709b..854025d 100644
> --- a/src/glx/Makefile.am
> +++ b/src/glx/Makefile.am
> @@ -92,6 +92,8 @@ libglx_la_SOURCES = \
>  	  glxhash.c \
>  	  dri2_glx.c \
>  	  dri2.c \
> +          dri3_glx.c \
> +          dri3_common.c \
>  	  applegl_glx.c
>  
>  GL_LIBS = \
> diff --git a/src/glx/dri3_common.c b/src/glx/dri3_common.c
> new file mode 100644
> index 0000000..c758f96
> --- /dev/null
> +++ b/src/glx/dri3_common.c
> @@ -0,0 +1,146 @@
> +/*
> + * Copyright © 2013 Keith Packard
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and its
> + * documentation for any purpose is hereby granted without fee, provided that
> + * the above copyright notice appear in all copies and that both that copyright
> + * notice and this permission notice appear in supporting documentation, and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no representations
> + * about the suitability of this software for any purpose.  It is provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +/*
> + * This code is derived from src/egl/drivers/dri2/common.c which
> + * carries the following copyright:
> + * 
> + * Copyright © 2011 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Kristian Høgsberg <krh at bitplanet.net>
> + *    Benjamin Franzke <benjaminfranzke at googlemail.com>
> + */
> +
> +#include <stdio.h>
> +#include <string.h>
> +
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include <GL/gl.h>
> +#include "glapi.h"
> +#include "glxclient.h"
> +#include "xf86dri.h"
> +#include <dlfcn.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/mman.h>
> +#include <sys/time.h>
> +#include "xf86drm.h"
> +#include "dri_common.h"
> +#include "dri3_priv.h"
> +
> +#define DRIVER_MAP_DRI3_ONLY
> +#include "pci_ids/pci_id_driver_map.h"
> +
> +#include <libudev.h>
> +
> +static struct udev_device *
> +dri3_udev_device_new_from_fd(struct udev *udev, int fd)
> +{
> +   struct udev_device *device;
> +   struct stat buf;
> +
> +   if (fstat(fd, &buf) < 0) {
> +      ErrorMessageF("DRI3: failed to stat fd %d", fd);
> +      return NULL;
> +   }
> +
> +   device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev);
> +   if (device == NULL) {
> +      ErrorMessageF("DRI3: could not create udev device for fd %d", fd);
> +      return NULL;
> +   }
> +
> +   return device;
> +}
> +
> +char *
> +dri3_get_driver_for_fd(int fd)
> +{
> +   struct udev *udev;
> +   struct udev_device *device, *parent;
> +   const char *pci_id;
> +   char *driver = NULL;
> +   int vendor_id, chip_id, i, j;
> +
> +   udev = udev_new();
> +   device = dri3_udev_device_new_from_fd(udev, fd);
> +   if (device == NULL)
> +      return NULL;
> +
> +   parent = udev_device_get_parent(device);
> +   if (parent == NULL) {
> +      ErrorMessageF("DRI3: could not get parent device");
> +      goto out;
> +   }
> +
> +   pci_id = udev_device_get_property_value(parent, "PCI_ID");
> +   if (pci_id == NULL ||
> +       sscanf(pci_id, "%x:%x", &vendor_id, &chip_id) != 2) {
> +      ErrorMessageF("DRI3: malformed or no PCI ID");
> +      goto out;
> +   }
> +
> +   for (i = 0; driver_map[i].driver; i++) {
> +      if (vendor_id != driver_map[i].vendor_id)
> +         continue;
> +      if (driver_map[i].num_chips_ids == -1) {
> +         driver = strdup(driver_map[i].driver);
> +         goto out;
> +      }
> +
> +      for (j = 0; j < driver_map[i].num_chips_ids; j++)
> +         if (driver_map[i].chip_ids[j] == chip_id) {
> +            driver = strdup(driver_map[i].driver);
> +            goto out;
> +         }
> +   }
> +
> +out:
> +   udev_device_unref(device);
> +   udev_unref(udev);
> +
> +   return driver;
> +}
> diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
> new file mode 100644
> index 0000000..4d275f2
> --- /dev/null
> +++ b/src/glx/dri3_glx.c
> @@ -0,0 +1,1539 @@
> +/*
> + * Copyright © 2013 Keith Packard
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and its
> + * documentation for any purpose is hereby granted without fee, provided that
> + * the above copyright notice appear in all copies and that both that copyright
> + * notice and this permission notice appear in supporting documentation, and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no representations
> + * about the suitability of this software for any purpose.  It is provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +/*
> + * Portions of this code were adapted from dri2_glx.c which carries the
> + * following copyright:
> + *
> + * Copyright © 2008 Red Hat, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Soft-
> + * ware"), to deal in the Software without restriction, including without
> + * limitation the rights to use, copy, modify, merge, publish, distribute,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, provided that the above copyright
> + * notice(s) and this permission notice appear in all copies of the Soft-
> + * ware and that both the above copyright notice(s) and this permission
> + * notice appear in supporting documentation.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
> + * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
> + * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
> + * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
> + * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
> + * MANCE OF THIS SOFTWARE.
> + *
> + * Except as contained in this notice, the name of a copyright holder shall
> + * not be used in advertising or otherwise to promote the sale, use or
> + * other dealings in this Software without prior written authorization of
> + * the copyright holder.
> + *
> + * Authors:
> + *   Kristian Høgsberg (krh at redhat.com)
> + */
> +
> +#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
> +
> +#include <X11/Xlib.h>
> +#include <X11/extensions/Xfixes.h>
> +#include <X11/Xlib-xcb.h>
> +#include <X11/xshmfence.h>
> +#include <xcb/xcb.h>
> +#include <xcb/dri3.h>
> +#include <xcb/present.h>
> +#include <GL/gl.h>
> +#include "glapi.h"
> +#include "glxclient.h"
> +#include "xf86dri.h"
> +#include <dlfcn.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/mman.h>
> +#include <sys/time.h>
> +#include "xf86drm.h"
> +#include "dri_common.h"
> +#include "dri3_priv.h"
> +
> +static const struct glx_context_vtable dri3_context_vtable;
> +
> +#define HAS_SBC 0
> +
> +#if HAS_SBC
> +
> +/* For XCB's handling of ust/msc/sbc counters, we have to hand it the high and
> + * low halves separately.  This helps you split them.
> + */
> +static void
> +split_counter(uint64_t counter, uint32_t *hi, uint32_t *lo)
> +{
> +   *hi = (counter >> 32);
> +   *lo = counter & 0xffffffff;
> +}
> +
> +static uint64_t
> +merge_counter(uint32_t hi, uint32_t lo)
> +{
> +   return ((uint64_t)hi << 32) | lo;
> +}
> +#endif /* HAS_SBC */
> +
> +static inline void
> +dri3_fence_reset(xcb_connection_t *c, __DRIdri3Buffer *buffer) {
> +   xshmfence_reset(buffer->shm_fence);
> +}
> +
> +static inline void
> +dri3_fence_trigger(xcb_connection_t *c, __DRIdri3Buffer *buffer) {
> +   xcb_sync_trigger_fence(c, buffer->sync_fence);
> +}
> +
> +static inline void
> +dri3_fence_await(xcb_connection_t *c, __DRIdri3Buffer *buffer) {
> +   xcb_flush(c);
> +   xshmfence_await(buffer->shm_fence);
> +}
> +
> +static void
> +dri3_destroy_context(struct glx_context *context)
> +{
> +   struct dri3_context *pcp = (struct dri3_context *) context;
> +   struct dri3_screen *psc = (struct dri3_screen *) context->psc;
> +
> +   driReleaseDrawables(&pcp->base);
> +
> +   free((char *) context->extensions);
> +
> +   (*psc->core->destroyContext) (pcp->driContext);
> +
> +   free(pcp);
> +}
> +
> +static Bool
> +dri3_bind_context(struct glx_context *context, struct glx_context *old,
> +		  GLXDrawable draw, GLXDrawable read)
> +{
> +   struct dri3_context *pcp = (struct dri3_context *) context;
> +   struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc;
> +   struct dri3_drawable *pdraw, *pread;
> +
> +   pdraw = (struct dri3_drawable *) driFetchDrawable(context, draw);
> +   pread = (struct dri3_drawable *) driFetchDrawable(context, read);
> +
> +   driReleaseDrawables(&pcp->base);
> +
> +   if (pdraw == NULL || pread == NULL)
> +      return GLXBadDrawable;
> +
> +   if (!(*psc->core->bindContext) (pcp->driContext,
> +				   pdraw->driDrawable, pread->driDrawable))
> +      return GLXBadContext;
> +
> +   return Success;
> +}
> +
> +static void
> +dri3_unbind_context(struct glx_context *context, struct glx_context *new)
> +{
> +   struct dri3_context *pcp = (struct dri3_context *) context;
> +   struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc;
> +
> +   (*psc->core->unbindContext) (pcp->driContext);
> +}
> +
> +static struct glx_context *
> +dri3_create_context(struct glx_screen *base,
> +		    struct glx_config *config_base,
> +		    struct glx_context *shareList, int renderType)
> +{
> +   struct dri3_context *pcp, *pcp_shared;
> +   struct dri3_screen *psc = (struct dri3_screen *) base;
> +   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
> +   __DRIcontext *shared = NULL;
> +
> +   if (shareList) {
> +      /* If the shareList context is not a DRI3 context, we cannot possibly
> +       * create a DRI3 context that shares it.
> +       */
> +      if (shareList->vtable->destroy != dri3_destroy_context) {
> +	 return NULL;
> +      }
> +
> +      pcp_shared = (struct dri3_context *) shareList;
> +      shared = pcp_shared->driContext;
> +   }
> +
> +   pcp = calloc(1, sizeof *pcp);
> +   if (pcp == NULL)
> +      return NULL;
> +
> +   if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
> +      free(pcp);
> +      return NULL;
> +   }
> +
> +   pcp->driContext =
> +      (*psc->dri3->createNewContext) (psc->driScreen,
> +                                      config->driConfig, shared, pcp);
> +
> +   if (pcp->driContext == NULL) {
> +      free(pcp);
> +      return NULL;
> +   }
> +
> +   pcp->base.vtable = &dri3_context_vtable;
> +
> +   return &pcp->base;
> +}
> +
> +static struct glx_context *
> +dri3_create_context_attribs(struct glx_screen *base,
> +			    struct glx_config *config_base,
> +			    struct glx_context *shareList,
> +			    unsigned num_attribs,
> +			    const uint32_t *attribs,
> +			    unsigned *error)
> +{
> +   struct dri3_context *pcp = NULL;
> +   struct dri3_context *pcp_shared = NULL;
> +   struct dri3_screen *psc = (struct dri3_screen *) base;
> +   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
> +   __DRIcontext *shared = NULL;
> +
> +   uint32_t minor_ver = 1;
> +   uint32_t major_ver = 2;
> +   uint32_t flags = 0;
> +   unsigned api;
> +   int reset = __DRI_CTX_RESET_NO_NOTIFICATION;
> +   uint32_t ctx_attribs[2 * 5];
> +   unsigned num_ctx_attribs = 0;
> +   uint32_t render_type;
> +
> +   /* Remap the GLX tokens to DRI2 tokens.
> +    */
> +   if (!dri2_convert_glx_attribs(num_attribs, attribs,
> +				 &major_ver, &minor_ver,
> +                                 &render_type, &flags, &api,
> +                                 &reset, error))
> +      goto error_exit;
> +
> +   /* Check the renderType value */
> +   if (!validate_renderType_against_config(config_base, render_type))
> +       goto error_exit;
> +
> +   if (shareList) {
> +      pcp_shared = (struct dri3_context *) shareList;
> +      shared = pcp_shared->driContext;
> +   }
> +
> +   pcp = calloc(1, sizeof *pcp);
> +   if (pcp == NULL) {
> +      *error = __DRI_CTX_ERROR_NO_MEMORY;
> +      goto error_exit;
> +   }
> +
> +   if (!glx_context_init(&pcp->base, &psc->base, &config->base))
> +      goto error_exit;
> +
> +   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
> +   ctx_attribs[num_ctx_attribs++] = major_ver;
> +   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
> +   ctx_attribs[num_ctx_attribs++] = minor_ver;
> +
> +   /* Only send a value when the non-default value is requested.  By doing
> +    * this we don't have to check the driver's DRI3 version before sending the
> +    * default value.
> +    */
> +   if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
> +      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
> +      ctx_attribs[num_ctx_attribs++] = reset;
> +   }
> +
> +   if (flags != 0) {
> +      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
> +
> +      /* The current __DRI_CTX_FLAG_* values are identical to the
> +       * GLX_CONTEXT_*_BIT values.
> +       */
> +      ctx_attribs[num_ctx_attribs++] = flags;
> +   }
> +
> +   pcp->driContext =
> +      (*psc->dri3->createContextAttribs) (psc->driScreen,
> +					  api,
> +					  config->driConfig,
> +					  shared,
> +					  num_ctx_attribs / 2,
> +					  ctx_attribs,
> +					  error,
> +					  pcp);
> +
> +   if (pcp->driContext == NULL)
> +      goto error_exit;
> +
> +   pcp->base.vtable = &dri3_context_vtable;
> +
> +   return &pcp->base;
> +
> +error_exit:
> +   free(pcp);
> +
> +   return NULL;
> +}
> +
> +static void
> +dri3_destroy_drawable(__GLXDRIdrawable *base)
> +{
> +   struct dri3_screen *psc = (struct dri3_screen *) base->psc;
> +   struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
> +
> +   (*psc->core->destroyDrawable) (pdraw->driDrawable);
> +
> +   free(pdraw);
> +}
> +
> +static __GLXDRIdrawable *
> +dri3_create_drawable(struct glx_screen *base, XID xDrawable,
> +                     GLXDrawable drawable, struct glx_config *config_base)
> +{
> +   struct dri3_drawable *pdraw;
> +   struct dri3_screen *psc = (struct dri3_screen *) base;
> +   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
> +   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
> +
> +   pdraw = calloc(1, sizeof(*pdraw));
> +   if (!pdraw)
> +      return NULL;
> +
> +   pdraw->base.destroyDrawable = dri3_destroy_drawable;
> +   pdraw->base.xDrawable = xDrawable;
> +   pdraw->base.drawable = drawable;
> +   pdraw->base.psc = &psc->base;
> +//   pdraw->bufferCount = 0;
> +   pdraw->swap_interval = 1; /* default may be overridden below */
> +   pdraw->have_back = 0;
> +   pdraw->have_fake_front = 0;
> +
> +   if (psc->config)
> +      psc->config->configQueryi(psc->driScreen,
> +				"vblank_mode", &vblank_mode);
> +
> +   switch (vblank_mode) {
> +   case DRI_CONF_VBLANK_NEVER:
> +   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
> +      pdraw->swap_interval = 0;
> +      break;
> +   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
> +   case DRI_CONF_VBLANK_ALWAYS_SYNC:
> +   default:
> +      pdraw->swap_interval = 1;
> +      break;
> +   }
> +
> +   (void) __glXInitialize(psc->base.dpy);
> +
> +   /* Create a new drawable */
> +   pdraw->driDrawable =
> +      (*psc->dri3->createNewDrawable) (psc->driScreen,
> +                                       config->driConfig, pdraw);
> +
> +   if (!pdraw->driDrawable) {
> +      free(pdraw);
> +      return NULL;
> +   }
> +
> +   /*
> +    * Make sure server has the same swap interval we do for the new
> +    * drawable.
> +    */
> +   if (psc->vtable.setSwapInterval)
> +      psc->vtable.setSwapInterval(&pdraw->base, pdraw->swap_interval);
> +
> +   return &pdraw->base;
> +}
> +
> +#if HAS_SBC
> +static int
> +dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
> +                      int64_t *ust, int64_t *msc, int64_t *sbc)
> +{
> +   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
> +   xcb_dri2_get_msc_cookie_t get_msc_cookie;
> +   xcb_dri2_get_msc_reply_t *get_msc_reply;
> +
> +   get_msc_cookie = xcb_dri2_get_msc_unchecked(c, pdraw->xDrawable);
> +   get_msc_reply = xcb_dri2_get_msc_reply(c, get_msc_cookie, NULL);
> +
> +   if (!get_msc_reply)
> +      return 0;
> +
> +   *ust = merge_counter(get_msc_reply->ust_hi, get_msc_reply->ust_lo);
> +   *msc = merge_counter(get_msc_reply->msc_hi, get_msc_reply->msc_lo);
> +   *sbc = merge_counter(get_msc_reply->sbc_hi, get_msc_reply->sbc_lo);
> +   free(get_msc_reply);
> +
> +   return 1;
> +}
> +
> +static int
> +dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
> +                  int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
> +{
> +   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
> +   xcb_dri2_wait_msc_cookie_t wait_msc_cookie;
> +   xcb_dri2_wait_msc_reply_t *wait_msc_reply;
> +   uint32_t target_msc_hi, target_msc_lo;
> +   uint32_t divisor_hi, divisor_lo;
> +   uint32_t remainder_hi, remainder_lo;
> +
> +   split_counter(target_msc, &target_msc_hi, &target_msc_lo);
> +   split_counter(divisor, &divisor_hi, &divisor_lo);
> +   split_counter(remainder, &remainder_hi, &remainder_lo);
> +
> +   wait_msc_cookie = xcb_dri2_wait_msc_unchecked(c, pdraw->xDrawable,
> +                                                 target_msc_hi, target_msc_lo,
> +                                                 divisor_hi, divisor_lo,
> +                                                 remainder_hi, remainder_lo);
> +   wait_msc_reply = xcb_dri2_wait_msc_reply(c, wait_msc_cookie, NULL);
> +
> +   if (!wait_msc_reply)
> +      return 0;
> +
> +   *ust = merge_counter(wait_msc_reply->ust_hi, wait_msc_reply->ust_lo);
> +   *msc = merge_counter(wait_msc_reply->msc_hi, wait_msc_reply->msc_lo);
> +   *sbc = merge_counter(wait_msc_reply->sbc_hi, wait_msc_reply->sbc_lo);
> +   free(wait_msc_reply);
> +
> +   return 1;
> +}
> +
> +static int
> +dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
> +                  int64_t *msc, int64_t *sbc)
> +{
> +   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
> +   xcb_dri2_wait_sbc_cookie_t wait_sbc_cookie;
> +   xcb_dri2_wait_sbc_reply_t *wait_sbc_reply;
> +   uint32_t target_sbc_hi, target_sbc_lo;
> +
> +   split_counter(target_sbc, &target_sbc_hi, &target_sbc_lo);
> +
> +   wait_sbc_cookie = xcb_dri2_wait_sbc_unchecked(c, pdraw->xDrawable,
> +                                                 target_sbc_hi, target_sbc_lo);
> +   wait_sbc_reply = xcb_dri2_wait_sbc_reply(c, wait_sbc_cookie, NULL);
> +
> +   if (!wait_sbc_reply)
> +      return 0;
> +
> +   *ust = merge_counter(wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo);
> +   *msc = merge_counter(wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo);
> +   *sbc = merge_counter(wait_sbc_reply->sbc_hi, wait_sbc_reply->sbc_lo);
> +   free(wait_sbc_reply);
> +
> +   return 1;
> +}
> +#endif /* HAS_SBC */
> +
> +static __DRIcontext *
> +dri3_get_current_context(void)
> +{
> +   struct glx_context *gc = __glXGetCurrentContext();
> +   struct dri3_context *dri3Ctx = (struct dri3_context *)gc;
> +
> +   return dri3Ctx ? dri3Ctx->driContext : NULL;
> +}
> +
> +/**
> + * dri3Throttle - Request driver throttling
> + *
> + * This function uses the DRI2 throttle extension to give the
> + * driver the opportunity to throttle on flush front, copysubbuffer
> + * and swapbuffers.
> + */
> +static void
> +dri3_throttle(struct dri3_screen *psc,
> +              struct dri3_drawable *draw,
> +              enum __DRI2throttleReason reason)
> +{
> +   if (psc->throttle) {
> +      __DRIcontext *ctx = dri3_get_current_context();
> +
> +      psc->throttle->throttle(ctx, draw->driDrawable, reason);
> +   }
> +}
> +
> +/**
> + * Asks the driver to flush any queued work necessary for serializing with the
> + * X command stream, and optionally the slightly more strict requirement of
> + * glFlush() equivalence (which would require flushing even if nothing had
> + * been drawn to a window system framebuffer, for example).
> + */
> +static void
> +dri3_flush(struct dri3_screen *psc,
> +           __DRIcontext *ctx,
> +           struct dri3_drawable *draw,
> +           unsigned flags,
> +           enum __DRI2throttleReason throttle_reason)
> +{
> +   if (ctx && psc->f && psc->f->base.version >= 4) {
> +      psc->f->flush_with_flags(ctx, draw->driDrawable, flags, throttle_reason);
> +   } else {
> +      if (flags & __DRI2_FLUSH_CONTEXT)
> +         glFlush();
> +
> +      if (psc->f)
> +         psc->f->flush(draw->driDrawable);
> +
> +      dri3_throttle(psc, draw, throttle_reason);
> +   }
> +}
> +
> +static xcb_gcontext_t
> +dri3_drawable_gc(struct dri3_drawable *priv)
> +{
> +   if (!priv->gc) {
> +      uint32_t v;
> +      xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
> +
> +      v = 0;
> +      xcb_create_gc(c,
> +                    (priv->gc = xcb_generate_id(c)),
> +                    priv->base.xDrawable,
> +                    XCB_GC_GRAPHICS_EXPOSURES,
> +                    &v);
> +   }
> +   return priv->gc;
> +}
> +
> +static __DRIdri3Buffer *
> +dri3_back_buffer(struct dri3_drawable *priv)
> +{
> +   return priv->buffers[__DRI3_BUFFER_BACK];
> +}
> +
> +static __DRIdri3Buffer *
> +dri3_fake_front_buffer(struct dri3_drawable *priv)
> +{
> +   return priv->buffers[__DRI3_BUFFER_FRONT];
> +}
> +
> +static void
> +dri3_copy_area (xcb_connection_t *c  /**< */,
> +                xcb_drawable_t    src_drawable  /**< */,
> +                xcb_drawable_t    dst_drawable  /**< */,
> +                xcb_gcontext_t    gc  /**< */,
> +                int16_t           src_x  /**< */,
> +                int16_t           src_y  /**< */,
> +                int16_t           dst_x  /**< */,
> +                int16_t           dst_y  /**< */,
> +                uint16_t          width  /**< */,
> +                uint16_t          height  /**< */)
> +{
> +   xcb_void_cookie_t cookie;
> +
> +   cookie = xcb_copy_area_checked(c,
> +                                  src_drawable,
> +                                  dst_drawable,
> +                                  gc,
> +                                  src_x,
> +                                  src_y,
> +                                  dst_x,
> +                                  dst_y,
> +                                  width,
> +                                  height);
> +   xcb_discard_reply(c, cookie.sequence);
> +}
> +
> +static void
> +_dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y,
> +                       int width, int height,
> +                       enum __DRI2throttleReason reason, Bool flush)
> +{
> +   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
> +   struct dri3_screen *psc = (struct dri3_screen *) pdraw->psc;
> +   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
> +   __DRIcontext *ctx = dri3_get_current_context();
> +   __DRIdri3Buffer *back = dri3_back_buffer(priv);
> +
> +   unsigned flags;
> +
> +   /* Check we have the right attachments */
> +   if (!priv->have_back || priv->is_pixmap)
> +      return;
> +
> +   flags = __DRI2_FLUSH_DRAWABLE;
> +   if (flush)
> +      flags |= __DRI2_FLUSH_CONTEXT;
> +   dri3_flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
> +
> +   y = priv->height - y - height;
> +
> +   dri3_fence_reset(c, back);
> +   dri3_copy_area(c,
> +                  dri3_back_buffer(priv)->pixmap,
> +                  priv->base.xDrawable,
> +                  dri3_drawable_gc(priv),
> +                  x, y, x, y, width, height);
> +   dri3_fence_trigger(c, back);
> +   /* Refresh the fake front (if present) after we just damaged the real
> +    * front.
> +    */
> +   if (priv->have_fake_front) {
> +      dri3_fence_reset(c, dri3_fake_front_buffer(priv));
> +      dri3_copy_area(c,
> +                     dri3_back_buffer(priv)->pixmap,
> +                     dri3_fake_front_buffer(priv)->pixmap,
> +                     dri3_drawable_gc(priv),
> +                     x, y, x, y, width, height);
> +      dri3_fence_trigger(c, dri3_fake_front_buffer(priv));
> +      dri3_fence_await(c, dri3_fake_front_buffer(priv));
> +   }
> +   dri3_fence_await(c, back);
> +}
> +
> +static void
> +dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y,
> +		  int width, int height, Bool flush)
> +{
> +   _dri3_copy_sub_buffer(pdraw, x, y, width, height,
> +                         __DRI2_THROTTLE_COPYSUBBUFFER, flush);
> +}
> +
> +
> +static void
> +dri3_copy_drawable(struct dri3_drawable *priv, Drawable dest, Drawable src)
> +{
> +   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
> +   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
> +
> +   if (psc->f)
> +      (*psc->f->flush) (priv->driDrawable);
> +
> +   dri3_copy_area(c,
> +                  src, dest,
> +                  dri3_drawable_gc(priv),
> +                  0, 0, 0, 0, priv->width, priv->height);
> +}
> +
> +static void
> +dri3_wait_x(struct glx_context *gc)
> +{
> +   struct dri3_drawable *priv = (struct dri3_drawable *)
> +      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
> +
> +   if (priv == NULL || !priv->have_fake_front)
> +      return;
> +
> +   dri3_copy_drawable(priv, dri3_fake_front_buffer(priv)->pixmap, priv->base.xDrawable);
> +}
> +
> +static void
> +dri3_wait_gl(struct glx_context *gc)
> +{
> +   struct dri3_drawable *priv = (struct dri3_drawable *)
> +      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
> +
> +   if (priv == NULL || !priv->have_fake_front)
> +      return;
> +
> +   dri3_copy_drawable(priv, priv->base.xDrawable, dri3_fake_front_buffer(priv)->pixmap);
> +}
> +
> +/**
> + * Called by the driver when it needs to update the real front buffer with the
> + * contents of its fake front buffer.
> + */
> +static void
> +dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
> +{
> +   struct glx_context *gc;
> +   struct dri3_drawable *pdraw = loaderPrivate;
> +   struct dri3_screen *psc;
> +
> +   if (!pdraw)
> +      return;
> +
> +   if (!pdraw->base.psc)
> +      return;
> +
> +   psc = (struct dri3_screen *) pdraw->base.psc;
> +
> +   (void) __glXInitialize(psc->base.dpy);
> +
> +   gc = __glXGetCurrentContext();
> +
> +   dri3_throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT);
> +
> +   dri3_wait_gl(gc);
> +}
> +
> +static __DRIdri3Buffer *
> +dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw, unsigned int format, int width, int height, int depth)
> +{
> +   struct dri3_screen *psc = (struct dri3_screen *) glx_screen;
> +   Display *dpy = glx_screen->dpy;
> +   __DRIdri3Buffer *buffer;
> +   xcb_connection_t *c = XGetXCBConnection(dpy);
> +   xcb_pixmap_t pixmap;
> +   xcb_sync_fence_t sync_fence;
> +   int32_t *shm_fence;
> +   int buffer_fd, fence_fd;
> +
> +   fence_fd = xshmfence_alloc_shm();
> +   if (fence_fd < 0)
> +      return NULL;
> +   shm_fence = xshmfence_map_shm(fence_fd);
> +   if (shm_fence == NULL)
> +      goto no_shm_fence;
> +
> +   buffer = (*psc->dri3->allocateBuffer) (psc->driScreen,
> +                                          format,
> +                                          width,
> +                                          height);
> +   if (buffer == NULL)
> +      goto no_buffer;
> +
> +   buffer_fd = (*psc->dri3->bufferToFd)(psc->driScreen, buffer);
> +   if (buffer_fd < 0)
> +      goto no_buffer_fd;
> +
> +   xcb_dri3_pixmap_from_buffer(c,
> +                               (pixmap = xcb_generate_id(c)),
> +                               draw,
> +                               buffer->size,
> +                               width, height, buffer->pitch,
> +                               depth, buffer->cpp * 8,
> +                               buffer_fd);
> +
> +   xcb_dri3_fence_from_fd(c,
> +                          pixmap,
> +                          (sync_fence = xcb_generate_id(c)),
> +                          false,
> +                          fence_fd);
> +
> +   buffer->pixmap = pixmap;
> +   buffer->sync_fence = sync_fence;
> +   buffer->shm_fence = shm_fence;
> +   buffer->width = width;
> +   buffer->height = height;
> +   return buffer;
> +   
> +no_buffer_fd:
> +   (*psc->dri3->releaseBuffer)(psc->driScreen, buffer);
> +no_buffer:
> +   xshmfence_unmap_shm(shm_fence);
> +no_shm_fence:
> +   close(fence_fd);
> +   return NULL;
> +}
> +
> +static void
> +dri3_free_render_buffer(struct dri3_drawable *pdraw, __DRIdri3Buffer *buffer)
> +{
> +   struct dri3_screen   *psc = (struct dri3_screen *) pdraw->base.psc;
> +   xcb_connection_t     *c = XGetXCBConnection(pdraw->base.psc->dpy);
> +
> +   xcb_free_pixmap(c, buffer->pixmap);
> +   xcb_sync_destroy_fence(c, buffer->sync_fence);
> +   xshmfence_unmap_shm(buffer->shm_fence);
> +   (*psc->dri3->releaseBuffer)(psc->driScreen, buffer);
> +}
> +
> +static int
> +dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate)
> +{
> +   struct dri3_drawable *priv = loaderPrivate;
> +   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
> +
> +   /* First time through, go get the current drawable geometry
> +    */
> +   if (priv->width == 0 || priv->height == 0 || priv->depth == 0) {
> +      xcb_get_geometry_cookie_t                 geom_cookie;
> +      xcb_get_geometry_reply_t                  *geom_reply;
> +      struct dri3_screen                        *psc;
> +      xcb_void_cookie_t                         cookie;
> +      xcb_generic_error_t                       *error;
> +
> +      cookie = xcb_present_select_input_checked(c,
> +                                                (priv->eid = xcb_generate_id(c)),
> +                                                priv->base.xDrawable,
> +                                                XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY|
> +                                                XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
> +         
> +      if (!priv->present_extension) {
> +         priv->present_extension = xcb_get_extension_data(c, &xcb_present_id);
> +         if (!priv->present_extension)
> +            return false;
> +      }
> +
> +      psc = (struct dri3_screen *) priv->base.psc;
> +      priv->special_event = xcb_register_for_special_event(c,
> +                                                           priv->present_extension->major_opcode,
> +                                                           priv->eid,
> +                                                           psc->dri3->stamp(driDrawable));
> +
> +      geom_cookie = xcb_get_geometry(c, priv->base.xDrawable);
> +
> +      geom_reply = xcb_get_geometry_reply(c, geom_cookie, NULL);
> +
> +      if (!geom_reply)
> +         return false;
> +
> +      priv->width = geom_reply->width;
> +      priv->height = geom_reply->height;
> +      priv->depth = geom_reply->depth;
> +      priv->is_pixmap = false;
> +
> +      free(geom_reply);
> +
> +      error = xcb_request_check(c, cookie);
> +
> +      if (error) {
> +         if (error->error_code != BadWindow) {
> +            free(error);
> +            return false;
> +         }
> +         priv->is_pixmap = true;
> +         xcb_unregister_for_special_event(c, priv->special_event);
> +         priv->special_event = NULL;
> +      }
> +   }
> +
> +   /* Check to see if any configuration changes have occurred
> +    * since we were last invoked
> +    */
> +   if (priv->special_event) {
> +      xcb_generic_event_t    *ev;
> +
> +      while ((ev = xcb_check_for_special_event(c, priv->special_event)) != NULL) {
> +         xcb_present_generic_event_t *pe = (void *) ev;
> +
> +         switch (pe->evtype) {
> +         case XCB_PRESENT_EVENT_CONFIGURE_NOTIFY: {
> +            xcb_configure_notify_event_t *ce = (void *) ev;
> +
> +            priv->width = ce->width;
> +            priv->height = ce->height;
> +            break;
> +         }
> +         case XCB_PRESENT_EVENT_IDLE_NOTIFY:
> +            break;
> +         }
> +         free(ev);
> +      }
> +   }
> +   return true;
> +}
> +   
> +static __DRIdri3Buffer *
> +dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,
> +                       unsigned int format,
> +                       enum __DRI3bufferType buffer_type,
> +                       void *loaderPrivate)
> +{
> +   struct dri3_drawable                 *pdraw = loaderPrivate;
> +   __DRIdri3Buffer                      *buffer = pdraw->buffers[buffer_type];
> +   Pixmap                               pixmap;
> +   xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
> +   xcb_dri3_buffer_from_pixmap_reply_t  *bp_reply;
> +   int                                  *fds;
> +   int                                  buffer_fd;
> +   Display                              *dpy;
> +   struct dri3_screen                   *psc;
> +   xcb_connection_t                     *c;
> +   xcb_sync_fence_t                     sync_fence;
> +   int32_t                              *shm_fence;
> +   int                                  fence_fd;
> +
> +   if (buffer)
> +      return buffer;
> +
> +   pixmap = pdraw->base.xDrawable;
> +   psc = (struct dri3_screen *) pdraw->base.psc;
> +   dpy = psc->base.dpy;
> +   c = XGetXCBConnection(dpy);
> +
> +   fence_fd = xshmfence_alloc_shm();
> +   if (fence_fd < 0)
> +      return NULL;
> +   shm_fence = xshmfence_map_shm(fence_fd);
> +   if (shm_fence == NULL) {
> +      close (fence_fd);
> +      return NULL;
> +   }
> +
> +   xcb_dri3_fence_from_fd(c,
> +                          pixmap,
> +                          (sync_fence = xcb_generate_id(c)),
> +                          false,
> +                          fence_fd);
> +
> +   bp_cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
> +   bp_reply = xcb_dri3_buffer_from_pixmap_reply(c, bp_cookie, NULL);
> +   if (!bp_reply)
> +      goto no_pixmap;
> +   fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply);
> +   buffer_fd = fds[0];
> +   buffer = (*psc->dri3->fdToBuffer)(psc->driScreen,
> +                                     buffer_fd,
> +                                     format,
> +                                     bp_reply->width,
> +                                     bp_reply->height,
> +                                     bp_reply->stride,
> +                                     bp_reply->size);
> +   close(buffer_fd);
> +   if (!buffer)
> +      goto no_pixmap;
> +
> +   buffer->pixmap = pixmap;
> +   buffer->width = bp_reply->width;
> +   buffer->height = bp_reply->height;
> +   buffer->buffer_type = buffer_type;
> +   buffer->shm_fence = shm_fence;
> +   buffer->sync_fence = sync_fence;
> +
> +   pdraw->buffers[buffer_type] = buffer;
> +   return buffer;
> +
> +no_pixmap:
> +   xcb_sync_destroy_fence(c, sync_fence);
> +   xshmfence_unmap_shm(shm_fence);
> +   return NULL;
> +}
> +
> +static __DRIdri3Buffer *
> +dri3_get_buffer(__DRIdrawable *driDrawable,
> +                unsigned int format,
> +                enum __DRI3bufferType buffer_type,
> +                void *loaderPrivate)
> +{
> +   struct dri3_drawable *priv = loaderPrivate;
> +   __DRIdri3Buffer      *buffer = priv->buffers[buffer_type];
> +
> +   if (!buffer || buffer->width != priv->width || buffer->height != priv->height) {
> +      xcb_connection_t  *c = XGetXCBConnection(priv->base.psc->dpy);
> +      __DRIdri3Buffer   *new_buffer;
> +
> +      /* Allocate the new buffers
> +       */
> +      new_buffer = dri3_alloc_render_buffer(priv->base.psc,
> +                                            priv->base.xDrawable,
> +                                            format, priv->width, priv->height, priv->depth);
> +      if (!new_buffer)
> +         return NULL;
> +      switch (buffer_type) {
> +      case __DRI3_BUFFER_BACK:
> +         if (buffer) {
> +            dri3_fence_reset(c, new_buffer);
> +            dri3_fence_await(c, buffer);
> +            dri3_copy_area(c,
> +                           buffer->pixmap,
> +                           new_buffer->pixmap,
> +                           dri3_drawable_gc(priv),
> +                           0, 0, 0, 0, priv->width, priv->height);
> +            dri3_fence_trigger(c, new_buffer);
> +            dri3_free_render_buffer(priv, buffer);
> +            dri3_fence_await(c, new_buffer);
> +         }
> +         break;
> +      case __DRI3_BUFFER_FRONT:
> +         dri3_fence_reset(c, new_buffer);
> +         dri3_copy_area(c,
> +                        priv->base.xDrawable,
> +                        new_buffer->pixmap,
> +                        dri3_drawable_gc(priv),
> +                        0, 0, 0, 0, priv->width, priv->height);
> +         dri3_fence_trigger(c, new_buffer);
> +         dri3_fence_await(c, new_buffer);
> +         break;
> +      }
> +      buffer = new_buffer;
> +      buffer->buffer_type = buffer_type;
> +      priv->buffers[buffer_type] = buffer;
> +   }
> +
> +   /* Return the requested buffer */
> +   return buffer;
> +}
> +
> +static void
> +dri3_free_buffer(__DRIdrawable *driDrawable,
> +                 enum __DRI3bufferType buffer_type,
> +                 void *loaderPrivate)
> +{
> +   struct dri3_drawable *priv = loaderPrivate;
> +   __DRIdri3Buffer      *buffer = priv->buffers[buffer_type];
> +
> +   if (buffer) {
> +      dri3_free_render_buffer(priv, buffer);
> +      priv->buffers[buffer_type] = NULL;
> +   }
> +}
> +
> +static int
> +dri3_get_buffers(__DRIdrawable *driDrawable,
> +                 int *width, int *height,
> +                 unsigned int format,
> +                 void *loaderPrivate,
> +                 int need_front,
> +                 int need_back,
> +                 __DRIdri3Buffer **front,
> +                 __DRIdri3Buffer **back)
> +{
> +   struct dri3_drawable *priv = loaderPrivate;
> +
> +   *front = NULL;
> +   *back = NULL;
> +
> +   if (!dri3_update_drawable(driDrawable, loaderPrivate))
> +      return false;
> +
> +   if (priv->is_pixmap)
> +      need_front = 1;
> +
> +   if (need_front) {
> +      if (priv->is_pixmap)
> +         *front = dri3_get_pixmap_buffer(driDrawable,
> +                                         format,
> +                                         __DRI3_BUFFER_FRONT,
> +                                         loaderPrivate);
> +      else
> +         *front = dri3_get_buffer(driDrawable,
> +                                  format,
> +                                  __DRI3_BUFFER_FRONT,
> +                                  loaderPrivate);
> +
> +      if (!*front)
> +         return false;
> +      priv->have_fake_front = !priv->is_pixmap;
> +   } else {
> +      dri3_free_buffer(driDrawable, __DRI3_BUFFER_FRONT, loaderPrivate);
> +      priv->have_fake_front = 0;
> +   }
> +
> +   if (need_back) {
> +      *back = dri3_get_buffer(driDrawable,
> +                              format,
> +                              __DRI3_BUFFER_BACK,
> +                              loaderPrivate);
> +      if (!*back)
> +         return false;
> +      priv->have_back = 1;
> +   } else {
> +      dri3_free_buffer(driDrawable, __DRI3_BUFFER_BACK, loaderPrivate);
> +      priv->have_back = 0;
> +   }
> +
> +   /* Report back current geometry */
> +   *width = priv->width;
> +   *height = priv->height;
> +   return true;
> +}
> +
> +static int64_t
> +dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
> +                  int64_t remainder, Bool flush)
> +{
> +   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
> +   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
> +   xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
> +   int64_t ret = 0;
> +
> +   __DRIcontext *ctx = dri3_get_current_context();
> +   unsigned flags = __DRI2_FLUSH_DRAWABLE;
> +   if (flush)
> +      flags |= __DRI2_FLUSH_CONTEXT;
> +   dri3_flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
> +    
> +   if (priv->buffers[0] && !priv->is_pixmap) {
> +      dri3_fence_reset(c, priv->buffers[0]);
> +      dri3_copy_area(c,
> +                     priv->buffers[0]->pixmap,
> +                     priv->base.xDrawable,
> +                     dri3_drawable_gc(priv),
> +                     0, 0, 0, 0, priv->width, priv->height);
> +      dri3_fence_trigger(c, priv->buffers[0]);
> +      if (priv->have_fake_front) {
> +         dri3_fence_reset(c, priv->buffers[1]);
> +         dri3_copy_area(c,
> +                        priv->buffers[0]->pixmap,
> +                        priv->buffers[1]->pixmap,
> +                        dri3_drawable_gc(priv),
> +                        0, 0, 0, 0, priv->width, priv->height);
> +         dri3_fence_trigger(c, priv->buffers[1]);
> +      }
> +      dri3_fence_await(c, priv->buffers[0]);
> +      if (priv->have_fake_front)
> +         dri3_fence_await(c, priv->buffers[1]);
> +   }
> +
> +   return ret;
> +}
> +
> +static int
> +dri3_query_version(Display *dpy, int *major, int *minor)
> +{
> +   xcb_dri3_query_version_cookie_t      cookie;
> +   xcb_dri3_query_version_reply_t       *reply;       
> +   xcb_connection_t                     *c = XGetXCBConnection(dpy);
> +   xcb_generic_error_t                  *error;
> +
> +   cookie = xcb_dri3_query_version(c,
> +                                   XCB_DRI3_MAJOR_VERSION,
> +                                   XCB_DRI3_MINOR_VERSION);
> +   reply = xcb_dri3_query_version_reply(c, cookie, &error);
> +   if (!reply) {
> +      if (error) {
> +         free(error);
> +      }
> +      return 0;
> +   }
> +   *major = reply->major_version;
> +   *minor = reply->minor_version;
> +   free(reply);
> +   return 1;
> +}
> +
> +static int
> +dri3_open(Display *dpy,
> +          Window root,
> +          CARD32 provider)
> +{
> +   xcb_dri3_open_cookie_t       cookie;
> +   xcb_dri3_open_reply_t        *reply;       
> +   xcb_connection_t             *c = XGetXCBConnection(dpy);
> +   xcb_generic_error_t          *error;
> +   int                          fd;
> +
> +   cookie = xcb_dri3_open(c,
> +                          root,
> +                          provider);
> +
> +   reply = xcb_dri3_open_reply(c, cookie, &error);
> +   if (!reply)
> +      return -1;
> +
> +   if (reply->nfd != 1) {
> +      free(reply);
> +      return -1;
> +   }
> +
> +   fd = xcb_dri3_open_reply_fds(c, reply)[0];
> +   fcntl(fd, F_SETFD, FD_CLOEXEC);
> +
> +   return fd;
> +}
> +
> +
> +static void
> +dri3_destroy_screen(struct glx_screen *base)
> +{
> +   struct dri3_screen *psc = (struct dri3_screen *) base;
> +
> +   /* Free the direct rendering per screen data */
> +   (*psc->core->destroyScreen) (psc->driScreen);
> +   driDestroyConfigs(psc->driver_configs);
> +   close(psc->fd);
> +   free(psc);
> +}
> +
> +#if HAS_SBC
> +static int
> +dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
> +{
> +   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
> +   struct dri3_drawable *priv =  (struct dri3_drawable *) pdraw;
> +   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
> +   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
> +
> +   if (psc->config)
> +      psc->config->configQueryi(psc->driScreen,
> +				"vblank_mode", &vblank_mode);
> +
> +   switch (vblank_mode) {
> +   case DRI_CONF_VBLANK_NEVER:
> +      if (interval != 0)
> +         return GLX_BAD_VALUE;
> +      break;
> +   case DRI_CONF_VBLANK_ALWAYS_SYNC:
> +      if (interval <= 0)
> +	 return GLX_BAD_VALUE;
> +      break;
> +   default:
> +      break;
> +   }
> +
> +   xcb_dri2_swap_interval(c, priv->base.xDrawable, interval);
> +   priv->swap_interval = interval;
> +
> +   return 0;
> +}
> +
> +static int
> +dri3_get_swap_interval(__GLXDRIdrawable *pdraw)
> +{
> +   struct dri3_drawable *priv =  (struct dri3_drawable *) pdraw;
> +
> +  return priv->swap_interval;
> +}
> +#endif
> +
> +static const __DRIdri3LoaderExtension dri3LoaderExtension = {
> +   {__DRI_DRI3_LOADER, __DRI_DRI3_LOADER_VERSION},
> +   .getBuffers = dri3_get_buffers,
> +   .flushFrontBuffer = dri3_flush_front_buffer,
> +};
> +
> +static void
> +dri3_bind_tex_image(Display * dpy,
> +		    GLXDrawable drawable,
> +		    int buffer, const int *attrib_list)
> +{
> +   struct glx_context *gc = __glXGetCurrentContext();
> +   struct dri3_context *pcp = (struct dri3_context *) gc;
> +   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
> +   struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
> +   struct dri3_screen *psc;
> +
> +   if (pdraw != NULL) {
> +      psc = (struct dri3_screen *) base->psc;
> +
> +      if (psc->f &&
> +           psc->f->base.version >= 3 && psc->f->invalidate)
> +	 psc->f->invalidate(pdraw->driDrawable);
> +
> +      XSync(dpy, false);
> +      if (psc->texBuffer->base.version >= 2 &&
> +	  psc->texBuffer->setTexBuffer2 != NULL) {
> +	 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
> +					   pdraw->base.textureTarget,
> +					   pdraw->base.textureFormat,
> +					   pdraw->driDrawable);
> +      }
> +      else {
> +	 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
> +					  pdraw->base.textureTarget,
> +					  pdraw->driDrawable);
> +      }
> +   }
> +}
> +
> +static void
> +dri3_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
> +{
> +#if __DRI_TEX_BUFFER_VERSION >= 3
> +   struct glx_context *gc = __glXGetCurrentContext();
> +   struct dri3_context *pcp = (struct dri3_context *) gc;
> +   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
> +   struct glx_display *dpyPriv = __glXInitialize(dpy);
> +   struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
> +   struct dri3_display *pdp =
> +      (struct dri3_display *) dpyPriv->dri3Display;
> +   struct dri3_screen *psc;
> +
> +   if (pdraw != NULL) {
> +      psc = (struct dri3_screen *) base->psc;
> +
> +      if (psc->texBuffer->base.version >= 3 &&
> +          psc->texBuffer->releaseTexBuffer != NULL) {
> +         (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
> +                                           pdraw->base.textureTarget,
> +                                           pdraw->driDrawable);
> +      }
> +   }
> +#endif
> +}
> +
> +static const struct glx_context_vtable dri3_context_vtable = {
> +   dri3_destroy_context,
> +   dri3_bind_context,
> +   dri3_unbind_context,
> +   dri3_wait_gl,
> +   dri3_wait_x,
> +   DRI_glXUseXFont,
> +   dri3_bind_tex_image,
> +   dri3_release_tex_image,
> +   NULL, /* get_proc_address */
> +};
> +
> +static void
> +dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
> +                     const char *driverName)
> +{
> +//   const struct dri3_display *const pdp = (struct dri3_display *) priv->dri3Display;
> +   const __DRIextension **extensions;
> +   unsigned mask;
> +   int i;
> +
> +   extensions = psc->core->getExtensions(psc->driScreen);
> +
> +   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
> +   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
> +   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
> +   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
> +
> +   /*
> +    * GLX_INTEL_swap_event is broken on the server side, where it's
> +    * currently unconditionally enabled. This completely breaks
> +    * systems running on drivers which don't support that extension.
> +    * There's no way to test for its presence on this side, so instead
> +    * of disabling it unconditionally, just disable it for drivers
> +    * which are known to not support it, or for DDX drivers supporting
> +    * only an older (pre-ScheduleSwap) version of DRI2.
> +    *
> +    * This is a hack which is required until:
> +    * http://lists.x.org/archives/xorg-devel/2013-February/035449.html
> +    * is merged and updated xserver makes it's way into distros:
> +    */
> +//   if (pdp->swapAvailable && strcmp(driverName, "vmwgfx") != 0) {
> +//      __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
> +//   }
> +
> +   mask = psc->dri3->getAPIMask(psc->driScreen);
> +
> +   __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
> +   __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
> +
> +   if ((mask & (1 << __DRI_API_GLES2)) != 0)
> +      __glXEnableDirectExtension(&psc->base,
> +                                 "GLX_EXT_create_context_es2_profile");
> +
> +   for (i = 0; extensions[i]; i++) {
> +      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
> +	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
> +	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
> +      }
> +
> +      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
> +	 psc->f = (__DRI2flushExtension *) extensions[i];
> +	 /* internal driver extension, no GL extension exposed */
> +      }
> +
> +      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
> +	 psc->config = (__DRI2configQueryExtension *) extensions[i];
> +
> +      if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0)))
> +	 psc->throttle = (__DRI2throttleExtension *) extensions[i];
> +
> +      if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
> +         __glXEnableDirectExtension(&psc->base,
> +                                    "GLX_ARB_create_context_robustness");
> +   }
> +}
> +
> +static const struct glx_screen_vtable dri3_screen_vtable = {
> +   dri3_create_context,
> +   dri3_create_context_attribs
> +};
> +
> +static struct glx_screen *
> +dri3_create_screen(int screen, struct glx_display * priv)
> +{
> +   const __DRIconfig **driver_configs;
> +   const __DRIextension **extensions;
> +   const struct dri3_display *const pdp = (struct dri3_display *)
> +      priv->dri3Display;
> +   struct dri3_screen *psc;
> +   __GLXDRIscreen *psp;
> +   struct glx_config *configs = NULL, *visuals = NULL;
> +   char *driverName, *deviceName, *tmp;
> +   int i;
> +
> +   psc = calloc(1, sizeof *psc);
> +   if (psc == NULL)
> +      return NULL;
> +
> +   psc->fd = -1;
> +
> +   if (!glx_screen_init(&psc->base, screen, priv)) {
> +      free(psc);
> +      return NULL;
> +   }
> +
> +   psc->fd = dri3_open(priv->dpy, RootWindow(priv->dpy, screen), None);
> +   if (psc->fd < 0) {
> +      glx_screen_cleanup(&psc->base);
> +      free(psc);
> +      InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen);
> +      return NULL;
> +   }
> +   deviceName = NULL;
> +
> +   driverName = dri3_get_driver_for_fd(psc->fd);
> +   if (!driverName) {
> +      ErrorMessageF("No driver found\n");
> +      goto handle_error;
> +   }
> +
> +   psc->driver = driOpenDriver(driverName);
> +   if (psc->driver == NULL) {
> +      ErrorMessageF("driver pointer missing\n");
> +      goto handle_error;
> +   }
> +
> +   extensions = driGetDriverExtensions(psc->driver, driverName);
> +   if (extensions == NULL)
> +      goto handle_error;
> +
> +   for (i = 0; extensions[i]; i++) {
> +      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
> +	 psc->core = (__DRIcoreExtension *) extensions[i];
> +      if (strcmp(extensions[i]->name, __DRI_DRI3) == 0)
> +	 psc->dri3 = (__DRIdri3Extension *) extensions[i];
> +   }
> +
> +   if (psc->core == NULL || psc->dri3 == NULL) {
> +      ErrorMessageF("core dri or dri3 extension not found\n");
> +      goto handle_error;
> +   }
> +
> +   psc->driScreen =
> +      psc->dri3->createNewScreen2(screen, psc->fd,
> +                                  (const __DRIextension **)
> +                                  &pdp->loader_extensions[0],
> +                                  extensions,
> +                                  &driver_configs, psc);
> +
> +   if (psc->driScreen == NULL) {
> +      ErrorMessageF("failed to create dri screen\n");
> +      goto handle_error;
> +   }
> +
> +   dri3_bind_extensions(psc, priv, driverName);
> +
> +   configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
> +   visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
> +
> +   if (!configs || !visuals)
> +       goto handle_error;
> +
> +   glx_config_destroy_list(psc->base.configs);
> +   psc->base.configs = configs;
> +   glx_config_destroy_list(psc->base.visuals);
> +   psc->base.visuals = visuals;
> +
> +   psc->driver_configs = driver_configs;
> +
> +   psc->base.vtable = &dri3_screen_vtable;
> +   psp = &psc->vtable;
> +   psc->base.driScreen = psp;
> +   psp->destroyScreen = dri3_destroy_screen;
> +   psp->createDrawable = dri3_create_drawable;
> +   psp->swapBuffers = dri3_swap_buffers;
> +   psp->getDrawableMSC = NULL;
> +   psp->waitForMSC = NULL;
> +   psp->waitForSBC = NULL;
> +   psp->setSwapInterval = NULL;
> +   psp->getSwapInterval = NULL;
> +
> +#if HAS_SBC
> +   if (pdp->driMinor >= 2) {
> +      psp->getDrawableMSC = dri3DrawableGetMSC;
> +      psp->waitForMSC = dri3WaitForMSC;
> +      psp->waitForSBC = dri3WaitForSBC;
> +      psp->setSwapInterval = dri3SetSwapInterval;
> +      psp->getSwapInterval = dri3GetSwapInterval;
> +      __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
> +   }
> +#endif
> +
> +   psp->copySubBuffer = dri3_copy_sub_buffer;
> +   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
> +
> +   free(driverName);
> +   free(deviceName);
> +
> +   tmp = getenv("LIBGL_SHOW_FPS");
> +   psc->show_fps = tmp && strcmp(tmp, "1") == 0;
> +
> +   return &psc->base;
> +
> +handle_error:
> +   CriticalErrorMessageF("failed to load driver: %s\n", driverName);
> +
> +   if (configs)
> +       glx_config_destroy_list(configs);
> +   if (visuals)
> +       glx_config_destroy_list(visuals);
> +   if (psc->driScreen)
> +       psc->core->destroyScreen(psc->driScreen);
> +   psc->driScreen = NULL;
> +   if (psc->fd >= 0)
> +      close(psc->fd);
> +   if (psc->driver)
> +      dlclose(psc->driver);
> +
> +   free(driverName);
> +   free(deviceName);
> +   glx_screen_cleanup(&psc->base);
> +   free(psc);
> +
> +   return NULL;
> +}
> +
> +/* Called from __glXFreeDisplayPrivate.
> + */
> +static void
> +dri3_destroy_display(__GLXDRIdisplay * dpy)
> +{
> +   free(dpy);
> +}
> +
> +/*
> + * Allocate, initialize and return a __DRIdisplayPrivate object.
> + * This is called from __glXInitialize() when we are given a new
> + * display pointer.
> + */
> +_X_HIDDEN __GLXDRIdisplay *
> +dri3_create_display(Display * dpy)
> +{
> +   struct dri3_display *pdp;
> +   int i;
> +
> +   pdp = malloc(sizeof *pdp);
> +   if (pdp == NULL)
> +      return NULL;
> +
> +   if (!dri3_query_version(dpy, &pdp->dri3Major, &pdp->dri3Minor)) {
> +      free(pdp);
> +      return NULL;
> +   }
> +
> +   pdp->base.destroyDisplay = dri3_destroy_display;
> +   pdp->base.createScreen = dri3_create_screen;
> +
> +   i = 0;
> +
> +   pdp->loader_extensions[i++] = &dri3LoaderExtension.base;
> +   
> +   pdp->loader_extensions[i++] = &systemTimeExtension.base;
> +
> +   pdp->loader_extensions[i++] = NULL;
> +
> +   return &pdp->base;
> +}
> +
> +#endif /* GLX_DIRECT_RENDERING */
> diff --git a/src/glx/dri3_priv.h b/src/glx/dri3_priv.h
> new file mode 100644
> index 0000000..8703b39
> --- /dev/null
> +++ b/src/glx/dri3_priv.h
> @@ -0,0 +1,128 @@
> +/*
> + * Copyright © 2013 Keith Packard
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and its
> + * documentation for any purpose is hereby granted without fee, provided that
> + * the above copyright notice appear in all copies and that both that copyright
> + * notice and this permission notice appear in supporting documentation, and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no representations
> + * about the suitability of this software for any purpose.  It is provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +/* This file was derived from dri2_priv.h which carries the following
> + * copyright:
> + *
> + * Copyright © 2008 Red Hat, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Soft-
> + * ware"), to deal in the Software without restriction, including without
> + * limitation the rights to use, copy, modify, merge, publish, distribute,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, provided that the above copyright
> + * notice(s) and this permission notice appear in all copies of the Soft-
> + * ware and that both the above copyright notice(s) and this permission
> + * notice appear in supporting documentation.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
> + * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
> + * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
> + * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
> + * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
> + * MANCE OF THIS SOFTWARE.
> + *
> + * Except as contained in this notice, the name of a copyright holder shall
> + * not be used in advertising or otherwise to promote the sale, use or
> + * other dealings in this Software without prior written authorization of
> + * the copyright holder.
> + *
> + * Authors:
> + *   Kristian Høgsberg (krh at redhat.com)
> + */
> +
> +#include <xcb/xcb.h>
> +#include <xcb/dri3.h>
> +#include <xcb/sync.h>
> +
> +/* From xmlpool/options.h, user exposed so should be stable */
> +#define DRI_CONF_VBLANK_NEVER 0
> +#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
> +#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
> +#define DRI_CONF_VBLANK_ALWAYS_SYNC 3
> +
> +struct dri3_display
> +{
> +   __GLXDRIdisplay base;
> +
> +   const __DRIextension *loader_extensions[8];
> +
> +   /* DRI3 bits */
> +   int dri3Major;
> +   int dri3Minor;
> +};
> +
> +struct dri3_screen {
> +   struct glx_screen base;
> +
> +   __DRIscreen *driScreen;
> +   __GLXDRIscreen vtable;
> +
> +   const __DRIdri3Extension *dri3;
> +   const __DRIcoreExtension *core;
> +   const __DRI2flushExtension *f;
> +   const __DRI2configQueryExtension *config;
> +   const __DRItexBufferExtension *texBuffer;
> +   const __DRI2throttleExtension *throttle;
> +   const __DRIconfig **driver_configs;
> +
> +   void *driver;
> +   int fd;
> +
> +   Bool show_fps;
> +};
> +
> +struct dri3_context
> +{
> +   struct glx_context base;
> +   __DRIcontext *driContext;
> +};
> +
> +struct dri3_drawable
> +{
> +   __GLXDRIdrawable base;
> +   __DRIdrawable *driDrawable;
> +   int width, height;
> +   int swap_interval;
> +   uint8_t have_back;
> +   uint8_t have_fake_front;
> +   uint8_t is_pixmap;
> +
> +   uint64_t previous_time;
> +   unsigned frames;
> +
> +   __DRIdri3Buffer *buffers[2];
> +   int depth;
> +
> +   xcb_present_event_t eid;
> +   xcb_gcontext_t gc;
> +   const xcb_query_extension_reply_t *dri3_extension;
> +   const xcb_query_extension_reply_t *present_extension;
> +   xcb_special_event_t *special_event;
> +};
> +
> +char *
> +dri3_get_driver_for_fd(int fd);
> diff --git a/src/glx/glxclient.h b/src/glx/glxclient.h
> index 81ae792..ec168aa 100644
> --- a/src/glx/glxclient.h
> +++ b/src/glx/glxclient.h
> @@ -150,6 +150,7 @@ extern __GLXDRIdisplay *dri2CreateDisplay(Display * dpy);
>  extern void dri2InvalidateBuffers(Display *dpy, XID drawable);
>  extern unsigned dri2GetSwapEventType(Display *dpy, XID drawable);
>  
> +extern __GLXDRIdisplay *dri3_create_display(Display * dpy);
>  
>  /*
>  ** Functions to obtain driver configuration information from a direct
> @@ -582,6 +583,7 @@ struct glx_display
>     __GLXDRIdisplay *driswDisplay;
>     __GLXDRIdisplay *driDisplay;
>     __GLXDRIdisplay *dri2Display;
> +   __GLXDRIdisplay *dri3Display;
>  #endif
>  };
>  
> diff --git a/src/glx/glxext.c b/src/glx/glxext.c
> index bea1ccb..c6e4d9f 100644
> --- a/src/glx/glxext.c
> +++ b/src/glx/glxext.c
> @@ -770,7 +770,9 @@ AllocAndFetchScreenConfigs(Display * dpy, struct glx_display * priv)
>     for (i = 0; i < screens; i++, psc++) {
>        psc = NULL;
>  #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
> -      if (priv->dri2Display)
> +      if (priv->dri3Display)
> +         psc = (*priv->dri3Display->createScreen) (i, priv);
> +      if (psc == NULL && priv->dri2Display)
>  	 psc = (*priv->dri2Display->createScreen) (i, priv);
>        if (psc == NULL && priv->driDisplay)
>  	 psc = (*priv->driDisplay->createScreen) (i, priv);
> @@ -863,6 +865,8 @@ __glXInitialize(Display * dpy)
>      ** (e.g., those called in AllocAndFetchScreenConfigs).
>      */
>     if (glx_direct && glx_accel) {
> +      if (!getenv("LIBGL_DRI3_DISABLE"))
> +         dpyPriv->dri3Display = dri3_create_display(dpy);
>        dpyPriv->dri2Display = dri2CreateDisplay(dpy);
>        dpyPriv->driDisplay = driCreateDisplay(dpy);
>     }
> diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c
> index 539fb4b..9b24e54 100644
> --- a/src/mesa/drivers/dri/common/dri_util.c
> +++ b/src/mesa/drivers/dri/common/dri_util.c
> @@ -729,7 +729,7 @@ const __DRIcoreExtension driCoreExtension = {
>      .createNewDrawable          = NULL,
>      .destroyDrawable            = driDestroyDrawable,
>      .swapBuffers                = driSwapBuffers, /* swrast */
> -    .createNewContext           = dri2CreateNewContext, /* swrast */
> +    .createNewContext           = driCreateNewContext, /* swrast */
>      .copyContext                = driCopyContext,
>      .destroyContext             = driDestroyContext,
>      .bindContext                = driBindContext,
> @@ -747,16 +747,16 @@ const __DRIdri2Extension driDRI2Extension = {
>      .createNewContextForAPI     = driCreateNewContextForAPI,
>      .allocateBuffer             = dri2AllocateBuffer,
>      .releaseBuffer              = dri2ReleaseBuffer,
> -    .createContextAttribs       = driCreateContextAttribs
> +    .createContextAttribs       = driCreateContextAttribs,
>      .createNewScreen2           = dri2CreateNewScreen2,
>  };
>  
>  const __DRIswrastExtension driSWRastExtension = {
>      { __DRI_SWRAST, 4 },
>      driSWRastCreateNewScreen,
> -    dri2CreateNewDrawable,
> -    dri2CreateNewContextForAPI,
> -    dri2CreateContextAttribs,
> +    driCreateNewDrawable,
> +    driCreateNewContextForAPI,
> +    driCreateContextAttribs,
>      driSWRastCreateNewScreen2,
>  };
>  
> @@ -792,3 +792,156 @@ driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv)
>        assert(fb->Height == dPriv->h);
>     }
>  }
> +
> +/*
> + * Copyright © 2013 Keith Packard
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and its
> + * documentation for any purpose is hereby granted without fee, provided that
> + * the above copyright notice appear in all copies and that both that copyright
> + * notice and this permission notice appear in supporting documentation, and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no representations
> + * about the suitability of this software for any purpose.  It is provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +uint32_t *
> +dri3DrawableStamp(__DRIdrawable *drawable)
> +{
> +   return &drawable->dri2.stamp;
> +}
> +
> +static __DRIdri3Buffer *
> +dri3AllocateBuffer(__DRIscreen *screen, unsigned int depth, int width, int height)
> +{
> +   return (*dri3DriverAPI.allocate_buffer) (screen, depth, width, height);
> +}
> +
> +static void
> +dri3ReleaseBuffer(__DRIscreen *screen, __DRIdri3Buffer *buffer)
> +{
> +   return (*dri3DriverAPI.release_buffer) (screen, buffer);
> +}
> +
> +static int
> +dri3BufferToFd(__DRIscreen *screen, __DRIdri3Buffer *buffer)
> +{
> +   return (*dri3DriverAPI.buffer_to_fd)(screen, buffer);
> +}
> +
> +static __DRIdri3Buffer *
> +dri3FdToBuffer(__DRIscreen *screen, int fd, unsigned int format, int width, int height, int stride, unsigned int size)
> +{
> +   return (*dri3DriverAPI.fd_to_buffer)(screen, fd, format, width, height, stride, size);
> +}
> +
> +static uint32_t *
> +dri3Stamp(__DRIdrawable *drawable)
> +{
> +   return (*dri3DriverAPI.stamp)(drawable);
> +}
> +
> +PUBLIC const char __dri3ConfigOptions[] =
> +   DRI_CONF_BEGIN
> +      DRI_CONF_SECTION_PERFORMANCE
> +         DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1)
> +      DRI_CONF_SECTION_END
> +   DRI_CONF_END;
> +
> +static __DRIscreen *
> +dri3CreateNewScreen2(int scrn, int fd,
> +                     const __DRIextension **extensions,
> +                     const __DRIextension **driver_extensions,
> +                     const __DRIconfig ***driver_configs, void *data)
> +{
> +    static const __DRIextension *emptyExtensionList[] = { NULL };
> +    __DRIscreen *psp;
> +    drmVersionPtr version;
> +
> +    psp = calloc(1, sizeof(*psp));
> +    if (!psp)
> +	return NULL;
> +
> +    /* By default, use the global driDriverAPI symbol (non-megadrivers). */
> +    psp->driver = globalDriverAPI;
> +
> +    /* If the driver exposes its vtable through its extensions list
> +     * (megadrivers), use that instead.
> +     */
> +    if (driver_extensions) {
> +       for (int i = 0; driver_extensions[i]; i++) {
> +          if (strcmp(driver_extensions[i]->name, __DRI_DRIVER_VTABLE) == 0) {
> +             psp->driver =
> +                ((__DRIDriverVtableExtension *)driver_extensions[i])->vtable;
> +          }
> +       }
> +    }
> +
> +    setupLoaderExtensions(psp, extensions);
> +    setup_dri3_loader_extensions(psp, extensions);
> +
> +    version = drmGetVersion(fd);
> +    if (version) {
> +	psp->drm_version.major = version->version_major;
> +	psp->drm_version.minor = version->version_minor;
> +	psp->drm_version.patch = version->version_patchlevel;
> +	drmFreeVersion(version);
> +    }
> +
> +    psp->loaderPrivate = data;
> +
> +    psp->extensions = emptyExtensionList;
> +    psp->fd = fd;
> +    psp->myNum = scrn;
> +
> +    psp->api_mask = (1 << __DRI_API_OPENGL);
> +
> +    *driver_configs = psp->driver->InitScreen(psp);
> +    if (*driver_configs == NULL) {
> +	free(psp);
> +	return NULL;
> +    }
> +
> +    driParseOptionInfo(&psp->optionInfo, __dri3ConfigOptions);
> +    driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, "dri3");
> +
> +    return psp;
> +}
> +
> +void
> +setup_dri3_loader_extensions(__DRIscreen *psp,
> +                            const __DRIextension *const*extensions)
> +{
> +    int i;
> +
> +    for (i = 0; extensions[i]; i++) {
> +        if (strcmp(extensions[i]->name, __DRI_DRI3_LOADER) == 0)
> +           psp->dri3.loader = (__DRIdri3LoaderExtension *) extensions[i];
> +    }
> +}
> +
> +/** DRI3 interface */
> +const __DRIdri3Extension driDRI3Extension = {
> +    .base = { __DRI_DRI3, 1 },
> +
> +    .createNewScreen2           = dri3CreateNewScreen2,
> +    .createNewDrawable          = driCreateNewDrawable,
> +    .createNewContext           = driCreateNewContext,
> +    .getAPIMask                 = driGetAPIMask,
> +    .createContextAttribs       = driCreateContextAttribs,
> +    .allocateBuffer             = dri3AllocateBuffer,
> +    .releaseBuffer              = dri3ReleaseBuffer,
> +    .bufferToFd                 = dri3BufferToFd,
> +    .fdToBuffer                 = dri3FdToBuffer,
> +    .stamp                      = dri3Stamp,
> +};
> diff --git a/src/mesa/drivers/dri/common/dri_util.h b/src/mesa/drivers/dri/common/dri_util.h
> index 5b56061..9e96282 100644
> --- a/src/mesa/drivers/dri/common/dri_util.h
> +++ b/src/mesa/drivers/dri/common/dri_util.h
> @@ -174,6 +174,10 @@ struct __DRIscreenRec {
>  	__DRIuseInvalidateExtension *useInvalidate;
>      } dri2;
>  
> +    struct {
> +        __DRIdri3LoaderExtension *loader;
> +    } dri3;
> +
>      driOptionCache optionInfo;
>      driOptionCache optionCache;
>  
> @@ -277,4 +281,23 @@ dri2InvalidateDrawable(__DRIdrawable *drawable);
>  extern void
>  driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv);
>  
> +uint32_t *
> +dri3DrawableStamp(__DRIdrawable *drawable);
> +
> +void
> +setup_dri3_loader_extensions(__DRIscreen *psp,
> +                             const __DRIextension *const*extensions);
> +
> +struct __dri3DriverAPIRec {
> +   __DRIdri3AllocateBuffer      allocate_buffer;
> +   __DRIdri3ReleaseBuffer       release_buffer;
> +   __DRIdri3BufferToFd          buffer_to_fd;
> +   __DRIdri3FdToBuffer          fd_to_buffer;
> +   __DRIdri3Stamp               stamp;
> +};
> +
> +extern const struct __dri3DriverAPIRec dri3DriverAPI;
> +
> +extern const __DRIdri3Extension driDRI3Extension;
> +
>  #endif /* _DRI_UTIL_H_ */
> diff --git a/src/mesa/drivers/dri/i915/intel_context.c b/src/mesa/drivers/dri/i915/intel_context.c
> index 1798bc7..b99ff09 100644
> --- a/src/mesa/drivers/dri/i915/intel_context.c
> +++ b/src/mesa/drivers/dri/i915/intel_context.c
> @@ -91,6 +91,8 @@ intelGetString(struct gl_context * ctx, GLenum name)
>     }
>  }
>  
> +#define flushFront(screen)      ((screen)->dri3.loader ? (screen)->dri3.loader->flushFrontBuffer : (screen)->dri2.loader->flushFrontBuffer)
> +
>  static void
>  intel_flush_front(struct gl_context *ctx)
>  {
> @@ -100,11 +102,10 @@ intel_flush_front(struct gl_context *ctx)
>      __DRIscreen *const screen = intel->intelScreen->driScrnPriv;
>  
>      if (intel->front_buffer_dirty && _mesa_is_winsys_fbo(ctx->DrawBuffer)) {
> -      if (screen->dri2.loader->flushFrontBuffer != NULL &&
> +      if (flushFront(screen) && 
>            driDrawable &&
>            driDrawable->loaderPrivate) {
> -         screen->dri2.loader->flushFrontBuffer(driDrawable,
> -                                               driDrawable->loaderPrivate);
> +         flushFront(screen)(driDrawable, driDrawable->loaderPrivate);
>  
>  	 /* We set the dirty bit in intel_prepare_render() if we're
>  	  * front buffer rendering once we get there.
> @@ -114,6 +115,9 @@ intel_flush_front(struct gl_context *ctx)
>     }
>  }
>  
> +static void
> +intel_update_dri3_buffers(struct intel_context *intel, __DRIdrawable *drawable);
> +
>  static unsigned
>  intel_bits_per_pixel(const struct intel_renderbuffer *rb)
>  {
> @@ -194,7 +198,10 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
>     if (unlikely(INTEL_DEBUG & DEBUG_DRI))
>        fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable);
>  
> -   intel_update_dri2_buffers(intel, drawable);
> +   if (screen->dri3.loader)
> +      intel_update_dri3_buffers(intel, drawable);
> +   else
> +      intel_update_dri2_buffers(intel, drawable);
>  
>     driUpdateFramebufferSize(&intel->ctx, drawable);
>  }
> @@ -787,3 +794,97 @@ intel_process_dri2_buffer(struct intel_context *intel,
>                                                   region);
>     intel_region_release(&region);
>  }
> +
> +/**
> + * \brief Query DRI3 to obtain a DRIdrawable's buffers.
> + *
> + * To determine which DRI buffers to request, examine the renderbuffers
> + * attached to the drawable's framebuffer. Then request the buffers with
> + * dri3
> + *
> + * This is called from intel_update_renderbuffers().
> + *
> + * \param drawable      Drawable whose buffers are queried.
> + * \param buffers       [out] List of buffers returned by DRI2 query.
> + * \param buffer_count  [out] Number of buffers returned.
> + *
> + * \see intel_update_renderbuffers()
> + */
> +
> +static void
> +intel_update_dri3_buffer(struct intel_context *intel,
> +                         __DRIdrawable *drawable,
> +                         struct intel_renderbuffer *rb,
> +                         __DRIdri3Buffer *buffer)
> +{
> +   struct intel_region *region = buffer->driverPrivate;
> +
> +   if (!rb || !region)
> +      return;
> +
> +   unsigned num_samples = rb->Base.Base.NumSamples;
> +
> +   if (rb->mt &&
> +       rb->mt->region &&
> +       rb->mt->region == region)
> +      return;
> +
> +   intel_miptree_release(&rb->mt);
> +   rb->mt = intel_miptree_create_for_dri3_buffer(intel,
> +                                                 buffer->buffer_type,
> +                                                 intel_rb_format(rb),
> +                                                 num_samples,
> +                                                 region);
> +}
> +
> +
> +static void
> +intel_update_dri3_buffers(struct intel_context *intel, __DRIdrawable *drawable)
> +{
> +   struct gl_framebuffer *fb = drawable->driverPrivate;
> +   __DRIscreen *screen = intel->intelScreen->driScrnPriv;
> +   struct intel_renderbuffer *front_rb;
> +   struct intel_renderbuffer *back_rb;
> +   int need_front = 0, need_back = 0;
> +   __DRIdri3Buffer *front, *back;
> +   unsigned int format;
> +
> +   front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
> +   back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT);
> +
> +   if (back_rb)
> +      format = intel_rb_format(back_rb);
> +   else if (front_rb)
> +      format = intel_rb_format(front_rb);
> +   else
> +      return;
> +
> +   if ((intel->is_front_buffer_rendering || intel->is_front_buffer_reading || !back_rb) && front_rb)
> +      need_front = 1;
> +
> +   if (back_rb)
> +      need_back = 1;
> +
> +   (*screen->dri3.loader->getBuffers) (drawable,
> +                                       &drawable->w,
> +                                       &drawable->h,
> +                                       format,
> +                                       drawable->loaderPrivate,
> +                                       need_front,
> +                                       need_back,
> +                                       &front,
> +                                       &back);
> +
> +   if (front) {
> +      assert(front_rb);
> +      intel_update_dri3_buffer(intel,
> +                               drawable,
> +                               front_rb,
> +                               front);
> +   }
> +   if (back)
> +      intel_update_dri3_buffer(intel,
> +                               drawable,
> +                               back_rb,
> +                               back);
> +}
> diff --git a/src/mesa/drivers/dri/i915/intel_mipmap_tree.c b/src/mesa/drivers/dri/i915/intel_mipmap_tree.c
> index 8432b6d..97dcf80 100644
> --- a/src/mesa/drivers/dri/i915/intel_mipmap_tree.c
> +++ b/src/mesa/drivers/dri/i915/intel_mipmap_tree.c
> @@ -322,6 +322,39 @@ intel_miptree_create_for_dri2_buffer(struct intel_context *intel,
>     return mt;
>  }
>  
> +/**
> + * For a singlesample DRI3 buffer, this simply wraps the given region with a miptree.
> + *
> + * For a multisample DRI3 buffer, this wraps the given region with
> + * a singlesample miptree, then creates a multisample miptree into which the
> + * singlesample miptree is embedded as a child.
> + */
> +struct intel_mipmap_tree*
> +intel_miptree_create_for_dri3_buffer(struct intel_context *intel,
> +                                     enum __DRI3bufferType buffer_type,
> +                                     gl_format format,
> +                                     uint32_t num_samples,
> +                                     struct intel_region *region)
> +{
> +   struct intel_mipmap_tree *mt = NULL;
> +
> +   /* Only the front and back buffers, which are color buffers, are allocated
> +    * through DRI3.
> +    */
> +   assert(_mesa_get_format_base_format(format) == GL_RGB ||
> +          _mesa_get_format_base_format(format) == GL_RGBA);
> +
> +   mt = intel_miptree_create_for_bo(intel,
> +                                    region->bo,
> +                                    format,
> +                                    0,
> +                                    region->width,
> +                                    region->height,
> +                                    region->pitch,
> +                                    region->tiling);
> +   return mt;
> +}
> +
>  struct intel_mipmap_tree*
>  intel_miptree_create_for_renderbuffer(struct intel_context *intel,
>                                        gl_format format,
> diff --git a/src/mesa/drivers/dri/i915/intel_mipmap_tree.h b/src/mesa/drivers/dri/i915/intel_mipmap_tree.h
> index 1142af6..299ae99 100644
> --- a/src/mesa/drivers/dri/i915/intel_mipmap_tree.h
> +++ b/src/mesa/drivers/dri/i915/intel_mipmap_tree.h
> @@ -32,6 +32,7 @@
>  
>  #include "intel_screen.h"
>  #include "intel_regions.h"
> +#include "GL/internal/dri_interface.h"
>  
>  #ifdef __cplusplus
>  extern "C" {
> @@ -258,6 +259,13 @@ intel_miptree_create_for_dri2_buffer(struct intel_context *intel,
>                                       gl_format format,
>                                       struct intel_region *region);
>  
> +struct intel_mipmap_tree*
> +intel_miptree_create_for_dri3_buffer(struct intel_context *intel,
> +                                     enum __DRI3bufferType buffer_type,
> +                                     gl_format format,
> +                                     uint32_t num_samples,
> +                                     struct intel_region *region);
> +
>  /**
>   * Create a miptree appropriate as the storage for a non-texture renderbuffer.
>   * The miptree has the following properties:
> diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
> index c213b31..ecf5bd7 100644
> --- a/src/mesa/drivers/dri/i965/brw_context.c
> +++ b/src/mesa/drivers/dri/i965/brw_context.c
> @@ -151,6 +151,8 @@ intelInvalidateState(struct gl_context * ctx, GLuint new_state)
>     brw->NewGLState |= new_state;
>  }
>  
> +#define flushFront(screen)      ((screen)->dri3.loader ? (screen)->dri3.loader->flushFrontBuffer : (screen)->dri2.loader->flushFrontBuffer)
> +
>  static void
>  intel_flush_front(struct gl_context *ctx)
>  {
> @@ -160,8 +162,7 @@ intel_flush_front(struct gl_context *ctx)
>     __DRIscreen *const screen = brw->intelScreen->driScrnPriv;
>  
>     if (brw->front_buffer_dirty && _mesa_is_winsys_fbo(ctx->DrawBuffer)) {
> -      if (screen->dri2.loader->flushFrontBuffer != NULL &&
> -          driDrawable &&
> +      if (flushFront(screen) && driDrawable &&
>            driDrawable->loaderPrivate) {
>  
>           /* Resolve before flushing FAKE_FRONT_LEFT to FRONT_LEFT.
> @@ -174,8 +175,7 @@ intel_flush_front(struct gl_context *ctx)
>           intel_resolve_for_dri2_flush(brw, driDrawable);
>           intel_batchbuffer_flush(brw);
>  
> -         screen->dri2.loader->flushFrontBuffer(driDrawable,
> -                                               driDrawable->loaderPrivate);
> +         flushFront(screen)(driDrawable, driDrawable->loaderPrivate);
>  
>           /* We set the dirty bit in intel_prepare_render() if we're
>            * front buffer rendering once we get there.
> @@ -930,6 +930,9 @@ intel_process_dri2_buffer(struct brw_context *brw,
>                            const char *buffer_name);
>  
>  static void
> +intel_update_dri3_buffers(struct brw_context *brw, __DRIdrawable *drawable);
> +
> +static void
>  intel_update_dri2_buffers(struct brw_context *brw, __DRIdrawable *drawable)
>  {
>     struct gl_framebuffer *fb = drawable->driverPrivate;
> @@ -989,6 +992,7 @@ void
>  intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
>  {
>     struct brw_context *brw = context->driverPrivate;
> +   __DRIscreen *screen = brw->intelScreen->driScrnPriv;
>  
>     /* Set this up front, so that in case our buffers get invalidated
>      * while we're getting new buffers, we don't clobber the stamp and
> @@ -998,7 +1002,10 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
>     if (unlikely(INTEL_DEBUG & DEBUG_DRI))
>        fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable);
>  
> -   intel_update_dri2_buffers(brw, drawable);
> +   if (screen->dri3.loader)
> +      intel_update_dri3_buffers(brw, drawable);
> +   else
> +      intel_update_dri2_buffers(brw, drawable);
>  
>     driUpdateFramebufferSize(&brw->ctx, drawable);
>  }
> @@ -1204,3 +1211,96 @@ intel_process_dri2_buffer(struct brw_context *brw,
>                                                   region);
>     intel_region_release(&region);
>  }
> +
> +/**
> + * \brief Query DRI3 to obtain a DRIdrawable's buffers.
> + *
> + * To determine which DRI buffers to request, examine the renderbuffers
> + * attached to the drawable's framebuffer. Then request the buffers with
> + * dri3
> + *
> + * This is called from intel_update_renderbuffers().
> + *
> + * \param drawable      Drawable whose buffers are queried.
> + * \param buffers       [out] List of buffers returned by DRI2 query.
> + * \param buffer_count  [out] Number of buffers returned.
> + *
> + * \see intel_update_renderbuffers()
> + */
> +
> +static void
> +intel_update_dri3_buffer(struct brw_context *intel,
> +                         __DRIdrawable *drawable,
> +                         struct intel_renderbuffer *rb,
> +                         __DRIdri3Buffer *buffer)
> +{
> +   struct intel_region *region = buffer->driverPrivate;
> +
> +   if (!rb || !region)
> +      return;
> +
> +   unsigned num_samples = rb->Base.Base.NumSamples;
> +
> +   if (rb->mt &&
> +       rb->mt->region &&
> +       rb->mt->region == region)
> +      return;
> +
> +   intel_miptree_release(&rb->mt);
> +   rb->mt = intel_miptree_create_for_dri3_buffer(intel,
> +                                                 buffer->buffer_type,
> +                                                 intel_rb_format(rb),
> +                                                 num_samples,
> +                                                 region);
> +}
> +
> +static void
> +intel_update_dri3_buffers(struct brw_context *brw, __DRIdrawable *drawable)
> +{
> +   struct gl_framebuffer *fb = drawable->driverPrivate;
> +   __DRIscreen *screen = brw->intelScreen->driScrnPriv;
> +   struct intel_renderbuffer *front_rb;
> +   struct intel_renderbuffer *back_rb;
> +   int need_front = 0, need_back = 0;
> +   __DRIdri3Buffer *front, *back;
> +   unsigned int format;
> +
> +   front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
> +   back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT);
> +
> +   if (back_rb)
> +      format = intel_rb_format(back_rb);
> +   else if (front_rb)
> +      format = intel_rb_format(front_rb);
> +   else
> +      return;
> +
> +   if ((brw->is_front_buffer_rendering || brw->is_front_buffer_reading || !back_rb) && front_rb)
> +      need_front = 1;
> +
> +   if (back_rb)
> +      need_back = 1;
> +
> +   (*screen->dri3.loader->getBuffers) (drawable,
> +                                       &drawable->w,
> +                                       &drawable->h,
> +                                       format,
> +                                       drawable->loaderPrivate,
> +                                       need_front,
> +                                       need_back,
> +                                       &front,
> +                                       &back);
> +
> +   if (front) {
> +      assert(front_rb);
> +      intel_update_dri3_buffer(brw,
> +                               drawable,
> +                               front_rb,
> +                               front);
> +   }
> +   if (back)
> +      intel_update_dri3_buffer(brw,
> +                               drawable,
> +                               back_rb,
> +                               back);
> +}
> diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c
> index 2f5e04f..5c62a74 100644
> --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c
> +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c
> @@ -725,6 +725,67 @@ intel_miptree_create_for_dri2_buffer(struct brw_context *brw,
>     return multisample_mt;
>  }
>  
> +/**
> + * For a singlesample DRI3 buffer, this simply wraps the given region with a miptree.
> + *
> + * For a multisample DRI3 buffer, this wraps the given region with
> + * a singlesample miptree, then creates a multisample miptree into which the
> + * singlesample miptree is embedded as a child.
> + */
> +struct intel_mipmap_tree*
> +intel_miptree_create_for_dri3_buffer(struct brw_context *intel,
> +                                     enum __DRI3bufferType buffer_type,
> +                                     gl_format format,
> +                                     uint32_t num_samples,
> +                                     struct intel_region *region)
> +{
> +   struct intel_mipmap_tree *singlesample_mt = NULL;
> +   struct intel_mipmap_tree *multisample_mt = NULL;
> +
> +   /* Only the front and back buffers, which are color buffers, are allocated
> +    * through DRI3.
> +    */
> +   assert(_mesa_get_format_base_format(format) == GL_RGB ||
> +          _mesa_get_format_base_format(format) == GL_RGBA);
> +
> +   singlesample_mt = intel_miptree_create_for_bo(intel,
> +                                                 region->bo,
> +                                                 format,
> +                                                 0,
> +                                                 region->width,
> +                                                 region->height,
> +                                                 region->pitch,
> +                                                 region->tiling);
> +   if (!singlesample_mt)
> +      return NULL;
> +
> +   intel_region_reference(&singlesample_mt->region, region);
> +
> +   if (num_samples == 0)
> +      return singlesample_mt;
> +
> +   multisample_mt = intel_miptree_create_for_renderbuffer(intel,
> +                                                          format,
> +                                                          region->width,
> +                                                          region->height,
> +                                                          num_samples);
> +   if (!multisample_mt) {
> +      intel_miptree_release(&singlesample_mt);
> +      return NULL;
> +   }
> +
> +   multisample_mt->singlesample_mt = singlesample_mt;
> +   multisample_mt->need_downsample = false;
> +
> +   intel_region_reference(&multisample_mt->region, region);
> +
> +   if (intel->is_front_buffer_rendering && buffer_type == __DRI3_BUFFER_FRONT) {
> +      intel_miptree_upsample(intel, multisample_mt);
> +   }
> +
> +   return multisample_mt;
> +}
> +
>  struct intel_mipmap_tree*
>  intel_miptree_create_for_renderbuffer(struct brw_context *brw,
>                                        gl_format format,
> diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h
> index d718125..0c1922d 100644
> --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h
> +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h
> @@ -32,6 +32,7 @@
>  
>  #include "intel_regions.h"
>  #include "intel_resolve_map.h"
> +#include <GL/internal/dri_interface.h>
>  
>  #ifdef __cplusplus
>  extern "C" {
> @@ -529,6 +530,13 @@ intel_miptree_create_for_dri2_buffer(struct brw_context *brw,
>                                       uint32_t num_samples,
>                                       struct intel_region *region);
>  
> +struct intel_mipmap_tree*
> +intel_miptree_create_for_dri3_buffer(struct brw_context *intel,
> +                                     enum __DRI3bufferType buffer_type,
> +                                     gl_format format,
> +                                     uint32_t num_samples,
> +                                     struct intel_region *region);
> +
>  /**
>   * Create a miptree appropriate as the storage for a non-texture renderbuffer.
>   * The miptree has the following properties:
> diff --git a/src/mesa/drivers/dri/i965/intel_screen.c b/src/mesa/drivers/dri/i965/intel_screen.c
> index 0bd0789..b975142 100644
> --- a/src/mesa/drivers/dri/i965/intel_screen.c
> +++ b/src/mesa/drivers/dri/i965/intel_screen.c
> @@ -1225,7 +1225,8 @@ __DRIconfig **intelInitScreen2(__DRIscreen *psp)
>  {
>     struct intel_screen *intelScreen;
>  
> -   if (psp->dri2.loader->base.version <= 2 ||
> +   if (psp->dri3.loader) {
> +   } else if (psp->dri2.loader->base.version <= 2 ||
>         psp->dri2.loader->getBuffersWithFormat == NULL) {
>        fprintf(stderr,
>  	      "\nERROR!  DRI2 loader with getBuffersWithFormat() "
> @@ -1313,6 +1314,109 @@ intelReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer)
>     free(intelBuffer);
>  }
>  
> +/*
> + * DRI3 bits
> + */
> +
> +static __DRIdri3Buffer *
> +intel_dri3_allocate_buffer(__DRIscreen *screen,
> +                           unsigned int format,
> +                           int width,
> +                           int height)
> +{
> +   struct intel_screen *intel_screen = screen->driverPrivate;
> +   __DRIdri3Buffer *buffer;
> +   struct intel_region *region;
> +
> +   buffer = calloc(1, sizeof *buffer);
> +   if (buffer == NULL)
> +      return NULL;
> +
> +   /* The front and back buffers are color buffers, which are X tiled. */
> +   region = intel_region_alloc(intel_screen,
> +                               I915_TILING_X,
> +                               _mesa_get_format_bytes(format),
> +                               width,
> +                               height,
> +                               true);
> +   
> +   if (region == NULL) {
> +	   free(buffer);
> +	   return NULL;
> +   }
> +   
> +   buffer->cpp = region->cpp;
> +   buffer->pitch = region->pitch;
> +   buffer->size = region->bo->size;
> +   buffer->width = width;
> +   buffer->height = height;
> +   buffer->driverPrivate = region;
> +
> +   return buffer;
> +}
> +
> +static void
> +intel_dri3_release_buffer(__DRIscreen *screen,
> +                          __DRIdri3Buffer *buffer)
> +{
> +   intel_region_release((struct intel_region **) &buffer->driverPrivate);
> +   free(buffer);
> +}
> +
> +static int
> +intel_dri3_buffer_to_fd(__DRIscreen *screen,
> +                        __DRIdri3Buffer *buffer)
> +{
> +   struct intel_screen *intel_screen = screen->driverPrivate;
> +   struct intel_region *region = buffer->driverPrivate;
> +
> +   if (!region)
> +      return -1;
> +   return intel_fd_for_region(intel_screen, region);
> +}
> +
> +static __DRIdri3Buffer *
> +intel_dri3_fd_to_buffer(__DRIscreen *screen,
> +                        int fd,
> +                        unsigned int format,
> +                        int width,
> +                        int height,
> +                        int pitch,
> +                        unsigned int size)
> +{
> +   struct intel_screen *intel_screen = screen->driverPrivate;
> +   struct intel_region *region;
> +   __DRIdri3Buffer *buffer;
> +
> +   buffer = calloc(1, sizeof *buffer);
> +   if (!buffer)
> +      return NULL;
> +   
> +   region = intel_region_alloc_for_fd(intel_screen,
> +                                      _mesa_get_format_bytes(format),
> +                                      width, height, pitch, size,
> +                                      fd, "buffer");
> +   if (region == NULL) {
> +      free (buffer);
> +      return NULL;
> +   }
> +
> +   buffer->cpp = region->cpp;
> +   buffer->pitch = region->pitch;
> +   buffer->width = width;
> +   buffer->height = height;
> +   buffer->driverPrivate = region;
> +
> +   return buffer;
> +}
> +
> +const struct __dri3DriverAPIRec dri3DriverAPI = {
> +   .allocate_buffer     = intel_dri3_allocate_buffer,
> +   .release_buffer      = intel_dri3_release_buffer,
> +   .buffer_to_fd        = intel_dri3_buffer_to_fd,
> +   .fd_to_buffer        = intel_dri3_fd_to_buffer,
> +   .stamp               = dri3DrawableStamp,
> +};
>  
>  static const struct __DriverAPIRec brw_driver_api = {
>     .InitScreen		 = intelInitScreen2,
> @@ -1334,6 +1438,7 @@ static const struct __DRIDriverVtableExtensionRec brw_vtable = {
>  
>  static const __DRIextension *brw_driver_extensions[] = {
>      &driCoreExtension.base,
> +    &driDRI3Extension.base,
>      &driDRI2Extension.base,
>      &brw_vtable.base,
>      &brw_config_options.base,
> -- 
> 1.8.4.2
> 
> 
> ------------------------------------------------------------------------------
> Android is increasing in popularity, but the open development platform that
> developers love is also attractive to malware creators. Download this white
> paper to learn more about secure code signing practices that can help keep
> Android apps secure.
> http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk
> --
> _______________________________________________
> Dri-devel mailing list
> Dri-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/dri-devel
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the mesa-dev mailing list