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;
+};
+
+#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);
+
+    /**
+     * 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;
+
+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);
+
+typedef void
+(*__DRIdri3ReleaseBuffer)(__DRIscreen *screen,
+                          __DRIdri3Buffer *buffer);
+
+typedef int
+(*__DRIdri3BufferToFd)(__DRIscreen *screen,
+                       __DRIdri3Buffer *buffer);
+
+typedef __DRIdri3Buffer *
+(*__DRIdri3FdToBuffer)(__DRIscreen *screen,
+                       int fd, unsigned int bpp,
+                       int width, int height, int stride,
+                       unsigned int size);
+
+typedef uint32_t *
+(*__DRIdri3Stamp)(__DRIdrawable *drawable);
+
+#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@bitplanet.net>
+ *    Benjamin Franzke <benjaminfranzke@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@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@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,
