[PATCH 8/8] Add DRI3+Present loader

Keith Packard keithp at keithp.com
Mon Nov 4 18:23:28 PST 2013


Uses the __DRIimage loader interfaces.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 configure.ac          |   12 +-
 src/glx/Makefile.am   |    2 +
 src/glx/dri3_common.c |  146 +++++
 src/glx/dri3_glx.c    | 1722 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/glx/dri3_priv.h   |  199 ++++++
 src/glx/glxclient.h   |    2 +
 src/glx/glxext.c      |    6 +-
 7 files changed, 2085 insertions(+), 4 deletions(-)
 create mode 100644 src/glx/dri3_common.c
 create mode 100644 src/glx/dri3_glx.c
 create mode 100644 src/glx/dri3_priv.h

diff --git a/configure.ac b/configure.ac
index 0a25047..074368c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,6 +38,9 @@ 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
+PRESENTPROTO_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 +823,13 @@ 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([PRESENTPROTO], [presentproto >= $PRESENTPROTO_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-present xcb-sync xshmfence"
 
     # add xf86vidmode if available
     PKG_CHECK_MODULES([XF86VIDMODE], [xxf86vm], HAVE_XF86VIDMODE=yes, HAVE_XF86VIDMODE=no)
@@ -833,8 +839,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/src/glx/Makefile.am b/src/glx/Makefile.am
index f01709b..854025d 100644
--- a/src/glx/Makefile.am
+++ b/src/glx/Makefile.am
@@ -92,6 +92,8 @@ libglx_la_SOURCES = \
 	  glxhash.c \
 	  dri2_glx.c \
 	  dri2.c \
+          dri3_glx.c \
+          dri3_common.c \
 	  applegl_glx.c
 
 GL_LIBS = \
diff --git a/src/glx/dri3_common.c b/src/glx/dri3_common.c
new file mode 100644
index 0000000..c758f96
--- /dev/null
+++ b/src/glx/dri3_common.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * This code is derived from src/egl/drivers/dri2/common.c which
+ * carries the following copyright:
+ * 
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Kristian Høgsberg <krh at bitplanet.net>
+ *    Benjamin Franzke <benjaminfranzke at googlemail.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <GL/gl.h>
+#include "glapi.h"
+#include "glxclient.h"
+#include "xf86dri.h"
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "xf86drm.h"
+#include "dri_common.h"
+#include "dri3_priv.h"
+
+#define DRIVER_MAP_DRI3_ONLY
+#include "pci_ids/pci_id_driver_map.h"
+
+#include <libudev.h>
+
+static struct udev_device *
+dri3_udev_device_new_from_fd(struct udev *udev, int fd)
+{
+   struct udev_device *device;
+   struct stat buf;
+
+   if (fstat(fd, &buf) < 0) {
+      ErrorMessageF("DRI3: failed to stat fd %d", fd);
+      return NULL;
+   }
+
+   device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev);
+   if (device == NULL) {
+      ErrorMessageF("DRI3: could not create udev device for fd %d", fd);
+      return NULL;
+   }
+
+   return device;
+}
+
+char *
+dri3_get_driver_for_fd(int fd)
+{
+   struct udev *udev;
+   struct udev_device *device, *parent;
+   const char *pci_id;
+   char *driver = NULL;
+   int vendor_id, chip_id, i, j;
+
+   udev = udev_new();
+   device = dri3_udev_device_new_from_fd(udev, fd);
+   if (device == NULL)
+      return NULL;
+
+   parent = udev_device_get_parent(device);
+   if (parent == NULL) {
+      ErrorMessageF("DRI3: could not get parent device");
+      goto out;
+   }
+
+   pci_id = udev_device_get_property_value(parent, "PCI_ID");
+   if (pci_id == NULL ||
+       sscanf(pci_id, "%x:%x", &vendor_id, &chip_id) != 2) {
+      ErrorMessageF("DRI3: malformed or no PCI ID");
+      goto out;
+   }
+
+   for (i = 0; driver_map[i].driver; i++) {
+      if (vendor_id != driver_map[i].vendor_id)
+         continue;
+      if (driver_map[i].num_chips_ids == -1) {
+         driver = strdup(driver_map[i].driver);
+         goto out;
+      }
+
+      for (j = 0; j < driver_map[i].num_chips_ids; j++)
+         if (driver_map[i].chip_ids[j] == chip_id) {
+            driver = strdup(driver_map[i].driver);
+            goto out;
+         }
+   }
+
+out:
+   udev_device_unref(device);
+   udev_unref(udev);
+
+   return driver;
+}
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
new file mode 100644
index 0000000..4021baa
--- /dev/null
+++ b/src/glx/dri3_glx.c
@@ -0,0 +1,1722 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * Portions of this code were adapted from dri2_glx.c which carries the
+ * following copyright:
+ *
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ *   Kristian Høgsberg (krh at redhat.com)
+ */
+
+#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xfixes.h>
+#include <X11/Xlib-xcb.h>
+#include <X11/xshmfence.h>
+#include <xcb/xcb.h>
+#include <xcb/dri3.h>
+#include <xcb/present.h>
+#include <GL/gl.h>
+#include "glapi.h"
+#include "glxclient.h"
+#include "xf86dri.h"
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "xf86drm.h"
+#include "dri_common.h"
+#include "dri3_priv.h"
+
+static const struct glx_context_vtable dri3_context_vtable;
+
+static inline void
+dri3_fence_reset(xcb_connection_t *c, struct dri3_buffer *buffer) {
+   xshmfence_reset(buffer->shm_fence);
+}
+
+static inline void
+dri3_fence_set(struct dri3_buffer *buffer) {
+   xshmfence_trigger(buffer->shm_fence);
+}
+
+static inline void
+dri3_fence_trigger(xcb_connection_t *c, struct dri3_buffer *buffer) {
+   xcb_sync_trigger_fence(c, buffer->sync_fence);
+}
+
+static inline void
+dri3_fence_await(xcb_connection_t *c, struct dri3_buffer *buffer) {
+   xcb_flush(c);
+   xshmfence_await(buffer->shm_fence);
+}
+
+static inline Bool
+dri3_fence_triggered(struct dri3_buffer *buffer) {
+   return xshmfence_query(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->image_driver->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->image_driver->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->image_driver->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;
+}
+
+static void
+present_handle_special_event(struct dri3_drawable *priv, xcb_present_generic_event_t *ge)
+{
+   switch (ge->evtype) {
+   case XCB_PRESENT_CONFIGURE_NOTIFY: {
+      xcb_present_configure_notify_event_t *ce = (void *) ge;
+
+      priv->width = ce->width;
+      priv->height = ce->height;
+      break;
+   }
+   case XCB_PRESENT_COMPLETE_NOTIFY: {
+      xcb_present_complete_notify_event_t *ce = (void *) ge;
+
+      if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP)
+         priv->present_event_serial = ce->serial;
+      else
+         priv->present_msc_event_serial = ce->serial;
+      priv->ust = ce->ust;
+      priv->msc = ce->msc;
+      break;
+   }
+   case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
+      xcb_present_idle_notify_event_t *ie = (void *) ge;
+      int b;
+
+      for (b = 0; b < sizeof (priv->buffers) / sizeof (priv->buffers[0]); b++) {
+         struct dri3_buffer        *buf = priv->buffers[b];
+
+         if (buf && buf->pixmap == ie->pixmap) {
+            buf->busy = 0;
+            break;
+         }
+      }
+      break;
+   }
+   }
+   free(ge);
+}
+
+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);
+   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+   xcb_generic_event_t *ev;
+   xcb_present_generic_event_t *ge;
+
+   /* Ask for the an event for the target MSC */
+   ++priv->present_msc_request_serial;
+   xcb_present_notify_msc(c,
+                          priv->base.xDrawable,
+                          priv->present_msc_request_serial,
+                          target_msc,
+                          divisor,
+                          remainder);
+
+   xcb_flush(c);
+
+   /* Wait for the event */
+   if (priv->special_event) {
+      while (priv->present_msc_request_serial != priv->present_msc_event_serial) {
+         ev = xcb_wait_for_special_event(c, priv->special_event);
+         if (!ev)
+            break;
+         ge = (void *) ev;
+         present_handle_special_event(priv, ge);
+      }
+   }
+
+   *ust = priv->ust;
+   *msc = priv->msc;
+
+   *sbc = priv->sbc;
+
+   return 1;
+}
+
+static int
+dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
+                      int64_t *ust, int64_t *msc, int64_t *sbc)
+{
+   return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc,sbc);
+}
+
+static int
+dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
+                  int64_t *msc, int64_t *sbc)
+{
+   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+
+   while (priv->sbc < target_sbc) {
+      sleep(1);
+   }
+   return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc, 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 struct dri3_buffer *
+dri3_back_buffer(struct dri3_drawable *priv)
+{
+   return priv->buffers[DRI3_BACK_ID(priv->cur_back)];
+}
+
+static struct dri3_buffer *
+dri3_fake_front_buffer(struct dri3_drawable *priv)
+{
+   return priv->buffers[DRI3_FRONT_ID];
+}
+
+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();
+   struct dri3_buffer *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 struct dri3_buffer *
+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;
+   struct dri3_buffer *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;
+   int stride;
+
+   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 = calloc(1, sizeof (struct dri3_buffer));
+   if (!buffer)
+      goto no_buffer;
+
+   buffer->image = (*psc->image->createImage) (psc->driScreen,
+                                               width, height,
+                                               format,
+                                               __DRI_IMAGE_USE_SHARE|__DRI_IMAGE_USE_SCANOUT,
+                                               buffer);
+
+   
+   if (!buffer->image)
+      goto no_image;
+
+   if (!(*psc->image->queryImage)(buffer->image, __DRI_IMAGE_ATTRIB_STRIDE, &stride))
+      goto no_buffer_attrib;
+
+   buffer->pitch = stride;
+
+   if (!(*psc->image->queryImage)(buffer->image, __DRI_IMAGE_ATTRIB_FD, &buffer_fd))
+      goto no_buffer_attrib;
+
+   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;
+
+   /* Mark the buffer as idle */
+   dri3_fence_set(buffer);
+
+   return buffer;
+   
+no_buffer_attrib:
+   (*psc->image->destroyImage)(buffer->image);
+no_image:
+   free(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, struct dri3_buffer *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->image->destroyImage)(buffer->image);
+   free(buffer);
+}
+
+
+
+static void
+present_flush_events(struct dri3_drawable *priv)
+{
+   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
+
+   /* 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 *ge = (void *) ev;
+         present_handle_special_event(priv, ge);
+      }
+   }
+}
+
+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;
+      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_COMPLETE_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;
+      }
+
+      priv->special_event = xcb_register_for_special_event(c,
+                                                           priv->present_extension->major_opcode,
+                                                           priv->eid,
+                                                           priv->stamp);
+
+      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;
+      }
+   }
+   present_flush_events(priv);
+   return true;
+}
+   
+static int
+image_format_to_fourcc(int format)
+{
+
+   /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
+   switch (format) {
+   case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;
+   case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;
+   case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;
+   case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;
+   case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;
+//   case __DRI_IMAGE_FORMAT_R8: return __DRI_IMAGE_FOURCC_R8;
+//   case __DRI_IMAGE_FORMAT_GR88: return __DRI_IMAGE_FOURCC_GR88;
+//   case __DRI_IMAGE_FORMAT_NONE: return __DRI_IMAGE_FOURCC_NONE;
+//   case __DRI_IMAGE_FORMAT_XRGB2101010: return __DRI_IMAGE_FOURCC_XRGB2101010;
+//   case __DRI_IMAGE_FORMAT_ARGB2101010: return __DRI_IMAGE_FOURCC_ARGB2101010;
+   }
+   return 0;
+}
+
+static struct dri3_buffer *
+dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,
+                       unsigned int format,
+                       enum dri3_buffer_type buffer_type,
+                       void *loaderPrivate)
+{
+   struct dri3_drawable                 *pdraw = loaderPrivate;
+   int                                  buf_id = buffer_type == dri3_pixmap_buf_id(buffer_type);
+   struct dri3_buffer                   *buffer = pdraw->buffers[buf_id];
+   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;
+   __DRIimage                           *image_planar;
+   int                                  stride, offset;
+
+   if (buffer)
+      return buffer;
+
+   pixmap = pdraw->base.xDrawable;
+   psc = (struct dri3_screen *) pdraw->base.psc;
+   dpy = psc->base.dpy;
+   c = XGetXCBConnection(dpy);
+
+   buffer = calloc(1, sizeof (struct dri3_buffer));
+   if (!buffer)
+      goto no_buffer;
+
+   fence_fd = xshmfence_alloc_shm();
+   if (fence_fd < 0)
+      goto no_fence;
+   shm_fence = xshmfence_map_shm(fence_fd);
+   if (shm_fence == NULL) {
+      close (fence_fd);
+      goto no_fence;
+   }
+
+   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_image;
+   fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply);
+   buffer_fd = fds[0];
+
+   stride = bp_reply->stride;
+   offset = 0;
+
+   image_planar = (*psc->image->createImageFromFds) (psc->driScreen,
+                                                     bp_reply->width,
+                                                     bp_reply->height,
+                                                     image_format_to_fourcc(format),
+                                                     fds, 1,
+                                                     &stride, &offset, buffer);
+   close(buffer_fd);
+   if (!image_planar)
+      goto no_image;
+
+   buffer->image = (*psc->image->fromPlanar)(image_planar, 0, buffer);
+
+   (*psc->image->destroyImage)(image_planar);
+
+   if (!buffer->image)
+      goto no_image;
+
+   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[buf_id] = buffer;
+   return buffer;
+
+no_image:
+   xcb_sync_destroy_fence(c, sync_fence);
+   xshmfence_unmap_shm(shm_fence);
+no_fence:
+   free(buffer);
+no_buffer:
+   return NULL;
+}
+
+static int
+dri3_find_back(xcb_connection_t *c, struct dri3_drawable *priv)
+{
+   int  b;
+   xcb_generic_event_t *ev;
+   xcb_present_generic_event_t *ge;
+
+   for (;;) {
+
+      for (b = 0; b < DRI3_MAX_BACK; b++) {
+         int                    id = DRI3_BACK_ID(b);
+         struct dri3_buffer        *buffer = priv->buffers[id];
+
+         if (!buffer)
+            return b;
+         if (!buffer->busy)
+            return b;
+      }
+      ev = xcb_wait_for_special_event(c, priv->special_event);
+      if (!ev)
+         return -1;
+      ge = (void *) ev;
+      present_handle_special_event(priv, ge);
+   } 
+}
+
+static struct dri3_buffer *
+dri3_get_buffer(__DRIdrawable *driDrawable,
+                unsigned int format,
+                enum dri3_buffer_type buffer_type,
+                void *loaderPrivate)
+{
+   struct dri3_drawable *priv = loaderPrivate;
+   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
+   struct dri3_buffer      *buffer;
+   int                  buf_id;
+
+   if (buffer_type == dri3_buffer_back) {
+      int back = dri3_find_back(c, priv);
+
+      if (back < 0)
+         return NULL;
+
+      priv->cur_back = back;
+      buf_id = DRI3_BACK_ID(priv->cur_back);
+   } else {
+      buf_id = DRI3_FRONT_ID;
+   }
+
+   buffer = priv->buffers[buf_id];
+   if (!buffer || buffer->width != priv->width || buffer->height != priv->height) {
+      struct dri3_buffer   *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);
+         }
+         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);
+         break;
+      }
+      buffer = new_buffer;
+      buffer->buffer_type = buffer_type;
+      priv->buffers[buf_id] = buffer;
+   } 
+   dri3_fence_await(c, buffer);
+
+   /* Return the requested buffer */
+   return buffer;
+}
+
+static void
+dri3_free_buffers(__DRIdrawable *driDrawable,
+                 enum dri3_buffer_type buffer_type,
+                 void *loaderPrivate)
+{
+   struct dri3_drawable *priv = loaderPrivate;
+   struct dri3_buffer      *buffer;
+   int                  first_id;
+   int                  n_id;
+   int                  buf_id;
+   
+   switch (buffer_type) {
+   case dri3_buffer_back:
+      first_id = DRI3_BACK_ID(0);
+      n_id = DRI3_MAX_BACK;
+      break;
+   case dri3_buffer_front:
+      first_id = DRI3_FRONT_ID;
+      n_id = 1;
+   }
+
+   for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) {
+      buffer = priv->buffers[buf_id];
+      if (buffer) {
+         dri3_free_render_buffer(priv, buffer);
+         priv->buffers[buf_id] = NULL;
+      }
+   }
+}
+
+static int
+dri3_get_buffers(__DRIdrawable *driDrawable,
+                 int *width, int *height,
+                 unsigned int format,
+                 uint32_t *stamp,
+                 void *loaderPrivate,
+                 uint32_t buffer_mask,
+                 struct __DRIimageList *buffers)
+{
+   struct dri3_drawable *priv = loaderPrivate;
+   struct dri3_buffer   *front, *back;
+
+   buffers->front = NULL;
+   buffers->back = NULL;
+
+   front = NULL;
+   back = NULL;
+
+   if (!dri3_update_drawable(driDrawable, loaderPrivate))
+      return false;
+
+   if (priv->is_pixmap)
+      buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
+
+   if (buffer_mask & __DRI_IMAGE_BUFFER_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_buffers(driDrawable, dri3_buffer_front, loaderPrivate);
+      priv->have_fake_front = 0;
+   }
+
+   if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
+      back = dri3_get_buffer(driDrawable,
+                             format,
+                             dri3_buffer_back,
+                             loaderPrivate);
+      if (!back)
+         return false;
+      priv->have_back = 1;
+   } else {
+      dri3_free_buffers(driDrawable, dri3_buffer_back, loaderPrivate);
+      priv->have_back = 0;
+   }
+
+   if (front)
+      buffers->front = front->image;
+   
+   if (back)
+      buffers->back = back->image;
+
+   priv->stamp = stamp;
+
+   /* 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;
+   Display *dpy = priv->base.psc->dpy;
+   xcb_connection_t *c = XGetXCBConnection(dpy);
+   int buf_id = DRI3_BACK_ID(priv->cur_back);
+   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);
+    
+   present_flush_events(priv);
+
+   if (priv->buffers[buf_id] && !priv->is_pixmap) {
+      dri3_fence_reset(c, priv->buffers[buf_id]);
+
+      /* Compute when we want the frame shown by taking the last known successful
+       * MSC and adding in a swap interval for each outstanding swap request
+       */
+      ++priv->present_request_serial;
+      if (target_msc == 0)
+         target_msc = priv->msc + priv->swap_interval * (priv->present_request_serial - priv->present_event_serial);
+
+      priv->buffers[buf_id]->busy = 1;
+      xcb_present_pixmap(c,
+                         priv->base.xDrawable,
+                         priv->buffers[buf_id]->pixmap,
+                         priv->present_request_serial,
+                         0,                                    /* valid */
+                         0,                                    /* update */
+                         0,                                    /* x_off */
+                         0,                                    /* y_off */
+                         None,                                 /* target_crtc */
+                         None,
+                         priv->buffers[buf_id]->sync_fence,
+                         XCB_PRESENT_OPTION_NONE,
+                         target_msc,
+                         divisor,
+                         remainder, 0, NULL);
+      ret = ++priv->sbc;
+      if (priv->have_fake_front) {
+         dri3_fence_reset(c, priv->buffers[DRI3_FRONT_ID]);
+         dri3_copy_area(c,
+                        priv->buffers[buf_id]->pixmap,
+                        priv->buffers[DRI3_FRONT_ID]->pixmap,
+                        dri3_drawable_gc(priv),
+                        0, 0, 0, 0, priv->width, priv->height);
+         dri3_fence_trigger(c, priv->buffers[DRI3_FRONT_ID]);
+      }
+      xcb_flush(c);
+      if (priv->stamp)
+         ++(*priv->stamp);
+   }
+
+   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
+present_query_version(Display *dpy, int *major, int *minor)
+{
+   xcb_present_query_version_cookie_t   cookie;
+   xcb_present_query_version_reply_t    *reply;       
+   xcb_connection_t                     *c = XGetXCBConnection(dpy);
+   xcb_generic_error_t                  *error;
+
+   cookie = xcb_present_query_version(c,
+                                   XCB_PRESENT_MAJOR_VERSION,
+                                   XCB_PRESENT_MINOR_VERSION);
+   reply = xcb_present_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);
+}
+
+static int
+dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
+{
+   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;
+   }
+
+   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;
+}
+
+static const __DRIimageLoaderExtension imageLoaderExtension = {
+   {__DRI_IMAGE_LOADER, __DRI_IMAGE_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->image_driver->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_IMAGE_DRIVER) == 0)
+	 psc->image_driver = (__DRIimageDriverExtension *) extensions[i];
+   }
+
+
+   if (psc->core == NULL) {
+      ErrorMessageF("core dri driver extension not found\n");
+      goto handle_error;
+   }
+
+   if (psc->image_driver == NULL) {
+      ErrorMessageF("image driver extension not found\n");
+      goto handle_error;
+   }
+
+   psc->driScreen =
+      psc->image_driver->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;
+   }
+
+   extensions = (*psc->core->getExtensions)(psc->driScreen);
+
+   for (i = 0; extensions[i]; i++) {
+      if (strcmp(extensions[i]->name, __DRI_IMAGE) == 0)
+         psc->image = (__DRIimageExtension *) extensions[i];
+   }
+
+   if (psc->image == NULL) {
+      ErrorMessageF("image extension not found\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 = dri3_drawable_get_msc;
+   psp->waitForMSC = dri3_wait_for_msc;
+   psp->waitForSBC = dri3_wait_for_sbc;
+   psp->setSwapInterval = dri3_set_swap_interval;
+   psp->getSwapInterval = dri3_get_swap_interval;
+   __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
+
+   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))
+      goto no_extension;
+
+   if (!present_query_version(dpy, &pdp->presentMajor, &pdp->presentMinor))
+      goto no_extension;
+
+   pdp->base.destroyDisplay = dri3_destroy_display;
+   pdp->base.createScreen = dri3_create_screen;
+
+   i = 0;
+
+   pdp->loader_extensions[i++] = &imageLoaderExtension.base;
+   
+   pdp->loader_extensions[i++] = &systemTimeExtension.base;
+
+   pdp->loader_extensions[i++] = NULL;
+
+   return &pdp->base;
+no_extension:
+   free(pdp);
+   return NULL;
+}
+
+#endif /* GLX_DIRECT_RENDERING */
diff --git a/src/glx/dri3_priv.h b/src/glx/dri3_priv.h
new file mode 100644
index 0000000..2873919
--- /dev/null
+++ b/src/glx/dri3_priv.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/* This file was derived from dri2_priv.h which carries the following
+ * copyright:
+ *
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ *   Kristian Høgsberg (krh at redhat.com)
+ */
+
+#include <xcb/xcb.h>
+#include <xcb/dri3.h>
+#include <xcb/present.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
+
+enum dri3_buffer_type {
+   dri3_buffer_back = 0,
+   dri3_buffer_front = 1
+};
+
+struct dri3_buffer {
+   __DRIimage   *image;
+   uint32_t     pixmap;
+   uint32_t     sync_fence;
+   int32_t      *shm_fence;
+   GLboolean    busy;
+   void         *driverPrivate;
+
+   uint32_t     size;
+   uint32_t     pitch;
+   uint32_t     cpp;
+   uint32_t     flags;
+   uint32_t     width, height;
+
+   enum dri3_buffer_type        buffer_type;
+};
+
+struct dri3_display
+{
+   __GLXDRIdisplay base;
+
+   const __DRIextension *loader_extensions[8];
+
+   /* DRI3 bits */
+   int dri3Major;
+   int dri3Minor;
+
+   /* Present bits */
+   int hasPresent;
+   int presentMajor;
+   int presentMinor;
+};
+
+struct dri3_screen {
+   struct glx_screen base;
+
+   __DRIscreen *driScreen;
+   __GLXDRIscreen vtable;
+
+   const __DRIimageExtension *image;
+   const __DRIimageDriverExtension *image_driver;
+   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;
+};
+
+#define DRI3_MAX_BACK   2
+#define DRI3_BACK_ID(i) (i)
+#define DRI3_FRONT_ID   (DRI3_MAX_BACK)
+
+static inline int
+dri3_buf_id_next(int buf_id)
+{
+   if (buf_id == DRI3_MAX_BACK - 1)
+      return 0;
+   return buf_id + 1;
+}
+
+static inline int
+dri3_buf_id_prev(int buf_id)
+{
+   if (buf_id == 0)
+      return DRI3_MAX_BACK - 1;
+   return buf_id - 1;
+}
+
+static inline int
+dri3_pixmap_buf_id(enum dri3_buffer_type buffer_type)
+{
+   if (buffer_type == dri3_buffer_back)
+      return DRI3_BACK_ID(0);
+   else
+      return DRI3_FRONT_ID;
+}
+
+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;
+
+   uint32_t present_request_serial;
+   uint32_t present_event_serial;
+
+   uint64_t sbc;
+
+   uint64_t ust, msc;
+
+   /* For WaitMSC */
+   uint32_t     present_msc_request_serial;
+   uint32_t     present_msc_event_serial;
+   
+   uint64_t previous_time;
+   unsigned frames;
+
+   struct dri3_buffer *buffers[1 + DRI3_MAX_BACK];
+   int cur_back;
+   int depth;
+
+   uint32_t *stamp;
+
+   xcb_present_event_t eid;
+   xcb_gcontext_t gc;
+   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);
    }
-- 
1.8.4.2



More information about the dri-devel mailing list