<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">2015-07-01 23:31 GMT+08:00 Boyan Ding <span dir="ltr"><<a href="mailto:boyan.j.ding@gmail.com" target="_blank">boyan.j.ding@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Signed-off-by: Boyan Ding <<a href="mailto:boyan.j.ding@gmail.com">boyan.j.ding@gmail.com</a>><br>
---<br>
 <a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a>                             |    3 +<br>
 src/egl/drivers/dri2/Makefile.am         |    5 +<br>
 src/egl/drivers/dri2/egl_dri2.c          |   65 +-<br>
 src/egl/drivers/dri2/egl_dri2.h          |   12 +-<br>
 src/egl/drivers/dri2/platform_x11.c      |  127 ++-<br>
 src/egl/drivers/dri2/platform_x11_dri3.c | 1591 ++++++++++++++++++++++++++++++<br>
 src/egl/drivers/dri2/platform_x11_dri3.h |  140 +++<br>
 7 files changed, 1926 insertions(+), 17 deletions(-)<br>
 create mode 100644 src/egl/drivers/dri2/platform_x11_dri3.c<br>
 create mode 100644 src/egl/drivers/dri2/platform_x11_dri3.h<br>
<br>
diff --git a/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a> b/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
index af61aa2..090e6c9 100644<br>
--- a/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
+++ b/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
@@ -1545,6 +1545,9 @@ if test "x$enable_egl" = xyes; then<br>
             if test "x$enable_shared_glapi" = xno; then<br>
                 AC_MSG_ERROR([egl_dri2 requires --enable-shared-glapi])<br>
             fi<br>
+            if test "x$enable_dri3" = xyes; then<br>
+                EGL_LIB_DEPS="$EGL_LIB_DEPS -lxcb-dri3 -lxcb-present -lXxf86vm -lxshmfence -lxcb-sync"<br>
+            fi<br>
         else<br>
             # Avoid building an "empty" libEGL. Drop/update this<br>
             # when other backends (haiku?) come along.<br>
diff --git a/src/egl/drivers/dri2/Makefile.am b/src/egl/drivers/dri2/Makefile.am<br>
index 55be4a7..d5b511c 100644<br>
--- a/src/egl/drivers/dri2/Makefile.am<br>
+++ b/src/egl/drivers/dri2/Makefile.am<br>
@@ -52,6 +52,11 @@ if HAVE_EGL_PLATFORM_X11<br>
 libegl_dri2_la_SOURCES += platform_x11.c<br>
 AM_CFLAGS += -DHAVE_X11_PLATFORM<br>
 AM_CFLAGS += $(XCB_DRI2_CFLAGS)<br>
+if HAVE_DRI3<br>
+libegl_dri2_la_SOURCES += \<br>
+       platform_x11_dri3.c \<br>
+       platform_x11_dri3.h<br>
+endif<br>
 endif<br>
<br>
 if HAVE_EGL_PLATFORM_WAYLAND<br>
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c<br>
index b1b65f7..052c579 100644<br>
--- a/src/egl/drivers/dri2/egl_dri2.c<br>
+++ b/src/egl/drivers/dri2/egl_dri2.c<br>
@@ -322,6 +322,12 @@ struct dri2_extension_match {<br>
    int offset;<br>
 };<br>
<br>
+static struct dri2_extension_match dri3_driver_extensions[] = {<br>
+   { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },<br>
+   { __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) },<br>
+   { NULL, 0, 0 }<br>
+};<br>
+<br>
 static struct dri2_extension_match dri2_driver_extensions[] = {<br>
    { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },<br>
    { __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) },<br>
@@ -464,6 +470,24 @@ dri2_open_driver(_EGLDisplay *disp)<br>
 }<br>
<br>
 EGLBoolean<br>
+dri2_load_driver_dri3(_EGLDisplay *disp)<br>
+{<br>
+   struct dri2_egl_display *dri2_dpy = disp->DriverData;<br>
+   const __DRIextension **extensions;<br>
+<br>
+   extensions = dri2_open_driver(disp);<br>
+   if (!extensions)<br>
+      return EGL_FALSE;<br>
+<br>
+   if (!dri2_bind_extensions(dri2_dpy, dri3_driver_extensions, extensions)) {<br>
+      dlclose(dri2_dpy->driver);<br></blockquote><div><br></div><div>I missed a return EGL_FALSE here. Have been fixed locally.</div><div><br></div><div>Boyan Ding</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+   }<br>
+   dri2_dpy->driver_extensions = extensions;<br>
+<br>
+   return EGL_TRUE;<br>
+}<br>
+<br>
+EGLBoolean<br>
 dri2_load_driver(_EGLDisplay *disp)<br>
 {<br>
    struct dri2_egl_display *dri2_dpy = disp->DriverData;<br>
@@ -507,7 +531,9 @@ dri2_setup_screen(_EGLDisplay *disp)<br>
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
    unsigned int api_mask;<br>
<br>
-   if (dri2_dpy->dri2) {<br>
+   if (dri2_dpy->image_driver) {<br>
+      api_mask = dri2_dpy->image_driver->getAPIMask(dri2_dpy->dri_screen);<br>
+   } else if (dri2_dpy->dri2) {<br>
       api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);<br>
    } else {<br>
       assert(dri2_dpy->swrast);<br>
@@ -527,11 +553,12 @@ dri2_setup_screen(_EGLDisplay *disp)<br>
    if (api_mask & (1 << __DRI_API_GLES3))<br>
       disp->ClientAPIs |= EGL_OPENGL_ES3_BIT_KHR;<br>
<br>
-   assert(dri2_dpy->dri2 || dri2_dpy->swrast);<br>
+   assert(dri2_dpy->image_driver || dri2_dpy->dri2 || dri2_dpy->swrast);<br>
    disp->Extensions.KHR_surfaceless_context = EGL_TRUE;<br>
    disp->Extensions.MESA_configless_context = EGL_TRUE;<br>
<br>
-   if ((dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) ||<br>
+   if (dri2_dpy->image_driver ||<br>
+       (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) ||<br>
        (dri2_dpy->swrast && dri2_dpy->swrast->base.version >= 3)) {<br>
       disp->Extensions.KHR_create_context = EGL_TRUE;<br>
<br>
@@ -591,7 +618,14 @@ dri2_create_screen(_EGLDisplay *disp)<br>
<br>
    dri2_dpy = disp->DriverData;<br>
<br>
-   if (dri2_dpy->dri2) {<br>
+   if (dri2_dpy->image_driver) {<br>
+      dri2_dpy->dri_screen =<br>
+         dri2_dpy->image_driver->createNewScreen2(0, dri2_dpy->fd,<br>
+                                                  dri2_dpy->extensions,<br>
+                                                  dri2_dpy->driver_extensions,<br>
+                                                  &dri2_dpy->driver_configs,<br>
+                                                  disp);<br>
+   } else if (dri2_dpy->dri2) {<br>
       if (dri2_dpy->dri2->base.version >= 4) {<br>
          dri2_dpy->dri_screen =<br>
             dri2_dpy->dri2->createNewScreen2(0, dri2_dpy->fd,<br>
@@ -627,7 +661,7 @@ dri2_create_screen(_EGLDisplay *disp)<br>
<br>
    extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);<br>
<br>
-   if (dri2_dpy->dri2) {<br>
+   if (dri2_dpy->image_driver || dri2_dpy->dri2) {<br>
       if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))<br>
          goto cleanup_dri_screen;<br>
    } else {<br>
@@ -971,7 +1005,26 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,<br>
    else<br>
       dri_config = NULL;<br>
<br>
-   if (dri2_dpy->dri2) {<br>
+   if (dri2_dpy->image_driver) {<br>
+      unsigned error;<br>
+      unsigned num_attribs = 8;<br>
+      uint32_t ctx_attribs[8];<br>
+<br>
+      if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs,<br>
+                                        &num_attribs))<br>
+         goto cleanup;<br>
+<br>
+      dri2_ctx->dri_context =<br>
+         dri2_dpy->image_driver->createContextAttribs(dri2_dpy->dri_screen,<br>
+                                                      api,<br>
+                                                      dri_config,<br>
+                                                      shared,<br>
+                                                      num_attribs / 2,<br>
+                                                      ctx_attribs,<br>
+                                                      & error,<br>
+                                                      dri2_ctx);<br>
+      dri2_create_context_attribs_error(error);<br>
+   } else if (dri2_dpy->dri2) {<br>
       if (dri2_dpy->dri2->base.version >= 3) {<br>
          unsigned error;<br>
          unsigned num_attribs = 8;<br>
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h<br>
index f0cc6da..d258753 100644<br>
--- a/src/egl/drivers/dri2/egl_dri2.h<br>
+++ b/src/egl/drivers/dri2/egl_dri2.h<br>
@@ -153,11 +153,16 @@ struct dri2_egl_display<br>
<br>
    int                       dri2_major;<br>
    int                       dri2_minor;<br>
+   int                       dri3_major;<br>
+   int                       dri3_minor;<br>
+   int                       present_major;<br>
+   int                       present_minor;<br>
    __DRIscreen              *dri_screen;<br>
    int                       own_dri_screen;<br>
    const __DRIconfig       **driver_configs;<br>
    void                     *driver;<br>
    const __DRIcoreExtension       *core;<br>
+   const __DRIimageDriverExtension *image_driver;<br>
    const __DRIdri2Extension       *dri2;<br>
    const __DRIswrastExtension     *swrast;<br>
    const __DRI2flushExtension     *flush;<br>
@@ -189,6 +194,7 @@ struct dri2_egl_display<br>
 #ifdef HAVE_X11_PLATFORM<br>
    xcb_connection_t         *conn;<br>
    int                      screen;<br>
+   Display                  *dpy;<br>
 #endif<br>
<br>
 #ifdef HAVE_WAYLAND_PLATFORM<br>
@@ -202,8 +208,9 @@ struct dri2_egl_display<br>
    int                      formats;<br>
    uint32_t                  capabilities;<br>
    int                      is_render_node;<br>
-   int                      is_different_gpu;<br>
 #endif<br>
+<br>
+   int                      is_different_gpu;<br>
 };<br>
<br>
 struct dri2_egl_context<br>
@@ -324,6 +331,9 @@ EGLBoolean<br>
 dri2_load_driver_swrast(_EGLDisplay *disp);<br>
<br>
 EGLBoolean<br>
+dri2_load_driver_dri3(_EGLDisplay *disp);<br>
+<br>
+EGLBoolean<br>
 dri2_create_screen(_EGLDisplay *disp);<br>
<br>
 __DRIimage *<br>
diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c<br>
index ad40bd5..2ce260f 100644<br>
--- a/src/egl/drivers/dri2/platform_x11.c<br>
+++ b/src/egl/drivers/dri2/platform_x11.c<br>
@@ -45,6 +45,10 @@<br>
 #include "egl_dri2_fallbacks.h"<br>
 #include "loader.h"<br>
<br>
+#ifdef HAVE_DRI3<br>
+#include "platform_x11_dri3.h"<br>
+#endif<br>
+<br>
 static EGLBoolean<br>
 dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,<br>
                        EGLint interval);<br>
@@ -1094,13 +1098,17 @@ dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp)<br>
<br>
    disp->DriverData = (void *) dri2_dpy;<br>
    if (disp->PlatformDisplay == NULL) {<br>
-      dri2_dpy->conn = xcb_connect(0, &dri2_dpy->screen);<br>
+      dri2_dpy->dpy = XOpenDisplay(NULL);<br>
+<br>
+      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
+<br>
       dri2_dpy->own_device = true;<br>
    } else {<br>
-      Display *dpy = disp->PlatformDisplay;<br>
+      dri2_dpy->dpy = disp->PlatformDisplay;<br>
<br>
-      dri2_dpy->conn = XGetXCBConnection(dpy);<br>
-      dri2_dpy->screen = DefaultScreen(dpy);<br>
+      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
    }<br>
<br>
    if (xcb_connection_has_error(dri2_dpy->conn)) {<br>
@@ -1202,6 +1210,94 @@ dri2_x11_setup_swap_interval(struct dri2_egl_display *dri2_dpy)<br>
    }<br>
 }<br>
<br>
+#ifdef HAVE_DRI3<br>
+static EGLBoolean<br>
+dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp)<br>
+{<br>
+   struct dri2_egl_display *dri2_dpy;<br>
+<br>
+   dri2_dpy = calloc(1, sizeof *dri2_dpy);<br>
+   if (!dri2_dpy)<br>
+      return _eglError(EGL_BAD_ALLOC, "eglInitialize");<br>
+<br>
+   disp->DriverData = (void *) dri2_dpy;<br>
+   if (disp->PlatformDisplay == NULL) {<br>
+      dri2_dpy->dpy = XOpenDisplay(NULL);<br>
+<br>
+      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
+<br>
+      dri2_dpy->own_device = true;<br>
+   } else {<br>
+      dri2_dpy->dpy = disp->PlatformDisplay;<br>
+<br>
+      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
+   }<br>
+<br>
+   if (xcb_connection_has_error(dri2_dpy->conn)) {<br>
+      _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");<br>
+      goto cleanup_dpy;<br>
+   }<br>
+<br>
+   if (dri2_dpy->conn) {<br>
+      if (!dri3_x11_connect(dri2_dpy))<br>
+        goto cleanup_conn;<br>
+   }<br>
+<br>
+   if (!dri2_load_driver_dri3(disp))<br>
+      goto cleanup_conn;<br>
+<br>
+   dri2_dpy->extensions[0] = &dri3_image_loader_extension.base;<br>
+   dri2_dpy->extensions[1] = &dri3_system_time_extension.base;<br>
+   dri2_dpy->extensions[2] = &use_invalidate.base;<br>
+   dri2_dpy->extensions[3] = &image_lookup_extension.base;<br>
+   dri2_dpy->extensions[4] = NULL;<br>
+<br>
+   dri2_dpy->swap_available = true;<br>
+   dri2_dpy->invalidate_available = true;<br>
+<br>
+   if (!dri2_create_screen(disp))<br>
+      goto cleanup_fd;<br>
+<br>
+   dri2_x11_setup_swap_interval(dri2_dpy);<br>
+<br>
+   disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;<br>
+   disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;<br>
+   disp->Extensions.EXT_buffer_age = EGL_TRUE;<br>
+<br>
+#ifdef HAVE_WAYLAND_PLATFORM<br>
+   disp->Extensions.WL_bind_wayland_display = EGL_TRUE;<br>
+#endif<br>
+<br>
+   if (dri2_dpy->conn) {<br>
+      if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp))<br>
+        goto cleanup_configs;<br>
+   }<br>
+<br>
+   /* Fill vtbl last to prevent accidentally calling virtual function during<br>
+    * initialization.<br>
+    */<br>
+   dri2_dpy->vtbl = &dri3_x11_display_vtbl;<br>
+<br>
+   return EGL_TRUE;<br>
+<br>
+ cleanup_configs:<br>
+   _eglCleanupDisplay(disp);<br>
+   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);<br>
+   dlclose(dri2_dpy->driver);<br>
+ cleanup_fd:<br>
+   close(dri2_dpy->fd);<br>
+ cleanup_conn:<br>
+   if (disp->PlatformDisplay == NULL)<br>
+      xcb_disconnect(dri2_dpy->conn);<br>
+ cleanup_dpy:<br>
+   free(dri2_dpy);<br>
+<br>
+   return EGL_FALSE;<br>
+}<br>
+#endif<br>
+<br>
 static EGLBoolean<br>
 dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)<br>
 {<br>
@@ -1213,13 +1309,17 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)<br>
<br>
    disp->DriverData = (void *) dri2_dpy;<br>
    if (disp->PlatformDisplay == NULL) {<br>
-      dri2_dpy->conn = xcb_connect(0, &dri2_dpy->screen);<br>
+      dri2_dpy->dpy = XOpenDisplay(NULL);<br>
+<br>
+      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
+<br>
       dri2_dpy->own_device = true;<br>
    } else {<br>
-      Display *dpy = disp->PlatformDisplay;<br>
+      dri2_dpy->dpy = disp->PlatformDisplay;<br>
<br>
-      dri2_dpy->conn = XGetXCBConnection(dpy);<br>
-      dri2_dpy->screen = DefaultScreen(dpy);<br>
+      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
    }<br>
<br>
    if (xcb_connection_has_error(dri2_dpy->conn)) {<br>
@@ -1321,9 +1421,16 @@ dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)<br>
    int x11_dri2_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);<br>
<br>
    if (x11_dri2_accel) {<br>
-      if (!dri2_initialize_x11_dri2(drv, disp)) {<br>
-         initialized = dri2_initialize_x11_swrast(drv, disp);<br>
+#ifdef HAVE_DRI3<br>
+      if (getenv("LIBGL_DRI3_ENABLE") == NULL ||<br>
+          !dri2_initialize_x11_dri3(drv, disp)) {<br>
+#endif<br>
+         if (!dri2_initialize_x11_dri2(drv, disp)) {<br>
+            initialized = dri2_initialize_x11_swrast(drv, disp);<br>
+         }<br>
+#ifdef HAVE_DRI3<br>
       }<br>
+#endif<br>
    } else {<br>
       initialized = dri2_initialize_x11_swrast(drv, disp);<br>
    }<br>
diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c<br>
new file mode 100644<br>
index 0000000..dcd7128<br>
--- /dev/null<br>
+++ b/src/egl/drivers/dri2/platform_x11_dri3.c<br>
@@ -0,0 +1,1591 @@<br>
+/*<br>
+ * Copyright © 2013 Keith Packard<br>
+ *<br>
+ * Permission to use, copy, modify, distribute, and sell this software and its<br>
+ * documentation for any purpose is hereby granted without fee, provided that<br>
+ * the above copyright notice appear in all copies and that both that copyright<br>
+ * notice and this permission notice appear in supporting documentation, and<br>
+ * that the name of the copyright holders not be used in advertising or<br>
+ * publicity pertaining to distribution of the software without specific,<br>
+ * written prior permission.  The copyright holders make no representations<br>
+ * about the suitability of this software for any purpose.  It is provided "as<br>
+ * is" without express or implied warranty.<br>
+ *<br>
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,<br>
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO<br>
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR<br>
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,<br>
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER<br>
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE<br>
+ * OF THIS SOFTWARE.<br>
+ */<br>
+<br>
+#include <fcntl.h><br>
+#include <stdbool.h><br>
+#include <stdlib.h><br>
+#include <string.h><br>
+#include <unistd.h><br>
+#include <sys/time.h><br>
+<br>
+#ifdef XF86VIDMODE<br>
+#include <X11/extensions/xf86vmode.h><br>
+#endif<br>
+#include <X11/xshmfence.h><br>
+#include <xcb/xcb.h><br>
+#include <xcb/dri3.h><br>
+#include <xcb/present.h><br>
+#include <xf86drm.h><br>
+<br>
+#include "egl_dri2.h"<br>
+#include "egl_dri2_fallbacks.h"<br>
+#include "platform_x11_dri3.h"<br>
+<br>
+#include "loader.h"<br>
+<br>
+static inline void<br>
+dri3_fence_reset(xcb_connection_t *c, struct dri3_buffer *buffer)<br>
+{<br>
+   xshmfence_reset(buffer->shm_fence);<br>
+}<br>
+<br>
+static inline void<br>
+dri3_fence_set(struct dri3_buffer *buffer)<br>
+{<br>
+   xshmfence_trigger(buffer->shm_fence);<br>
+}<br>
+<br>
+static inline void<br>
+dri3_fence_trigger(xcb_connection_t *c, struct dri3_buffer *buffer)<br>
+{<br>
+   xcb_sync_trigger_fence(c, buffer->sync_fence);<br>
+}<br>
+<br>
+static inline void<br>
+dri3_fence_await(xcb_connection_t *c, struct dri3_buffer *buffer)<br>
+{<br>
+   xcb_flush(c);<br>
+   xshmfence_await(buffer->shm_fence);<br>
+}<br>
+<br>
+static void<br>
+dri3_update_num_back(struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+   dri3_surf->num_back = 1;<br>
+   if (dri3_surf->flipping) {<br>
+      if (!dri3_surf->is_pixmap && !(dri3_surf->present_capabilities & XCB_PRESENT_CAPABILITY_ASYNC))<br>
+         dri3_surf->num_back++;<br>
+      dri3_surf->num_back++;<br>
+   }<br>
+   if (dri3_surf->base.SwapInterval == 0)<br>
+      dri3_surf->num_back++;<br>
+}<br>
+<br>
+/** dri3_free_render_buffer<br>
+ *<br>
+ * Free everything associated with one render buffer including pixmap, fence<br>
+ * stuff and the driver image<br>
+ */<br>
+static void<br>
+dri3_free_render_buffer(struct dri2_egl_display *dri2_dpy,<br>
+                        struct dri3_egl_surface *dri3_surf,<br>
+                        struct dri3_buffer *buffer)<br>
+{<br>
+   if (buffer->own_pixmap)<br>
+      xcb_free_pixmap(dri2_dpy->conn, buffer->pixmap);<br>
+   xcb_sync_destroy_fence(dri2_dpy->conn, buffer->sync_fence);<br>
+   xshmfence_unmap_shm(buffer->shm_fence);<br>
+   (*dri2_dpy->image->destroyImage)(buffer->image);<br>
+   if (buffer->linear_buffer)<br>
+      (*dri2_dpy->image->destroyImage)(buffer->linear_buffer);<br>
+   free(buffer);<br>
+}<br>
+<br>
+static EGLBoolean<br>
+dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)<br>
+{<br>
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
+   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);<br>
+   int i;<br>
+<br>
+   (void) drv;<br>
+<br>
+   if (!_eglPutSurface(surf))<br>
+      return EGL_TRUE;<br>
+<br>
+   (*dri2_dpy->core->destroyDrawable) (dri3_surf->dri_drawable);<br>
+<br>
+   for (i = 0; i < DRI3_NUM_BUFFERS; i++) {<br>
+      if (dri3_surf->buffers[i])<br>
+         dri3_free_render_buffer(dri2_dpy, dri3_surf, dri3_surf->buffers[i]);<br>
+   }<br>
+<br>
+   if (dri3_surf->special_event)<br>
+      xcb_unregister_for_special_event(dri2_dpy->conn, dri3_surf->special_event);<br>
+   free(surf);<br>
+<br>
+   return EGL_TRUE;<br>
+}<br>
+<br>
+static EGLBoolean<br>
+dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,<br>
+                       EGLint interval)<br>
+{<br>
+   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);<br>
+<br>
+   if (interval > surf->Config->MaxSwapInterval)<br>
+      interval = surf->Config->MaxSwapInterval;<br>
+   else if (interval < surf->Config->MinSwapInterval)<br>
+      interval = surf->Config->MinSwapInterval;<br>
+<br>
+   dri3_surf->base.SwapInterval = interval;<br>
+   dri3_update_num_back(dri3_surf);<br>
+<br>
+   return EGL_TRUE;<br>
+}<br>
+<br>
+static xcb_screen_t *<br>
+get_xcb_screen(xcb_screen_iterator_t iter, int screen)<br>
+{<br>
+    for (; iter.rem; --screen, xcb_screen_next(&iter))<br>
+        if (screen == 0)<br>
+            return iter.data;<br>
+<br>
+    return NULL;<br>
+}<br>
+<br>
+/* xDrawable in glx maps to drawable here */<br>
+static _EGLSurface *<br>
+dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,<br>
+                    _EGLConfig *conf, void *native_surface,<br>
+                    const EGLint *attrib_list)<br>
+{<br>
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
+   struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);<br>
+   struct dri3_egl_surface *dri3_surf;<br>
+   xcb_drawable_t drawable;<br>
+   xcb_get_geometry_cookie_t cookie;<br>
+   xcb_get_geometry_reply_t *reply;<br>
+   xcb_screen_iterator_t s;<br>
+   xcb_generic_error_t *error;<br>
+   xcb_screen_t *screen;<br>
+   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;<br>
+<br>
+   STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));<br>
+   drawable = (uintptr_t) native_surface;<br>
+<br>
+   (void) drv;<br>
+<br>
+   dri3_surf = calloc(1, sizeof *dri3_surf);<br>
+   if (!dri3_surf) {<br>
+      _eglError(EGL_BAD_ALLOC, "dri3_create_surface");<br>
+      return NULL;<br>
+   }<br>
+<br>
+   if (!_eglInitSurface(&dri3_surf->base, disp, type, conf, attrib_list))<br>
+      goto cleanup_surf;<br>
+<br>
+   if (type == EGL_PBUFFER_BIT) {<br>
+      s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));<br>
+      screen = get_xcb_screen(s, dri2_dpy->screen);<br>
+      if (!screen) {<br>
+         _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_create_surface");<br>
+         goto cleanup_surf;<br>
+      }<br>
+<br>
+      dri3_surf->drawable = xcb_generate_id(dri2_dpy->conn);<br>
+      xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,<br>
+                        dri3_surf->drawable, screen->root,<br>
+                        dri3_surf->base.Width, dri3_surf->base.Height);<br>
+   } else {<br>
+      dri3_surf->drawable = drawable;<br>
+   }<br>
+<br>
+   dri3_surf->base.SwapInterval = 1; /* default may be overridden below */<br>
+   dri3_surf->have_back = 0;<br>
+   dri3_surf->have_fake_front = 0;<br>
+   dri3_surf->first_init = true;<br>
+<br>
+   if (dri2_dpy->config)<br>
+      dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,<br>
+                                "vblank_mode", &vblank_mode);<br>
+<br>
+   switch (vblank_mode) {<br>
+   case DRI_CONF_VBLANK_NEVER:<br>
+   case DRI_CONF_VBLANK_DEF_INTERVAL_0:<br>
+      dri3_surf->base.SwapInterval = 0;<br>
+      break;<br>
+   case DRI_CONF_VBLANK_DEF_INTERVAL_1:<br>
+   case DRI_CONF_VBLANK_ALWAYS_SYNC:<br>
+   default:<br>
+      dri3_surf->base.SwapInterval = 1;<br>
+      break;<br>
+   }<br>
+<br>
+   dri3_update_num_back(dri3_surf);<br>
+<br>
+   /* Create a new drawable */<br>
+   dri3_surf->dri_drawable =<br>
+      (*dri2_dpy->image_driver->createNewDrawable) (dri2_dpy->dri_screen,<br>
+                                                    type == EGL_WINDOW_BIT ?<br>
+                                                    dri2_conf->dri_double_config :<br>
+                                                    dri2_conf->dri_single_config,<br>
+                                                    dri3_surf);<br>
+<br>
+   if (!dri3_surf->dri_drawable) {<br>
+      _eglError(EGL_BAD_ALLOC, "dri3->createNewDrawable");<br>
+      goto cleanup_pixmap;<br>
+   }<br>
+<br>
+   if (type != EGL_PBUFFER_BIT) {<br>
+      cookie = xcb_get_geometry (dri2_dpy->conn, dri3_surf->drawable);<br>
+      reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);<br>
+      if (reply == NULL || error != NULL) {<br>
+        _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");<br>
+        free(error);<br>
+        goto cleanup_dri_drawable;<br>
+      }<br>
+<br>
+      dri3_surf->base.Width = reply->width;<br>
+      dri3_surf->base.Height = reply->height;<br>
+      dri3_surf->depth = reply->depth;<br>
+      free(reply);<br>
+   }<br>
+<br>
+   /*<br>
+    * Make sure server has the same swap interval we do for the new<br>
+    * drawable.<br>
+    */<br>
+   dri3_set_swap_interval(drv, disp, &dri3_surf->base,<br>
+                          dri3_surf->base.SwapInterval);<br>
+<br>
+   return &dri3_surf->base;<br>
+<br>
+ cleanup_dri_drawable:<br>
+   dri2_dpy->core->destroyDrawable(dri3_surf->dri_drawable);<br>
+ cleanup_pixmap:<br>
+   if (type == EGL_PBUFFER_BIT)<br>
+      xcb_free_pixmap(dri2_dpy->conn, dri3_surf->drawable);<br>
+ cleanup_surf:<br>
+   free(dri3_surf);<br>
+<br>
+   return NULL;<br>
+}<br>
+<br>
+/**<br>
+ * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().<br>
+ */<br>
+static _EGLSurface *<br>
+dri3_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,<br>
+                           _EGLConfig *conf, void *native_window,<br>
+                           const EGLint *attrib_list)<br>
+{<br>
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
+   _EGLSurface *surf;<br>
+<br>
+   surf = dri3_create_surface(drv, disp, EGL_WINDOW_BIT, conf,<br>
+                              native_window, attrib_list);<br>
+   if (surf != NULL)<br>
+      dri3_set_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);<br>
+<br>
+   return surf;<br>
+}<br>
+<br>
+static _EGLSurface *<br>
+dri3_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,<br>
+                           _EGLConfig *conf, void *native_pixmap,<br>
+                           const EGLint *attrib_list)<br>
+{<br>
+   return dri3_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,<br>
+                              native_pixmap, attrib_list);<br>
+}<br>
+<br>
+static _EGLSurface *<br>
+dri3_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,<br>
+                                _EGLConfig *conf, const EGLint *attrib_list)<br>
+{<br>
+   return dri3_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,<br>
+                              XCB_WINDOW_NONE, attrib_list);<br>
+}<br>
+<br>
+/*<br>
+ * Process one Present event<br>
+ */<br>
+static void<br>
+dri3_handle_present_event(struct dri2_egl_display *dri2_dpy,<br>
+                          struct dri3_egl_surface *dri3_surf,<br>
+                          xcb_present_generic_event_t *ge)<br>
+{<br>
+   switch (ge->evtype) {<br>
+   case XCB_PRESENT_CONFIGURE_NOTIFY: {<br>
+      xcb_present_configure_notify_event_t *ce = (void *) ge;<br>
+<br>
+      dri3_surf->base.Width = ce->width;<br>
+      dri3_surf->base.Height = ce->height;<br>
+      break;<br>
+   }<br>
+   case XCB_PRESENT_COMPLETE_NOTIFY: {<br>
+      xcb_present_complete_notify_event_t *ce = (void *) ge;<br>
+<br>
+      /* Compute the processed SBC number from the received 32-bit serial number merged<br>
+       * with the upper 32-bits of the sent 64-bit serial number while checking for<br>
+       * wrap<br>
+       */<br>
+      if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {<br>
+         dri3_surf->recv_sbc = (dri3_surf->send_sbc & 0xffffffff00000000LL) | ce->serial;<br>
+         if (dri3_surf->recv_sbc > dri3_surf->send_sbc)<br>
+            dri3_surf->recv_sbc -= 0x100000000;<br>
+         switch (ce->mode) {<br>
+         case XCB_PRESENT_COMPLETE_MODE_FLIP:<br>
+            dri3_surf->flipping = true;<br>
+            break;<br>
+         case XCB_PRESENT_COMPLETE_MODE_COPY:<br>
+            dri3_surf->flipping = false;<br>
+            break;<br>
+         }<br>
+         dri3_update_num_back(dri3_surf);<br>
+<br>
+         /*<br>
+         if (psc->show_fps_interval)<br>
+            show_fps(priv, ce->ust); */<br>
+<br>
+         dri3_surf->ust = ce->ust;<br>
+         dri3_surf->msc = ce->msc;<br>
+      } else {<br>
+         dri3_surf->recv_msc_serial = ce->serial;<br>
+         dri3_surf->notify_ust = ce->ust;<br>
+         dri3_surf->notify_msc = ce->msc;<br>
+      }<br>
+      break;<br>
+   }<br>
+   case XCB_PRESENT_EVENT_IDLE_NOTIFY: {<br>
+      xcb_present_idle_notify_event_t *ie = (void *) ge;<br>
+      int b;<br>
+<br>
+      for (b = 0; b < sizeof (dri3_surf->buffers) / sizeof (dri3_surf->buffers[0]); b++) {<br>
+         struct dri3_buffer *buf = dri3_surf->buffers[b];<br>
+<br>
+         if (buf && buf->pixmap == ie->pixmap) {<br>
+            buf->busy = 0;<br>
+            if (dri3_surf->num_back <= b && b < DRI3_MAX_BACK) {<br>
+               dri3_free_render_buffer(dri2_dpy, dri3_surf, buf);<br>
+               dri3_surf->buffers[b] = NULL;<br>
+            }<br>
+            break;<br>
+         }<br>
+      }<br>
+      break;<br>
+   }<br>
+   }<br>
+   free(ge);<br>
+}<br>
+<br>
+static bool<br>
+dri3_wait_for_event(struct dri2_egl_display *dri2_dpy,<br>
+                    struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+   xcb_generic_event_t *ev;<br>
+   xcb_present_generic_event_t *ge;<br>
+<br>
+   xcb_flush(dri2_dpy->conn);<br>
+   ev = xcb_wait_for_special_event(dri2_dpy->conn, dri3_surf->special_event);<br>
+   if (!ev)<br>
+      return false;<br>
+   ge = (void *) ev;<br>
+   dri3_handle_present_event(dri2_dpy, dri3_surf, ge);<br>
+   return true;<br>
+}<br>
+<br>
+/** dri3_wait_for_msc<br>
+ *<br>
+ * Get the X server to send an event when the target msc/divisor/remainder is<br>
+ * reached.<br>
+ */<br>
+static EGLBoolean<br>
+dri3_wait_for_msc(struct dri2_egl_display *dri2_dpy,<br>
+                  struct dri3_egl_surface *dri3_surf,<br>
+                  int64_t target_msc, int64_t divisor, int64_t remainder,<br>
+                  int64_t *ust, int64_t *msc, int64_t *sbc)<br>
+{<br>
+   uint32_t msc_serial;<br>
+<br>
+   msc_serial = ++dri3_surf->send_msc_serial;<br>
+   xcb_present_notify_msc(dri2_dpy->conn,<br>
+                          dri3_surf->drawable,<br>
+                          msc_serial,<br>
+                          target_msc,<br>
+                          divisor,<br>
+                          remainder);<br>
+<br>
+   xcb_flush(dri2_dpy->conn);<br>
+<br>
+   /* Wait for the event */<br>
+   if (dri3_surf->special_event) {<br>
+      while ((int32_t) (msc_serial - dri3_surf->recv_msc_serial) > 0) {<br>
+         if (!dri3_wait_for_event(dri2_dpy, dri3_surf))<br>
+            return EGL_FALSE;<br>
+      }<br>
+   }<br>
+<br>
+   *ust = dri3_surf->notify_ust;<br>
+   *msc = dri3_surf->notify_msc;<br>
+   *sbc = dri3_surf->recv_sbc;<br>
+<br>
+   return EGL_TRUE;<br>
+}<br>
+<br>
+static EGLBoolean<br>
+dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,<br>
+                     EGLuint64KHR *ust, EGLuint64KHR *msc,<br>
+                     EGLuint64KHR *sbc)<br>
+{<br>
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(display);<br>
+   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);<br>
+<br>
+   return dri3_wait_for_msc(dri2_dpy, dri3_surf, 0, 0, 0, ust, msc, sbc);<br>
+}<br>
+<br>
+/**<br>
+ * Asks the driver to flush any queued work necessary for serializing with the<br>
+ * X command stream, and optionally the slightly more strict requirement of<br>
+ * glFlush() equivalence (which would require flushing even if nothing had<br>
+ * been drawn to a window system framebuffer, for example).<br>
+ */<br>
+static void<br>
+dri3_flush(struct dri2_egl_display *dri2_dpy,<br>
+           struct dri3_egl_surface *dri3_surf,<br>
+           unsigned flags,<br>
+           enum __DRI2throttleReason throttle_reason)<br>
+{<br>
+   _EGLContext *ctx = _eglGetCurrentContext();<br>
+   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);<br>
+<br>
+   if (dri2_ctx)<br>
+      (*dri2_dpy->flush->flush_with_flags)(dri2_ctx->dri_context,<br>
+                                           dri3_surf->dri_drawable,<br>
+                                           flags, throttle_reason);<br>
+}<br>
+<br>
+static xcb_gcontext_t<br>
+dri3_drawable_gc(struct dri2_egl_display *dri2_dpy,<br>
+                 struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+   if (!dri3_surf->gc) {<br>
+      uint32_t v = 0;<br>
+      xcb_create_gc(dri2_dpy->conn,<br>
+                    (dri3_surf->gc = xcb_generate_id(dri2_dpy->conn)),<br>
+                    dri3_surf->drawable,<br>
+                    XCB_GC_GRAPHICS_EXPOSURES,<br>
+                    &v);<br>
+   }<br>
+   return dri3_surf->gc;<br>
+}<br>
+<br>
+<br>
+static struct dri3_buffer *<br>
+dri3_back_buffer(struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+   return dri3_surf->buffers[DRI3_BACK_ID(dri3_surf->cur_back)];<br>
+}<br>
+<br>
+static struct dri3_buffer *<br>
+dri3_fake_front_buffer(struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+   return dri3_surf->buffers[DRI3_FRONT_ID];<br>
+}<br>
+<br>
+static void<br>
+dri3_copy_area (xcb_connection_t *c  /**< */,<br>
+                xcb_drawable_t    src_drawable  /**< */,<br>
+                xcb_drawable_t    dst_drawable  /**< */,<br>
+                xcb_gcontext_t    gc  /**< */,<br>
+                int16_t           src_x  /**< */,<br>
+                int16_t           src_y  /**< */,<br>
+                int16_t           dst_x  /**< */,<br>
+                int16_t           dst_y  /**< */,<br>
+                uint16_t          width  /**< */,<br>
+                uint16_t          height  /**< */)<br>
+{<br>
+   xcb_void_cookie_t cookie;<br>
+<br>
+   cookie = xcb_copy_area_checked(c,<br>
+                                  src_drawable,<br>
+                                  dst_drawable,<br>
+                                  gc,<br>
+                                  src_x,<br>
+                                  src_y,<br>
+                                  dst_x,<br>
+                                  dst_y,<br>
+                                  width,<br>
+                                  height);<br>
+   xcb_discard_reply(c, cookie.sequence);<br>
+}<br>
+<br>
+/**<br>
+ * Called by the driver when it needs to update the real front buffer with the<br>
+ * contents of its fake front buffer.<br>
+ */<br>
+static void<br>
+dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)<br>
+{<br>
+#if 0<br>
+   struct glx_context *gc;<br>
+   struct dri3_drawable *pdraw = loaderPrivate;<br>
+   struct dri3_screen *psc;<br>
+<br>
+   if (!pdraw)<br>
+      return;<br>
+<br>
+   if (!pdraw->base.psc)<br>
+      return;<br>
+<br>
+   psc = (struct dri3_screen *) pdraw->base.psc;<br>
+<br>
+   (void) __glXInitialize(psc->base.dpy);<br>
+<br>
+   gc = __glXGetCurrentContext();<br>
+<br>
+   dri3_flush(psc, pdraw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT);<br>
+<br>
+   dri3_wait_gl(gc);<br>
+#endif<br>
+   /* FIXME */<br>
+   (void) driDrawable;<br>
+   (void) loaderPrivate;<br>
+}<br>
+<br>
+static uint32_t<br>
+dri3_cpp_for_format(uint32_t format) {<br>
+   switch (format) {<br>
+   case  __DRI_IMAGE_FORMAT_R8:<br>
+      return 1;<br>
+   case  __DRI_IMAGE_FORMAT_RGB565:<br>
+   case  __DRI_IMAGE_FORMAT_GR88:<br>
+      return 2;<br>
+   case  __DRI_IMAGE_FORMAT_XRGB8888:<br>
+   case  __DRI_IMAGE_FORMAT_ARGB8888:<br>
+   case  __DRI_IMAGE_FORMAT_ABGR8888:<br>
+   case  __DRI_IMAGE_FORMAT_XBGR8888:<br>
+   case  __DRI_IMAGE_FORMAT_XRGB2101010:<br>
+   case  __DRI_IMAGE_FORMAT_ARGB2101010:<br>
+   case  __DRI_IMAGE_FORMAT_SARGB8:<br>
+      return 4;<br>
+   case  __DRI_IMAGE_FORMAT_NONE:<br>
+   default:<br>
+      return 0;<br>
+   }<br>
+}<br>
+<br>
+/** dri3_alloc_render_buffer<br>
+ *<br>
+ * Use the driver createImage function to construct a __DRIimage, then<br>
+ * get a file descriptor for that and create an X pixmap from that<br>
+ *<br>
+ * Allocate an xshmfence for synchronization<br>
+ */<br>
+static struct dri3_buffer *<br>
+dri3_alloc_render_buffer(struct dri2_egl_display *dri2_dpy, xcb_drawable_t draw,<br>
+                         unsigned int format, int width, int height, int depth)<br>
+{<br>
+   struct dri3_buffer *buffer;<br>
+   __DRIimage *pixmap_buffer;<br>
+   xcb_pixmap_t pixmap;<br>
+   xcb_sync_fence_t sync_fence;<br>
+   struct xshmfence *shm_fence;<br>
+   int buffer_fd, fence_fd;<br>
+   int stride;<br>
+<br>
+   /* Create an xshmfence object and<br>
+    * prepare to send that to the X server<br>
+    */<br>
+<br>
+   fence_fd = xshmfence_alloc_shm();<br>
+   if (fence_fd < 0) {<br>
+      _eglLog(_EGL_WARNING, "DRI3 Fence object allocation failure %s\n", strerror(errno));<br>
+      return NULL;<br>
+   }<br>
+   shm_fence = xshmfence_map_shm(fence_fd);<br>
+   if (shm_fence == NULL) {<br>
+      _eglLog(_EGL_WARNING, "DRI3 Fence object map failure %s\n", strerror(errno));<br>
+      goto no_shm_fence;<br>
+   }<br>
+<br>
+   /* Allocate the image from the driver<br>
+    */<br>
+   buffer = calloc(1, sizeof (struct dri3_buffer));<br>
+   if (!buffer)<br>
+      goto no_buffer;<br>
+<br>
+   buffer->cpp = dri3_cpp_for_format(format);<br>
+   if (!buffer->cpp) {<br>
+      _eglLog(_EGL_WARNING, "DRI3 buffer format %d invalid\n", format);<br>
+      goto no_image;<br>
+   }<br>
+<br>
+   if (!dri2_dpy->is_different_gpu) {<br>
+      buffer->image = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen,<br>
+                                                       width, height,<br>
+                                                       format,<br>
+                                                       __DRI_IMAGE_USE_SHARE |<br>
+                                                       __DRI_IMAGE_USE_SCANOUT,<br>
+                                                       buffer);<br>
+      pixmap_buffer = buffer->image;<br>
+<br>
+      if (!buffer->image) {<br>
+         _eglLog(_EGL_WARNING, "DRI3 gpu image creation failure\n");<br>
+         goto no_image;<br>
+      }<br>
+   } else {<br>
+      buffer->image = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen,<br>
+                                                       width, height,<br>
+                                                       format,<br>
+                                                       0,<br>
+                                                       buffer);<br>
+<br>
+      if (!buffer->image) {<br>
+         _eglLog(_EGL_WARNING, "DRI3 other gpu image creation failure\n");<br>
+         goto no_image;<br>
+      }<br>
+<br>
+      buffer->linear_buffer = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen,<br>
+                                                               width, height,<br>
+                                                               format,<br>
+                                                               __DRI_IMAGE_USE_SHARE |<br>
+                                                               __DRI_IMAGE_USE_LINEAR,<br>
+                                                               buffer);<br>
+      pixmap_buffer = buffer->linear_buffer;<br>
+<br>
+      if (!buffer->linear_buffer) {<br>
+         _eglLog(_EGL_WARNING, "DRI3 gpu linear image creation failure\n");<br>
+         goto no_linear_buffer;<br>
+      }<br>
+   }<br>
+<br>
+   /* X wants the stride, so ask the image for it<br>
+    */<br>
+   if (!(*dri2_dpy->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE, &stride)) {<br>
+      _eglLog(_EGL_WARNING, "DRI3 get image stride failed\n");<br>
+      goto no_buffer_attrib;<br>
+   }<br>
+<br>
+   buffer->pitch = stride;<br>
+<br>
+   if (!(*dri2_dpy->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD, &buffer_fd)) {<br>
+      _eglLog(_EGL_WARNING, "DRI3 get image FD failed\n");<br>
+      goto no_buffer_attrib;<br>
+   }<br>
+<br>
+   xcb_dri3_pixmap_from_buffer(dri2_dpy->conn,<br>
+                               (pixmap = xcb_generate_id(dri2_dpy->conn)),<br>
+                               draw,<br>
+                               buffer->size,<br>
+                               width, height, buffer->pitch,<br>
+                               depth, buffer->cpp * 8,<br>
+                               buffer_fd);<br>
+<br>
+   xcb_dri3_fence_from_fd(dri2_dpy->conn,<br>
+                          pixmap,<br>
+                          (sync_fence = xcb_generate_id(dri2_dpy->conn)),<br>
+                          false,<br>
+                          fence_fd);<br>
+<br>
+   buffer->pixmap = pixmap;<br>
+   buffer->own_pixmap = true;<br>
+   buffer->sync_fence = sync_fence;<br>
+   buffer->shm_fence = shm_fence;<br>
+   buffer->width = width;<br>
+   buffer->height = height;<br>
+<br>
+   /* Mark the buffer as idle<br>
+    */<br>
+   dri3_fence_set(buffer);<br>
+<br>
+   return buffer;<br>
+<br>
+no_buffer_attrib:<br>
+   (*dri2_dpy->image->destroyImage)(pixmap_buffer);<br>
+no_linear_buffer:<br>
+   if (dri2_dpy->is_different_gpu)<br>
+      (*dri2_dpy->image->destroyImage)(buffer->image);<br>
+no_image:<br>
+   free(buffer);<br>
+no_buffer:<br>
+   xshmfence_unmap_shm(shm_fence);<br>
+no_shm_fence:<br>
+   close(fence_fd);<br>
+   _eglLog(_EGL_WARNING, "DRI3 alloc_render_buffer failed\n");<br>
+   return NULL;<br>
+}<br>
+<br>
+/** dri3_flush_present_events<br>
+ *<br>
+ * Process any present events that have been received from the X server<br>
+ */<br>
+static void<br>
+dri3_flush_present_events(struct dri2_egl_display *dri2_dpy,<br>
+                          struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+   /* Check to see if any configuration changes have occurred<br>
+    * since we were last invoked<br>
+    */<br>
+   if (dri3_surf->special_event) {<br>
+      xcb_generic_event_t    *ev;<br>
+<br>
+      while ((ev = xcb_poll_for_special_event(dri2_dpy->conn,<br>
+                                              dri3_surf->special_event)) != NULL) {<br>
+         xcb_present_generic_event_t *ge = (void *) ev;<br>
+         dri3_handle_present_event(dri2_dpy, dri3_surf, ge);<br>
+      }<br>
+   }<br>
+}<br>
+<br>
+/** dri3_update_drawable<br>
+ *<br>
+ * Called the first time we use the drawable and then<br>
+ * after we receive present configure notify events to<br>
+ * track the geometry of the drawable<br>
+ */<br>
+static int<br>
+dri3_update_drawable(__DRIdrawable *driDrawable,<br>
+                     struct dri3_egl_surface *dri3_surf,<br>
+                     struct dri2_egl_display *dri2_dpy)<br>
+{<br>
+   /* First time through, go get the current drawable geometry<br>
+    */<br>
+   if (dri3_surf->first_init) {<br>
+      xcb_void_cookie_t                         cookie;<br>
+      xcb_generic_error_t                       *error;<br>
+      xcb_present_query_capabilities_cookie_t   present_capabilities_cookie;<br>
+      xcb_present_query_capabilities_reply_t    *present_capabilities_reply;<br>
+<br>
+      dri3_surf->first_init = false;<br>
+<br>
+      /* Try to select for input on the window.<br>
+       *<br>
+       * If the drawable is a window, this will get our events<br>
+       * delivered.<br>
+       *<br>
+       * Otherwise, we'll get a BadWindow error back from this request which<br>
+       * will let us know that the drawable is a pixmap instead.<br>
+       */<br>
+<br>
+<br>
+      cookie = xcb_present_select_input_checked(dri2_dpy->conn,<br>
+                                                (dri3_surf->eid = xcb_generate_id(dri2_dpy->conn)),<br>
+                                                dri3_surf->drawable,<br>
+                                                XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY|<br>
+                                                XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|<br>
+                                                XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);<br>
+<br>
+      present_capabilities_cookie = xcb_present_query_capabilities(dri2_dpy->conn,<br>
+                                                                   dri3_surf->drawable);<br>
+<br>
+      /* Create an XCB event queue to hold present events outside of the usual<br>
+       * application event queue<br>
+       */<br>
+      dri3_surf->special_event = xcb_register_for_special_xge(dri2_dpy->conn,<br>
+                                                              &xcb_present_id,<br>
+                                                              dri3_surf->eid,<br>
+                                                              dri3_surf->stamp);<br>
+<br>
+      dri3_surf->is_pixmap = false;<br>
+<br>
+      /* Check to see if our select input call failed. If it failed with a<br>
+       * BadWindow error, then assume the drawable is a pixmap. Destroy the<br>
+       * special event queue created above and mark the drawable as a pixmap<br>
+       */<br>
+<br>
+      error = xcb_request_check(dri2_dpy->conn, cookie);<br>
+<br>
+      present_capabilities_reply = xcb_present_query_capabilities_reply(dri2_dpy->conn,<br>
+                                                                        present_capabilities_cookie,<br>
+                                                                        NULL);<br>
+<br>
+      if (present_capabilities_reply) {<br>
+         dri3_surf->present_capabilities = present_capabilities_reply->capabilities;<br>
+         free(present_capabilities_reply);<br>
+      } else<br>
+         dri3_surf->present_capabilities = 0;<br>
+<br>
+      if (error) {<br>
+         if (error->error_code != BadWindow) {<br>
+            free(error);<br>
+            return false;<br>
+         }<br>
+         dri3_surf->is_pixmap = true;<br>
+         xcb_unregister_for_special_event(dri2_dpy->conn, dri3_surf->special_event);<br>
+         dri3_surf->special_event = NULL;<br>
+      }<br>
+   }<br>
+   dri3_flush_present_events(dri2_dpy, dri3_surf);<br>
+   return true;<br>
+}<br>
+<br>
+/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while<br>
+ * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid<br>
+ * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and<br>
+ * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds<br>
+ */<br>
+static int<br>
+image_format_to_fourcc(int format)<br>
+{<br>
+<br>
+   /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */<br>
+   switch (format) {<br>
+   case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;<br>
+   case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;<br>
+   case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;<br>
+   case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;<br>
+   case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;<br>
+   case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;<br>
+   }<br>
+   return 0;<br>
+}<br>
+<br>
+/** dri3_get_pixmap_buffer<br>
+ *<br>
+ * Get the DRM object for a pixmap from the X server and<br>
+ * wrap that with a __DRIimage structure using createImageFromFds<br>
+ */<br>
+static struct dri3_buffer *<br>
+dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,<br>
+                       unsigned int format,<br>
+                       enum dri3_buffer_type buffer_type,<br>
+                       struct dri3_egl_surface *dri3_surf,<br>
+                       struct dri2_egl_display *dri2_dpy)<br>
+{<br>
+   int                                  buf_id = dri3_pixmap_buf_id(buffer_type);<br>
+   struct dri3_buffer                   *buffer = dri3_surf->buffers[buf_id];<br>
+   xcb_drawable_t                       pixmap;<br>
+   xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;<br>
+   xcb_dri3_buffer_from_pixmap_reply_t  *bp_reply;<br>
+   int                                  *fds;<br>
+   xcb_sync_fence_t                     sync_fence;<br>
+   struct xshmfence                     *shm_fence;<br>
+   int                                  fence_fd;<br>
+   __DRIimage                           *image_planar;<br>
+   int                                  stride, offset;<br>
+<br>
+   if (buffer)<br>
+      return buffer;<br>
+<br>
+   pixmap = dri3_surf->drawable;<br>
+<br>
+   buffer = calloc(1, sizeof (struct dri3_buffer));<br>
+   if (!buffer)<br>
+      goto no_buffer;<br>
+<br>
+   fence_fd = xshmfence_alloc_shm();<br>
+   if (fence_fd < 0)<br>
+      goto no_fence;<br>
+   shm_fence = xshmfence_map_shm(fence_fd);<br>
+   if (shm_fence == NULL) {<br>
+      close (fence_fd);<br>
+      goto no_fence;<br>
+   }<br>
+<br>
+   xcb_dri3_fence_from_fd(dri2_dpy->conn,<br>
+                          pixmap,<br>
+                          (sync_fence = xcb_generate_id(dri2_dpy->conn)),<br>
+                          false,<br>
+                          fence_fd);<br>
+<br>
+   /* Get an FD for the pixmap object<br>
+    */<br>
+   bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, pixmap);<br>
+   bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,<br>
+                                                bp_cookie, NULL);<br>
+   if (!bp_reply)<br>
+      goto no_image;<br>
+   fds = xcb_dri3_buffer_from_pixmap_reply_fds(dri2_dpy->conn, bp_reply);<br>
+<br>
+   stride = bp_reply->stride;<br>
+   offset = 0;<br>
+<br>
+   /* createImageFromFds creates a wrapper __DRIimage structure which<br>
+    * can deal with multiple planes for things like Yuv images. So, once<br>
+    * we've gotten the planar wrapper, pull the single plane out of it and<br>
+    * discard the wrapper.<br>
+    */<br>
+   image_planar = (*dri2_dpy->image->createImageFromFds) (dri2_dpy->dri_screen,<br>
+                                                          bp_reply->width,<br>
+                                                          bp_reply->height,<br>
+                                                          image_format_to_fourcc(format),<br>
+                                                          fds, 1,<br>
+                                                          &stride, &offset, buffer);<br>
+   close(fds[0]);<br>
+   if (!image_planar)<br>
+      goto no_image;<br>
+<br>
+   buffer->image = (*dri2_dpy->image->fromPlanar)(image_planar, 0, buffer);<br>
+<br>
+   (*dri2_dpy->image->destroyImage)(image_planar);<br>
+<br>
+   if (!buffer->image)<br>
+      goto no_image;<br>
+<br>
+   buffer->pixmap = pixmap;<br>
+   buffer->own_pixmap = false;<br>
+   buffer->width = bp_reply->width;<br>
+   buffer->height = bp_reply->height;<br>
+   buffer->buffer_type = buffer_type;<br>
+   buffer->shm_fence = shm_fence;<br>
+   buffer->sync_fence = sync_fence;<br>
+<br>
+   dri3_surf->buffers[buf_id] = buffer;<br>
+   return buffer;<br>
+<br>
+no_image:<br>
+   xcb_sync_destroy_fence(dri2_dpy->conn, sync_fence);<br>
+   xshmfence_unmap_shm(shm_fence);<br>
+no_fence:<br>
+   free(buffer);<br>
+no_buffer:<br>
+   return NULL;<br>
+}<br>
+<br>
+/** dri3_find_back<br>
+ *<br>
+ * Find an idle back buffer. If there isn't one, then<br>
+ * wait for a present idle notify event from the X server<br>
+ */<br>
+static int<br>
+dri3_find_back(struct dri2_egl_display *dri2_dpy,<br>
+               struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+   int  b;<br>
+   xcb_generic_event_t *ev;<br>
+   xcb_present_generic_event_t *ge;<br>
+<br>
+   for (;;) {<br>
+      for (b = 0; b < dri3_surf->num_back; b++) {<br>
+         int id = DRI3_BACK_ID((b + dri3_surf->cur_back) % dri3_surf->num_back);<br>
+         struct dri3_buffer *buffer = dri3_surf->buffers[id];<br>
+<br>
+         if (!buffer || !buffer->busy) {<br>
+            dri3_surf->cur_back = id;<br>
+            return id;<br>
+         }<br>
+      }<br>
+      xcb_flush(dri2_dpy->conn);<br>
+      ev = xcb_wait_for_special_event(dri2_dpy->conn, dri3_surf->special_event);<br>
+      if (!ev)<br>
+         return -1;<br>
+      ge = (void *) ev;<br>
+      dri3_handle_present_event(dri2_dpy, dri3_surf, ge);<br>
+   }<br>
+}<br>
+<br>
+/** dri3_get_buffer<br>
+ *<br>
+ * Find a front or back buffer, allocating new ones as necessary<br>
+ */<br>
+static struct dri3_buffer *<br>
+dri3_get_buffer(__DRIdrawable *driDrawable,<br>
+                unsigned int format,<br>
+                enum dri3_buffer_type buffer_type,<br>
+                struct dri3_egl_surface *dri3_surf,<br>
+                struct dri2_egl_display *dri2_dpy)<br>
+{<br>
+   struct dri3_buffer      *buffer;<br>
+   _EGLContext *ctx = _eglGetCurrentContext();<br>
+   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);<br>
+   int                  buf_id;<br>
+<br>
+   if (buffer_type == dri3_buffer_back) {<br>
+      buf_id = dri3_find_back(dri2_dpy, dri3_surf);<br>
+<br>
+      if (buf_id < 0)<br>
+         return NULL;<br>
+   } else {<br>
+      buf_id = DRI3_FRONT_ID;<br>
+   }<br>
+<br>
+   buffer = dri3_surf->buffers[buf_id];<br>
+<br>
+   /* Allocate a new buffer if there isn't an old one, or if that<br>
+    * old one is the wrong size<br>
+    */<br>
+   if (!buffer || buffer->width != dri3_surf->base.Width ||<br>
+       buffer->height != dri3_surf->base.Height) {<br>
+      struct dri3_buffer   *new_buffer;<br>
+<br>
+      /* Allocate the new buffers<br>
+       */<br>
+      new_buffer = dri3_alloc_render_buffer(dri2_dpy,<br>
+                                            dri3_surf->drawable,<br>
+                                            format,<br>
+                                            dri3_surf->base.Width,<br>
+                                            dri3_surf->base.Height,<br>
+                                            dri3_surf->depth);<br>
+      if (!new_buffer)<br>
+         return NULL;<br>
+<br>
+      /* When resizing, copy the contents of the old buffer, waiting for that<br>
+       * copy to complete using our fences before proceeding<br>
+       */<br>
+      switch (buffer_type) {<br>
+      case dri3_buffer_back:<br>
+         if (buffer) {<br>
+            if (!buffer->linear_buffer) {<br>
+               dri3_fence_reset(dri2_dpy->conn, new_buffer);<br>
+               dri3_fence_await(dri2_dpy->conn, buffer);<br>
+               dri3_copy_area(dri2_dpy->conn,<br>
+                              buffer->pixmap,<br>
+                              new_buffer->pixmap,<br>
+                              dri3_drawable_gc(dri2_dpy, dri3_surf),<br>
+                              0, 0, 0, 0,<br>
+                              dri3_surf->base.Width,<br>
+                              dri3_surf->base.Height);<br>
+            dri3_fence_trigger(dri2_dpy->conn, new_buffer);<br>
+            } else if (dri2_ctx->base.Resource.Display == dri3_surf->base.Resource.Display) {<br>
+               dri2_dpy->image->blitImage(dri2_ctx->dri_context,<br>
+                                         new_buffer->image,<br>
+                                         buffer->image,<br>
+                                         0, 0, dri3_surf->base.Width,<br>
+                                         dri3_surf->base.Height,<br>
+                                         0, 0, dri3_surf->base.Width,<br>
+                                         dri3_surf->base.Height, 0);<br>
+            }<br>
+            dri3_free_render_buffer(dri2_dpy, dri3_surf, buffer);<br>
+         }<br>
+         break;<br>
+      case dri3_buffer_front:<br>
+         dri3_fence_reset(dri2_dpy->conn, new_buffer);<br>
+         dri3_copy_area(dri2_dpy->conn,<br>
+                        dri3_surf->drawable,<br>
+                        new_buffer->pixmap,<br>
+                        dri3_drawable_gc(dri2_dpy, dri3_surf),<br>
+                        0, 0, 0, 0,<br>
+                        dri3_surf->base.Width,<br>
+                        dri3_surf->base.Height);<br>
+         dri3_fence_trigger(dri2_dpy->conn, new_buffer);<br>
+<br>
+         if (new_buffer->linear_buffer &&<br>
+             dri2_ctx->base.Resource.Display == dri3_surf->base.Resource.Display) {<br>
+            dri3_fence_await(dri2_dpy->conn, new_buffer);<br>
+            dri2_dpy->image->blitImage(dri2_ctx->dri_context,<br>
+                                       new_buffer->image,<br>
+                                       new_buffer->linear_buffer,<br>
+                                       0, 0, dri3_surf->base.Width,<br>
+                                       dri3_surf->base.Height,<br>
+                                       0, 0, dri3_surf->base.Width,<br>
+                                       dri3_surf->base.Height, 0);<br>
+         }<br>
+         break;<br>
+      }<br>
+      buffer = new_buffer;<br>
+      buffer->buffer_type = buffer_type;<br>
+      dri3_surf->buffers[buf_id] = buffer;<br>
+   }<br>
+   dri3_fence_await(dri2_dpy->conn, buffer);<br>
+<br>
+   /* Return the requested buffer */<br>
+   return buffer;<br>
+}<br>
+<br>
+/** dri3_free_buffers<br>
+ *<br>
+ * Free the front bufffer or all of the back buffers. Used<br>
+ * when the application changes which buffers it needs<br>
+ */<br>
+static void<br>
+dri3_free_buffers(__DRIdrawable *driDrawable,<br>
+                  enum dri3_buffer_type buffer_type,<br>
+                  struct dri3_egl_surface *dri3_surf,<br>
+                  struct dri2_egl_display *dri2_dpy)<br>
+{<br>
+   struct dri3_buffer      *buffer;<br>
+   int                  first_id;<br>
+   int                  n_id;<br>
+   int                  buf_id;<br>
+<br>
+   switch (buffer_type) {<br>
+   case dri3_buffer_back:<br>
+      first_id = DRI3_BACK_ID(0);<br>
+      n_id = DRI3_MAX_BACK;<br>
+      break;<br>
+   case dri3_buffer_front:<br>
+      first_id = DRI3_FRONT_ID;<br>
+      n_id = 1;<br>
+   }<br>
+<br>
+   for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) {<br>
+      buffer = dri3_surf->buffers[buf_id];<br>
+      if (buffer) {<br>
+         dri3_free_render_buffer(dri2_dpy, dri3_surf, buffer);<br>
+         dri3_surf->buffers[buf_id] = NULL;<br>
+      }<br>
+   }<br>
+}<br>
+<br>
+/** dri3_get_buffers<br>
+ *<br>
+ * The published buffer allocation API.<br>
+ * Returns all of the necessary buffers, allocating<br>
+ * as needed.<br>
+ */<br>
+static int<br>
+dri3_get_buffers(__DRIdrawable *driDrawable,<br>
+                 unsigned int format,<br>
+                 uint32_t *stamp,<br>
+                 void *loaderPrivate,<br>
+                 uint32_t buffer_mask,<br>
+                 struct __DRIimageList *buffers)<br>
+{<br>
+   struct dri3_egl_surface *dri3_surf = loaderPrivate;<br>
+   struct dri2_egl_display *dri2_dpy =<br>
+      dri2_egl_display(dri3_surf->base.Resource.Display);<br>
+   struct dri3_buffer   *front, *back;<br>
+<br>
+   buffers->image_mask = 0;<br>
+   buffers->front = NULL;<br>
+   buffers->back = NULL;<br>
+<br>
+   front = NULL;<br>
+   back = NULL;<br>
+<br>
+   if (!dri3_update_drawable(driDrawable, dri3_surf, dri2_dpy))<br>
+      return false;<br>
+<br>
+   /* pixmaps always have front buffers */<br>
+   if (dri3_surf->is_pixmap)<br>
+      buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;<br>
+<br>
+   if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {<br>
+      /* All pixmaps are owned by the server gpu.<br>
+       * When we use a different gpu, we can't use the pixmap<br>
+       * as buffer since it is potentially tiled a way<br>
+       * our device can't understand. In this case, use<br>
+       * a fake front buffer. Hopefully the pixmap<br>
+       * content will get synced with the fake front<br>
+       * buffer.<br>
+       */<br>
+      if (dri3_surf->is_pixmap && !dri2_dpy->is_different_gpu)<br>
+         front = dri3_get_pixmap_buffer(driDrawable,<br>
+                                        format,<br>
+                                        dri3_buffer_front,<br>
+                                        dri3_surf,<br>
+                                        dri2_dpy);<br>
+      else<br>
+         front = dri3_get_buffer(driDrawable,<br>
+                                 format,<br>
+                                 dri3_buffer_front,<br>
+                                 dri3_surf,<br>
+                                 dri2_dpy);<br>
+<br>
+      if (!front)<br>
+         return false;<br>
+   } else {<br>
+      dri3_free_buffers(driDrawable, dri3_buffer_front, dri3_surf, dri2_dpy);<br>
+      dri3_surf->have_fake_front = 0;<br>
+   }<br>
+<br>
+   if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {<br>
+      back = dri3_get_buffer(driDrawable,<br>
+                             format,<br>
+                             dri3_buffer_back,<br>
+                             dri3_surf,<br>
+                             dri2_dpy);<br>
+      if (!back)<br>
+         return false;<br>
+      dri3_surf->have_back = 1;<br>
+   } else {<br>
+      dri3_free_buffers(driDrawable, dri3_buffer_back, dri3_surf, dri2_dpy);<br>
+      dri3_surf->have_back = 0;<br>
+   }<br>
+<br>
+   if (front) {<br>
+      buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;<br>
+      buffers->front = front->image;<br>
+      dri3_surf->have_fake_front = dri2_dpy->is_different_gpu || !dri3_surf->is_pixmap;<br>
+   }<br>
+<br>
+   if (back) {<br>
+      buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK;<br>
+      buffers->back = back->image;<br>
+   }<br>
+<br>
+   dri3_surf->stamp = stamp;<br>
+<br>
+   return true;<br>
+}<br>
+<br>
+const __DRIimageLoaderExtension dri3_image_loader_extension = {<br>
+   .base = { __DRI_IMAGE_LOADER, 1 },<br>
+<br>
+   .getBuffers          = dri3_get_buffers,<br>
+   .flushFrontBuffer    = dri3_flush_front_buffer,<br>
+};<br>
+<br>
+static int<br>
+dri3_get_ust(int64_t *ust)<br>
+{<br>
+   struct timeval tv;<br>
+<br>
+   if (ust == NULL)<br>
+      return -EFAULT;<br>
+<br>
+   if (gettimeofday(&tv, NULL) == 0) {<br>
+      ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;<br>
+      return 0;<br>
+   } else<br>
+      return -errno;<br>
+}<br>
+<br>
+static GLboolean<br>
+dri3_get_msc_rate(__DRIdrawable *draw, int32_t *numerator,<br>
+                  int32_t *denominator, void *loaderPrivate)<br>
+{<br>
+#ifdef XF86VIDMODE<br>
+   dri3_egl_surface *dri3_surf = loaderPrivate;<br>
+   struct dri2_egl_display *dri2_dpy =<br>
+      dri2_egl_display(dri3_surf->base.Resource.Display);<br>
+   XF86VidModeModeLine mode_line;<br>
+   int dot_clock;<br>
+   int i;<br>
+<br>
+   if (XF86VidModeQueryVersion(dri2_dpy->dpy, &i, &i) &&<br>
+       XF86VidModeGetModeLine(dri2_dpy->dpy, dri2_dpy->screen,<br>
+                              &dot_clock, &mode_line)) {<br>
+      unsigned n = dot_clock * 1000;<br>
+      unsigned d = mode_line.vtotal * mode_line.htotal;<br>
+<br>
+# define V_INTERLACE 0x010<br>
+# define V_DBLSCAN   0x020<br>
+<br>
+      if (mode_line.flags & V_INTERLACE)<br>
+         n *= 2;<br>
+      else if (mode_line.flags & V_DBLSCAN)<br>
+         d *= 2;<br>
+<br>
+      /* The OML_sync_control spec requires that if the refresh rate is a<br>
+       * whole number, that the returned numerator be equal to the refresh<br>
+       * rate and the denominator be 1.<br>
+       */<br>
+<br>
+      if (n % d == 0) {<br>
+         n /= d;<br>
+         d = 1;<br>
+      }<br>
+      else {<br>
+         static const unsigned f[] = { 13, 11, 7, 5, 3, 2, 0 };<br>
+<br>
+         /* This is a poor man's way to reduce a fraction.  It's far from<br>
+          * perfect, but it will work well enough for this situation.<br>
+          */<br>
+<br>
+         for (i = 0; f[i] != 0; i++) {<br>
+            while (n % f[i] == 0 && d % f[i] == 0) {<br>
+               d /= f[i];<br>
+               n /= f[i];<br>
+            }<br>
+         }<br>
+      }<br>
+<br>
+      *numerator = n;<br>
+      *denominator = d;<br>
+<br>
+      return True;<br>
+<br>
+#endif<br>
+   return False;<br>
+}<br>
+<br>
+const __DRIsystemTimeExtension dri3_system_time_extension = {<br>
+   .base = { __DRI_SYSTEM_TIME, 1 },<br>
+<br>
+   .getUST              = dri3_get_ust,<br>
+   .getMSCRate          = dri3_get_msc_rate,<br>
+};<br>
+<br>
+/** dri3_swap_buffers_msc<br>
+ *<br>
+ * Make the current back buffer visible using the present extension<br>
+ */<br>
+static int64_t<br>
+dri3_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,<br>
+                      int64_t target_msc, int64_t divisor,<br>
+                      int64_t remainder)<br>
+{<br>
+   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);<br>
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
+   struct dri3_buffer *back;<br>
+   _EGLContext *ctx = _eglGetCurrentContext();<br>
+   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);<br>
+   int64_t ret = 0;<br>
+   uint32_t options = XCB_PRESENT_OPTION_NONE;<br>
+<br>
+   dri2_flush_drawable_for_swapbuffers(disp, draw);<br>
+<br>
+   back = dri3_surf->buffers[DRI3_BACK_ID(dri3_surf->cur_back)];<br>
+   if (dri2_dpy->is_different_gpu && back) {<br>
+      /* Update the linear buffer before presenting the pixmap */<br>
+      dri2_dpy->image->blitImage(dri2_ctx->dri_context,<br>
+                                 back->linear_buffer,<br>
+                                 back->image,<br>
+                                 0, 0, back->width,<br>
+                                 back->height,<br>
+                                 0, 0, back->width,<br>
+                                 back->height, __BLIT_FLAG_FLUSH);<br>
+      /* Update the fake front */<br>
+      if (dri3_surf->have_fake_front)<br>
+         dri2_dpy->image->blitImage(dri2_ctx->dri_context,<br>
+                                    dri3_surf->buffers[DRI3_FRONT_ID]->image,<br>
+                                    back->image,<br>
+                                    0, 0, dri3_surf->base.Width,<br>
+                                    dri3_surf->base.Height,<br>
+                                    0, 0, dri3_surf->base.Width,<br>
+                                    dri3_surf->base.Height,<br>
+                                    __BLIT_FLAG_FLUSH);<br>
+   }<br>
+<br>
+   dri3_flush_present_events(dri2_dpy, dri3_surf);<br>
+<br>
+   if (back && !dri3_surf->is_pixmap) {<br>
+      dri3_fence_reset(dri2_dpy->conn, back);<br>
+<br>
+      /* Compute when we want the frame shown by taking the last known successful<br>
+       * MSC and adding in a swap interval for each outstanding swap request.<br>
+       * target_msc=divisor=remainder=0 means "Use glXSwapBuffers() semantic"<br>
+       */<br>
+      ++dri3_surf->send_sbc;<br>
+      if (target_msc == 0 && divisor == 0 && remainder == 0)<br>
+         target_msc = dri3_surf->msc + dri3_surf->base.SwapInterval * (dri3_surf->send_sbc - dri3_surf->recv_sbc);<br>
+      else if (divisor == 0 && remainder > 0) {<br>
+         /*<br>
+          *     "If <divisor> = 0, the swap will occur when MSC becomes<br>
+          *      greater than or equal to <target_msc>."<br>
+          *<br>
+          * Note that there's no mention of the remainder.  The Present extension<br>
+          * throws BadValue for remainder != 0 with divisor == 0, so just drop<br>
+          * the passed in value.<br>
+          */<br>
+         remainder = 0;<br>
+      }<br>
+<br>
+      /* From the EGL 1.4 spec (page 53):<br>
+       *<br>
+       *     "If <interval> is set to a value of 0, buffer swaps are not<br>
+       *      synchronized to a video frame."<br>
+       *<br>
+       * Implementation note: It is possible to enable triple buffering behaviour<br>
+       * by not using XCB_PRESENT_OPTION_ASYNC, but this should not be the default.<br>
+       */<br>
+      if (dri3_surf->base.SwapInterval == 0)<br>
+          options |= XCB_PRESENT_OPTION_ASYNC;<br>
+<br>
+      back->busy = 1;<br>
+      back->last_swap = dri3_surf->send_sbc;<br>
+      xcb_present_pixmap(dri2_dpy->conn,<br>
+                         dri3_surf->drawable,<br>
+                         back->pixmap,<br>
+                         (uint32_t) dri3_surf->send_sbc,<br>
+                         0,                                    /* valid */<br>
+                         0,                                    /* update */<br>
+                         0,                                    /* x_off */<br>
+                         0,                                    /* y_off */<br>
+                         None,                                 /* target_crtc */<br>
+                         None,<br>
+                         back->sync_fence,<br>
+                         options,<br>
+                         target_msc,<br>
+                         divisor,<br>
+                         remainder, 0, NULL);<br>
+      ret = (int64_t) dri3_surf->send_sbc;<br>
+<br>
+      /* If there's a fake front, then copy the source back buffer<br>
+       * to the fake front to keep it up to date. This needs<br>
+       * to reset the fence and make future users block until<br>
+       * the X server is done copying the bits<br>
+       */<br>
+      if (dri3_surf->have_fake_front && !dri2_dpy->is_different_gpu) {<br>
+         dri3_fence_reset(dri2_dpy->conn, dri3_surf->buffers[DRI3_FRONT_ID]);<br>
+         dri3_copy_area(dri2_dpy->conn,<br>
+                        back->pixmap,<br>
+                        dri3_surf->buffers[DRI3_FRONT_ID]->pixmap,<br>
+                        dri3_drawable_gc(dri2_dpy, dri3_surf),<br>
+                        0, 0, 0, 0,<br>
+                        dri3_surf->base.Width,<br>
+                        dri3_surf->base.Height);<br>
+         dri3_fence_trigger(dri2_dpy->conn, dri3_surf->buffers[DRI3_FRONT_ID]);<br>
+      }<br>
+      xcb_flush(dri2_dpy->conn);<br>
+      if (dri3_surf->stamp)<br>
+         ++(*dri3_surf->stamp);<br>
+   }<br>
+<br>
+   (*dri2_dpy->flush->invalidate)(dri3_surf->dri_drawable);<br>
+<br>
+   return ret;<br>
+}<br>
+<br>
+static EGLBoolean<br>
+dri3_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)<br>
+{<br>
+   return dri3_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1;<br>
+}<br>
+<br>
+static int<br>
+dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)<br>
+{<br>
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);<br>
+   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);<br>
+   int back_id = DRI3_BACK_ID(dri3_find_back(dri2_dpy, dri3_surf));<br>
+<br>
+   if (back_id < 0 || !dri3_surf->buffers[back_id])<br>
+      return 0;<br>
+<br>
+   if (dri3_surf->buffers[back_id]->last_swap != 0)<br>
+      return dri3_surf->send_sbc - dri3_surf->buffers[back_id]->last_swap + 1;<br>
+   else<br>
+      return 0;<br>
+}<br>
+<br>
+/* FIXME: Is this right? Seems problematic for WL_bind_wayland_display */<br>
+static int<br>
+dri3_authenticate(_EGLDisplay *disp, uint32_t id)<br>
+{<br>
+   return 0;<br>
+}<br>
+<br>
+struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {<br>
+   .authenticate = dri3_authenticate,<br>
+   .create_window_surface = dri3_create_window_surface,<br>
+   .create_pixmap_surface = dri3_create_pixmap_surface,<br>
+   .create_pbuffer_surface = dri3_create_pbuffer_surface,<br>
+   .destroy_surface = dri3_destroy_surface,<br>
+   .create_image = dri2_create_image_khr,<br>
+   .swap_interval = dri3_set_swap_interval,<br>
+   .swap_buffers = dri3_swap_buffers,<br>
+   .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,<br>
+   .swap_buffers_region = dri2_fallback_swap_buffers_region,<br>
+   .post_sub_buffer = dri2_fallback_post_sub_buffer,<br>
+   .copy_buffers = dri2_fallback_copy_buffers,<br>
+   .query_buffer_age = dri3_query_buffer_age,<br>
+   .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,<br>
+   .get_sync_values = dri3_get_sync_values,<br>
+};<br>
+<br>
+/** dri3_open<br>
+ *<br>
+ * Wrapper around xcb_dri3_open<br>
+ */<br>
+static int<br>
+dri3_open(xcb_connection_t *conn,<br>
+          xcb_window_t root,<br>
+          uint32_t provider)<br>
+{<br>
+   xcb_dri3_open_cookie_t       cookie;<br>
+   xcb_dri3_open_reply_t        *reply;<br>
+   int                          fd;<br>
+<br>
+   cookie = xcb_dri3_open(conn,<br>
+                          root,<br>
+                          provider);<br>
+<br>
+   reply = xcb_dri3_open_reply(conn, cookie, NULL);<br>
+   if (!reply)<br>
+      return -1;<br>
+<br>
+   if (reply->nfd != 1) {<br>
+      free(reply);<br>
+      return -1;<br>
+   }<br>
+<br>
+   fd = xcb_dri3_open_reply_fds(conn, reply)[0];<br>
+   fcntl(fd, F_SETFD, FD_CLOEXEC);<br>
+<br>
+   return fd;<br>
+}<br>
+<br>
+EGLBoolean<br>
+dri3_x11_connect(struct dri2_egl_display *dri2_dpy)<br>
+{<br>
+   xcb_dri3_query_version_reply_t *dri3_query;<br>
+   xcb_dri3_query_version_cookie_t dri3_query_cookie;<br>
+   xcb_present_query_version_reply_t *present_query;<br>
+   xcb_present_query_version_cookie_t present_query_cookie;<br>
+   xcb_generic_error_t *error;<br>
+   xcb_screen_iterator_t s;<br>
+   xcb_screen_t *screen;<br>
+   const xcb_query_extension_reply_t *extension;<br>
+<br>
+   xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);<br>
+   xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);<br>
+<br>
+   extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);<br>
+   if (!(extension && extension->present))<br>
+      return EGL_FALSE;<br>
+<br>
+   extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);<br>
+   if (!(extension && extension->present))<br>
+      return EGL_FALSE;<br>
+<br>
+   dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,<br>
+                                              XCB_DRI3_MAJOR_VERSION,<br>
+                                              XCB_DRI3_MINOR_VERSION);<br>
+<br>
+   present_query_cookie = xcb_present_query_version(dri2_dpy->conn,<br>
+                                                    XCB_PRESENT_MAJOR_VERSION,<br>
+                                                    XCB_PRESENT_MINOR_VERSION);<br>
+<br>
+   /* FIXME: a little bit memory leak here */<br>
+   dri3_query =<br>
+      xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);<br>
+   if (dri3_query == NULL || error != NULL) {<br>
+      _eglLog(_EGL_WARNING, "DRI2: failed to query dri3 version");<br>
+      free(error);<br>
+      return EGL_FALSE;<br>
+   }<br>
+   dri2_dpy->dri3_major = dri3_query->major_version;<br>
+   dri2_dpy->dri3_minor = dri3_query->minor_version;<br>
+   free(dri3_query);<br>
+<br>
+   present_query =<br>
+      xcb_present_query_version_reply(dri2_dpy->conn,<br>
+                                      present_query_cookie, &error);<br>
+   if (present_query == NULL || error != NULL) {<br>
+      _eglLog(_EGL_WARNING, "DRI2: failed to query Present version");<br>
+      free(error);<br>
+      return EGL_FALSE;<br>
+   }<br>
+   dri2_dpy->present_major = present_query->major_version;<br>
+   dri2_dpy->present_minor = present_query->minor_version;<br>
+   free(present_query);<br>
+<br>
+   s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));<br>
+   screen = get_xcb_screen(s, dri2_dpy->screen);<br>
+   if (!screen) {<br>
+      _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_x11_connect");<br>
+      return EGL_FALSE;<br>
+   }<br>
+<br>
+   dri2_dpy->fd = dri3_open(dri2_dpy->conn, screen->root, 0);<br>
+   if (dri2_dpy->fd < 0) {<br>
+      int conn_error = xcb_connection_has_error(dri2_dpy->conn);<br>
+      _eglLog(_EGL_WARNING, "DRI2: Screen seem not DRI3 capable");<br>
+<br>
+      if (conn_error)<br>
+         _eglLog(_EGL_WARNING, "DRI2: Failed to initialize DRI3");<br>
+<br>
+      return EGL_FALSE;<br>
+   }<br>
+<br>
+   dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);<br>
+<br>
+   dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);<br>
+   if (!dri2_dpy->driver_name) {<br>
+      _eglLog(_EGL_WARNING, "DRI2: No driver found");<br>
+      close(dri2_dpy->fd);<br>
+      return EGL_FALSE;<br>
+   }<br>
+<br>
+   dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);<br>
+   if (!dri2_dpy->device_name) {<br>
+      _eglLog(_EGL_WARNING, "DRI2: Cannot find device name");<br>
+      close(dri2_dpy->fd);<br>
+      return EGL_FALSE;<br>
+   }<br>
+<br>
+   return EGL_TRUE;<br>
+}<br>
diff --git a/src/egl/drivers/dri2/platform_x11_dri3.h b/src/egl/drivers/dri2/platform_x11_dri3.h<br>
new file mode 100644<br>
index 0000000..efdfcdb<br>
--- /dev/null<br>
+++ b/src/egl/drivers/dri2/platform_x11_dri3.h<br>
@@ -0,0 +1,140 @@<br>
+/*<br>
+ * Copyright © 2013 Keith Packard<br>
+ *<br>
+ * Permission to use, copy, modify, distribute, and sell this software and its<br>
+ * documentation for any purpose is hereby granted without fee, provided that<br>
+ * the above copyright notice appear in all copies and that both that copyright<br>
+ * notice and this permission notice appear in supporting documentation, and<br>
+ * that the name of the copyright holders not be used in advertising or<br>
+ * publicity pertaining to distribution of the software without specific,<br>
+ * written prior permission.  The copyright holders make no representations<br>
+ * about the suitability of this software for any purpose.  It is provided "as<br>
+ * is" without express or implied warranty.<br>
+ *<br>
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,<br>
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO<br>
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR<br>
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,<br>
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER<br>
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE<br>
+ * OF THIS SOFTWARE.<br>
+ */<br>
+<br>
+#ifndef EGL_X11_DRI3_INCLUDED<br>
+#define EGL_X11_DRI3_INCLUDED<br>
+<br>
+#include <stdbool.h><br>
+#include <xcb/xcb.h><br>
+#include <xcb/present.h><br>
+<br>
+#include "egl_dri2.h"<br>
+<br>
+_EGL_DRIVER_TYPECAST(dri3_egl_surface, _EGLSurface, obj)<br>
+enum dri3_buffer_type {<br>
+   dri3_buffer_back = 0,<br>
+   dri3_buffer_front = 1<br>
+};<br>
+<br>
+struct dri3_buffer {<br>
+   __DRIimage   *image;<br>
+   __DRIimage   *linear_buffer;<br>
+   uint32_t     pixmap;<br>
+<br>
+   /* Synchronization between the client and X server is done using an<br>
+    * xshmfence that is mapped into an X server SyncFence. This lets the<br>
+    * client check whether the X server is done using a buffer with a simple<br>
+    * xshmfence call, rather than going to read X events from the wire.<br>
+    *<br>
+    * However, we can only wait for one xshmfence to be triggered at a time,<br>
+    * so we need to know *which* buffer is going to be idle next. We do that<br>
+    * by waiting for a PresentIdleNotify event. When that event arrives, the<br>
+    * 'busy' flag gets cleared and the client knows that the fence has been<br>
+    * triggered, and that the wait call will not block.<br>
+    */<br>
+<br>
+   uint32_t     sync_fence;     /* XID of X SyncFence object */<br>
+   struct xshmfence *shm_fence; /* pointer to xshmfence object */<br>
+   bool         busy;           /* Set on swap, cleared on IdleNotify */<br>
+   bool         own_pixmap;     /* We allocated the pixmap ID, free on destroy */<br>
+<br>
+   uint32_t     size;<br>
+   uint32_t     pitch;<br>
+   uint32_t     cpp;<br>
+   uint32_t     flags;<br>
+   uint32_t     width, height;<br>
+   uint64_t     last_swap;<br>
+<br>
+   enum dri3_buffer_type        buffer_type;<br>
+};<br>
+<br>
+<br>
+#define DRI3_MAX_BACK   4<br>
+#define DRI3_BACK_ID(i) (i)<br>
+#define DRI3_FRONT_ID   (DRI3_MAX_BACK)<br>
+<br>
+static inline int<br>
+dri3_pixmap_buf_id(enum dri3_buffer_type buffer_type)<br>
+{<br>
+   if (buffer_type == dri3_buffer_back)<br>
+      return DRI3_BACK_ID(0);<br>
+   else<br>
+      return DRI3_FRONT_ID;<br>
+}<br>
+<br>
+#define DRI3_NUM_BUFFERS        (1 + DRI3_MAX_BACK)<br>
+<br>
+struct dri3_egl_surface {<br>
+   _EGLSurface base;<br>
+   __DRIdrawable *dri_drawable;<br>
+   xcb_drawable_t drawable;<br>
+   int depth;<br>
+   uint8_t have_back;<br>
+   uint8_t have_fake_front;<br>
+   uint8_t is_pixmap;<br>
+   uint8_t flipping;<br>
+<br>
+   /* Present extension capabilities<br>
+    */<br>
+   uint32_t present_capabilities;<br>
+<br>
+   /* SBC numbers are tracked by using the serial numbers<br>
+    * in the present request and complete events<br>
+    */<br>
+   uint64_t send_sbc;<br>
+   uint64_t recv_sbc;<br>
+<br>
+   /* Last received UST/MSC values for pixmap present complete */<br>
+   uint64_t ust, msc;<br>
+<br>
+   /* Last received UST/MSC values from present notify msc event */<br>
+   uint64_t notify_ust, notify_msc;<br>
+<br>
+   /* Serial numbers for tracking wait_for_msc events */<br>
+   uint32_t send_msc_serial;<br>
+   uint32_t recv_msc_serial;<br>
+<br>
+   struct dri3_buffer *buffers[DRI3_NUM_BUFFERS];<br>
+   int cur_back;<br>
+   int num_back;<br>
+<br>
+   uint32_t *stamp;<br>
+<br>
+   xcb_present_event_t eid;<br>
+   xcb_gcontext_t gc;<br>
+   xcb_special_event_t *special_event;<br>
+<br>
+   /* LIBGL_SHOW_FPS support */<br>
+   uint64_t previous_ust;<br>
+   unsigned frames;<br>
+<br>
+   bool first_init;<br>
+};<br>
+<br>
+extern const __DRIimageLoaderExtension dri3_image_loader_extension;<br>
+extern const __DRIsystemTimeExtension dri3_system_time_extension;<br>
+extern struct dri2_egl_display_vtbl dri3_x11_display_vtbl;<br>
+<br>
+EGLBoolean<br>
+dri3_x11_connect(struct dri2_egl_display *dri2_dpy);<br>
+<br>
+#endif<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.4.4<br>
<br>
</font></span></blockquote></div><br></div></div>