[Mesa-dev] [PATCH RFC] egl/dri2: Add dri3 support to x11 platform

Emil Velikov emil.l.velikov at gmail.com
Fri Jul 3 07:36:18 PDT 2015


Hi Boyan,

Thank you for doing this ! A few suggestions which you might be interesting:

Considering that the backend has handled more than dri2 perhaps we can
do a s/dri2/dri/ :-) That obviously is independent of your work.

On 01/07/15 16:31, Boyan Ding wrote:
> Signed-off-by: Boyan Ding <boyan.j.ding at gmail.com>
> ---
>  configure.ac                             |    3 +
>  src/egl/drivers/dri2/Makefile.am         |    5 +
>  src/egl/drivers/dri2/egl_dri2.c          |   65 +-
>  src/egl/drivers/dri2/egl_dri2.h          |   12 +-
>  src/egl/drivers/dri2/platform_x11.c      |  127 ++-
>  src/egl/drivers/dri2/platform_x11_dri3.c | 1591 ++++++++++++++++++++++++++++++
>  src/egl/drivers/dri2/platform_x11_dri3.h |  140 +++
>  7 files changed, 1926 insertions(+), 17 deletions(-)
>  create mode 100644 src/egl/drivers/dri2/platform_x11_dri3.c
>  create mode 100644 src/egl/drivers/dri2/platform_x11_dri3.h
> 
> diff --git a/configure.ac b/configure.ac
> index af61aa2..090e6c9 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1545,6 +1545,9 @@ if test "x$enable_egl" = xyes; then
>              if test "x$enable_shared_glapi" = xno; then
>                  AC_MSG_ERROR([egl_dri2 requires --enable-shared-glapi])
>              fi
> +            if test "x$enable_dri3" = xyes; then
> +                EGL_LIB_DEPS="$EGL_LIB_DEPS -lxcb-dri3 -lxcb-present -lXxf86vm -lxshmfence -lxcb-sync"
Neither one of these should be a direct -lfoo expression. We should
check/use PKG_CHECK_MODULES and foo_{CFLAGS,LIBS}.

> +            fi
>          else
>              # Avoid building an "empty" libEGL. Drop/update this
>              # when other backends (haiku?) come along.
> diff --git a/src/egl/drivers/dri2/Makefile.am b/src/egl/drivers/dri2/Makefile.am
> index 55be4a7..d5b511c 100644
> --- a/src/egl/drivers/dri2/Makefile.am
> +++ b/src/egl/drivers/dri2/Makefile.am
> @@ -52,6 +52,11 @@ if HAVE_EGL_PLATFORM_X11
>  libegl_dri2_la_SOURCES += platform_x11.c
>  AM_CFLAGS += -DHAVE_X11_PLATFORM
>  AM_CFLAGS += $(XCB_DRI2_CFLAGS)
> +if HAVE_DRI3
> +libegl_dri2_la_SOURCES += \
> +	platform_x11_dri3.c \
> +	platform_x11_dri3.h
> +endif
>  endif
>  
>  if HAVE_EGL_PLATFORM_WAYLAND
> diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
> index b1b65f7..052c579 100644
> --- a/src/egl/drivers/dri2/egl_dri2.c
> +++ b/src/egl/drivers/dri2/egl_dri2.c
> @@ -322,6 +322,12 @@ struct dri2_extension_match {
>     int offset;
>  };
>  
> +static struct dri2_extension_match dri3_driver_extensions[] = {
> +   { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
> +   { __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) },
> +   { NULL, 0, 0 }
> +};
> +
>  static struct dri2_extension_match dri2_driver_extensions[] = {
>     { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
>     { __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) },
> @@ -464,6 +470,24 @@ dri2_open_driver(_EGLDisplay *disp)
>  }
>  
>  EGLBoolean
> +dri2_load_driver_dri3(_EGLDisplay *disp)
dri3_load_driver perhaps ?

> +{
> +   struct dri2_egl_display *dri2_dpy = disp->DriverData;
> +   const __DRIextension **extensions;
> +
> +   extensions = dri2_open_driver(disp);
> +   if (!extensions)
> +      return EGL_FALSE;
> +
> +   if (!dri2_bind_extensions(dri2_dpy, dri3_driver_extensions, extensions)) {
> +      dlclose(dri2_dpy->driver);
> +   }
> +   dri2_dpy->driver_extensions = extensions;
> +
> +   return EGL_TRUE;
> +}
> +
> +EGLBoolean
>  dri2_load_driver(_EGLDisplay *disp)
>  {
>     struct dri2_egl_display *dri2_dpy = disp->DriverData;
> @@ -507,7 +531,9 @@ dri2_setup_screen(_EGLDisplay *disp)
>     struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
>     unsigned int api_mask;
>  
> -   if (dri2_dpy->dri2) {
> +   if (dri2_dpy->image_driver) {
> +      api_mask = dri2_dpy->image_driver->getAPIMask(dri2_dpy->dri_screen);
> +   } else if (dri2_dpy->dri2) {
>        api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);
>     } else {
>        assert(dri2_dpy->swrast);
> @@ -527,11 +553,12 @@ dri2_setup_screen(_EGLDisplay *disp)
>     if (api_mask & (1 << __DRI_API_GLES3))
>        disp->ClientAPIs |= EGL_OPENGL_ES3_BIT_KHR;
>  
> -   assert(dri2_dpy->dri2 || dri2_dpy->swrast);
> +   assert(dri2_dpy->image_driver || dri2_dpy->dri2 || dri2_dpy->swrast);
>     disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
>     disp->Extensions.MESA_configless_context = EGL_TRUE;
>  
> -   if ((dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) ||
> +   if (dri2_dpy->image_driver ||
> +       (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) ||
>         (dri2_dpy->swrast && dri2_dpy->swrast->base.version >= 3)) {
>        disp->Extensions.KHR_create_context = EGL_TRUE;
>  
> @@ -591,7 +618,14 @@ dri2_create_screen(_EGLDisplay *disp)
>  
>     dri2_dpy = disp->DriverData;
>  
> -   if (dri2_dpy->dri2) {
> +   if (dri2_dpy->image_driver) {
> +      dri2_dpy->dri_screen =
> +         dri2_dpy->image_driver->createNewScreen2(0, dri2_dpy->fd,
> +                                                  dri2_dpy->extensions,
> +                                                  dri2_dpy->driver_extensions,
> +                                                  &dri2_dpy->driver_configs,
> +                                                  disp);
> +   } else if (dri2_dpy->dri2) {
>        if (dri2_dpy->dri2->base.version >= 4) {
>           dri2_dpy->dri_screen =
>              dri2_dpy->dri2->createNewScreen2(0, dri2_dpy->fd,
> @@ -627,7 +661,7 @@ dri2_create_screen(_EGLDisplay *disp)
>  
>     extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
>  
> -   if (dri2_dpy->dri2) {
> +   if (dri2_dpy->image_driver || dri2_dpy->dri2) {
>        if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
>           goto cleanup_dri_screen;
>     } else {
> @@ -971,7 +1005,26 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
>     else
>        dri_config = NULL;
>  
> -   if (dri2_dpy->dri2) {
> +   if (dri2_dpy->image_driver) {
> +      unsigned error;
> +      unsigned num_attribs = 8;
> +      uint32_t ctx_attribs[8];
> +
> +      if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs,
> +                                        &num_attribs))
> +         goto cleanup;
> +
> +      dri2_ctx->dri_context =
> +         dri2_dpy->image_driver->createContextAttribs(dri2_dpy->dri_screen,
> +                                                      api,
> +                                                      dri_config,
> +                                                      shared,
> +                                                      num_attribs / 2,
> +                                                      ctx_attribs,
> +                                                      & error,
> +                                                      dri2_ctx);
> +      dri2_create_context_attribs_error(error);
> +   } else if (dri2_dpy->dri2) {
>        if (dri2_dpy->dri2->base.version >= 3) {
>           unsigned error;
>           unsigned num_attribs = 8;
> diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
> index f0cc6da..d258753 100644
> --- a/src/egl/drivers/dri2/egl_dri2.h
> +++ b/src/egl/drivers/dri2/egl_dri2.h
> @@ -153,11 +153,16 @@ struct dri2_egl_display
>  
>     int                       dri2_major;
>     int                       dri2_minor;
> +   int                       dri3_major;
> +   int                       dri3_minor;
> +   int                       present_major;
> +   int                       present_minor;
Many of these are unused. Same goes for the glx code which was the
inspiration for this work :-)

>     __DRIscreen              *dri_screen;
>     int                       own_dri_screen;
>     const __DRIconfig       **driver_configs;
>     void                     *driver;
>     const __DRIcoreExtension       *core;
> +   const __DRIimageDriverExtension *image_driver;
>     const __DRIdri2Extension       *dri2;
>     const __DRIswrastExtension     *swrast;
>     const __DRI2flushExtension     *flush;
> @@ -189,6 +194,7 @@ struct dri2_egl_display
>  #ifdef HAVE_X11_PLATFORM
>     xcb_connection_t         *conn;
>     int                      screen;
> +   Display                  *dpy;
If we only loved XF86VIDMODE and/or xcb a bit more we wouldn't need this
:'-(

>  #endif
>  
>  #ifdef HAVE_WAYLAND_PLATFORM
> @@ -202,8 +208,9 @@ struct dri2_egl_display
>     int			     formats;
>     uint32_t                  capabilities;
>     int			     is_render_node;
> -   int			     is_different_gpu;
>  #endif
> +
> +   int			     is_different_gpu;
This could be a separate patch.

>  };
>  
>  struct dri2_egl_context
> @@ -324,6 +331,9 @@ EGLBoolean
>  dri2_load_driver_swrast(_EGLDisplay *disp);
>  
>  EGLBoolean
> +dri2_load_driver_dri3(_EGLDisplay *disp);
> +
> +EGLBoolean
>  dri2_create_screen(_EGLDisplay *disp);
>  
>  __DRIimage *
> diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c
> index ad40bd5..2ce260f 100644
> --- a/src/egl/drivers/dri2/platform_x11.c
> +++ b/src/egl/drivers/dri2/platform_x11.c
> @@ -45,6 +45,10 @@
>  #include "egl_dri2_fallbacks.h"
>  #include "loader.h"
>  
> +#ifdef HAVE_DRI3
> +#include "platform_x11_dri3.h"
> +#endif
> +
>  static EGLBoolean
>  dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
>                         EGLint interval);
> @@ -1094,13 +1098,17 @@ dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp)
>  
>     disp->DriverData = (void *) dri2_dpy;
>     if (disp->PlatformDisplay == NULL) {
> -      dri2_dpy->conn = xcb_connect(0, &dri2_dpy->screen);
> +      dri2_dpy->dpy = XOpenDisplay(NULL);
> +
> +      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);
> +      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);
> +
>        dri2_dpy->own_device = true;
>     } else {
> -      Display *dpy = disp->PlatformDisplay;
> +      dri2_dpy->dpy = disp->PlatformDisplay;
>  
> -      dri2_dpy->conn = XGetXCBConnection(dpy);
> -      dri2_dpy->screen = DefaultScreen(dpy);
> +      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);
> +      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);
Why do we need this hunk ?

>     }
>  
>     if (xcb_connection_has_error(dri2_dpy->conn)) {
> @@ -1202,6 +1210,94 @@ dri2_x11_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
>     }
>  }
>  
> +#ifdef HAVE_DRI3
> +static EGLBoolean
> +dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp)
dri3_initialize_x11 ?

> +{
> +   struct dri2_egl_display *dri2_dpy;
> +
> +   dri2_dpy = calloc(1, sizeof *dri2_dpy);
> +   if (!dri2_dpy)
> +      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
> +
> +   disp->DriverData = (void *) dri2_dpy;
> +   if (disp->PlatformDisplay == NULL) {
> +      dri2_dpy->dpy = XOpenDisplay(NULL);
> +
> +      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);
> +      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);
> +
> +      dri2_dpy->own_device = true;
> +   } else {
> +      dri2_dpy->dpy = disp->PlatformDisplay;
> +
> +      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);
> +      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);
> +   }
> +
> +   if (xcb_connection_has_error(dri2_dpy->conn)) {
> +      _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
> +      goto cleanup_dpy;
> +   }
> +
> +   if (dri2_dpy->conn) {
> +      if (!dri3_x11_connect(dri2_dpy))
> +	 goto cleanup_conn;
> +   }
> +
> +   if (!dri2_load_driver_dri3(disp))
> +      goto cleanup_conn;
> +
> +   dri2_dpy->extensions[0] = &dri3_image_loader_extension.base;
> +   dri2_dpy->extensions[1] = &dri3_system_time_extension.base;
> +   dri2_dpy->extensions[2] = &use_invalidate.base;
> +   dri2_dpy->extensions[3] = &image_lookup_extension.base;
> +   dri2_dpy->extensions[4] = NULL;
> +
> +   dri2_dpy->swap_available = true;
> +   dri2_dpy->invalidate_available = true;
> +
> +   if (!dri2_create_screen(disp))
> +      goto cleanup_fd;
> +
> +   dri2_x11_setup_swap_interval(dri2_dpy);
> +
> +   disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
> +   disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
> +   disp->Extensions.EXT_buffer_age = EGL_TRUE;
> +
> +#ifdef HAVE_WAYLAND_PLATFORM
> +   disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
> +#endif
> +
> +   if (dri2_dpy->conn) {
> +      if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp))
> +	 goto cleanup_configs;
> +   }
> +
> +   /* Fill vtbl last to prevent accidentally calling virtual function during
> +    * initialization.
> +    */
> +   dri2_dpy->vtbl = &dri3_x11_display_vtbl;
> +
> +   return EGL_TRUE;
> +
> + cleanup_configs:
> +   _eglCleanupDisplay(disp);
> +   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
> +   dlclose(dri2_dpy->driver);
> + cleanup_fd:
> +   close(dri2_dpy->fd);
> + cleanup_conn:
> +   if (disp->PlatformDisplay == NULL)
> +      xcb_disconnect(dri2_dpy->conn);
Considering that we're using XOpenDisplay, the above should be
XCloseDisplay ?

> + cleanup_dpy:
> +   free(dri2_dpy);
> +
> +   return EGL_FALSE;
> +}
> +#endif
> +
>  static EGLBoolean
>  dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
>  {
> @@ -1213,13 +1309,17 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
>  
>     disp->DriverData = (void *) dri2_dpy;
>     if (disp->PlatformDisplay == NULL) {
> -      dri2_dpy->conn = xcb_connect(0, &dri2_dpy->screen);
> +      dri2_dpy->dpy = XOpenDisplay(NULL);
> +
> +      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);
> +      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);
> +
>        dri2_dpy->own_device = true;
>     } else {
> -      Display *dpy = disp->PlatformDisplay;
> +      dri2_dpy->dpy = disp->PlatformDisplay;
>  
> -      dri2_dpy->conn = XGetXCBConnection(dpy);
> -      dri2_dpy->screen = DefaultScreen(dpy);
> +      dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);
> +      dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);
Don't think we need this hunk.

>     }
>  
>     if (xcb_connection_has_error(dri2_dpy->conn)) {
> @@ -1321,9 +1421,16 @@ dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)
>     int x11_dri2_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
>  
>     if (x11_dri2_accel) {
> -      if (!dri2_initialize_x11_dri2(drv, disp)) {
> -         initialized = dri2_initialize_x11_swrast(drv, disp);
> +#ifdef HAVE_DRI3
> +      if (getenv("LIBGL_DRI3_ENABLE") == NULL ||
> +          !dri2_initialize_x11_dri3(drv, disp)) {
> +#endif
> +         if (!dri2_initialize_x11_dri2(drv, disp)) {
> +            initialized = dri2_initialize_x11_swrast(drv, disp);
> +         }
> +#ifdef HAVE_DRI3
>        }
> +#endif
>     } else {
>        initialized = dri2_initialize_x11_swrast(drv, disp);
>     }
> diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c
> new file mode 100644
> index 0000000..dcd7128
> --- /dev/null
> +++ b/src/egl/drivers/dri2/platform_x11_dri3.c
Considering that this is heavily based on the glx code I'm wondering if
we can get some of that into some common helpers ? Something like
src/loader/dri3_helper.[ch] perhaps.

> @@ -0,0 +1,1591 @@
> +/*
> + * 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.
> + */
> +
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/time.h>
> +
> +#ifdef XF86VIDMODE
> +#include <X11/extensions/xf86vmode.h>
> +#endif
> +#include <X11/xshmfence.h>
> +#include <xcb/xcb.h>
> +#include <xcb/dri3.h>
> +#include <xcb/present.h>
> +#include <xf86drm.h>
> +
> +#include "egl_dri2.h"
> +#include "egl_dri2_fallbacks.h"
> +#include "platform_x11_dri3.h"
> +
> +#include "loader.h"
> +
> +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 void
> +dri3_update_num_back(struct dri3_egl_surface *dri3_surf)
> +{
> +   dri3_surf->num_back = 1;
> +   if (dri3_surf->flipping) {
> +      if (!dri3_surf->is_pixmap && !(dri3_surf->present_capabilities & XCB_PRESENT_CAPABILITY_ASYNC))
> +         dri3_surf->num_back++;
> +      dri3_surf->num_back++;
> +   }
> +   if (dri3_surf->base.SwapInterval == 0)
> +      dri3_surf->num_back++;
> +}
> +
> +/** dri3_free_render_buffer
> + *
> + * Free everything associated with one render buffer including pixmap, fence
> + * stuff and the driver image
> + */
> +static void
> +dri3_free_render_buffer(struct dri2_egl_display *dri2_dpy,
> +                        struct dri3_egl_surface *dri3_surf,
> +                        struct dri3_buffer *buffer)
> +{
> +   if (buffer->own_pixmap)
> +      xcb_free_pixmap(dri2_dpy->conn, buffer->pixmap);
> +   xcb_sync_destroy_fence(dri2_dpy->conn, buffer->sync_fence);
> +   xshmfence_unmap_shm(buffer->shm_fence);
> +   (*dri2_dpy->image->destroyImage)(buffer->image);
> +   if (buffer->linear_buffer)
> +      (*dri2_dpy->image->destroyImage)(buffer->linear_buffer);
> +   free(buffer);
> +}
> +
> +static EGLBoolean
> +dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
> +{
> +   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +   int i;
> +
> +   (void) drv;
> +
> +   if (!_eglPutSurface(surf))
> +      return EGL_TRUE;
> +
> +   (*dri2_dpy->core->destroyDrawable) (dri3_surf->dri_drawable);
> +
> +   for (i = 0; i < DRI3_NUM_BUFFERS; i++) {
> +      if (dri3_surf->buffers[i])
> +         dri3_free_render_buffer(dri2_dpy, dri3_surf, dri3_surf->buffers[i]);
> +   }
> +
> +   if (dri3_surf->special_event)
> +      xcb_unregister_for_special_event(dri2_dpy->conn, dri3_surf->special_event);
> +   free(surf);
> +
> +   return EGL_TRUE;
> +}
> +
> +static EGLBoolean
> +dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
> +                       EGLint interval)
> +{
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +
> +   if (interval > surf->Config->MaxSwapInterval)
> +      interval = surf->Config->MaxSwapInterval;
> +   else if (interval < surf->Config->MinSwapInterval)
> +      interval = surf->Config->MinSwapInterval;
> +
> +   dri3_surf->base.SwapInterval = interval;
> +   dri3_update_num_back(dri3_surf);
> +
> +   return EGL_TRUE;
> +}
> +
> +static xcb_screen_t *
> +get_xcb_screen(xcb_screen_iterator_t iter, int screen)
> +{
> +    for (; iter.rem; --screen, xcb_screen_next(&iter))
> +        if (screen == 0)
> +            return iter.data;
> +
> +    return NULL;
> +}
> +
> +/* xDrawable in glx maps to drawable here */
> +static _EGLSurface *
> +dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
> +                    _EGLConfig *conf, void *native_surface,
> +                    const EGLint *attrib_list)
> +{
> +   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> +   struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
> +   struct dri3_egl_surface *dri3_surf;
> +   xcb_drawable_t drawable;
> +   xcb_get_geometry_cookie_t cookie;
> +   xcb_get_geometry_reply_t *reply;
> +   xcb_screen_iterator_t s;
> +   xcb_generic_error_t *error;
> +   xcb_screen_t *screen;
> +   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
> +
> +   STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
> +   drawable = (uintptr_t) native_surface;
> +
> +   (void) drv;
> +
> +   dri3_surf = calloc(1, sizeof *dri3_surf);
> +   if (!dri3_surf) {
> +      _eglError(EGL_BAD_ALLOC, "dri3_create_surface");
> +      return NULL;
> +   }
> +
> +   if (!_eglInitSurface(&dri3_surf->base, disp, type, conf, attrib_list))
> +      goto cleanup_surf;
> +
> +   if (type == EGL_PBUFFER_BIT) {
> +      s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
> +      screen = get_xcb_screen(s, dri2_dpy->screen);
> +      if (!screen) {
> +         _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_create_surface");
> +         goto cleanup_surf;
> +      }
> +
> +      dri3_surf->drawable = xcb_generate_id(dri2_dpy->conn);
> +      xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
> +                        dri3_surf->drawable, screen->root,
> +                        dri3_surf->base.Width, dri3_surf->base.Height);
> +   } else {
> +      dri3_surf->drawable = drawable;
> +   }
> +
> +   dri3_surf->base.SwapInterval = 1; /* default may be overridden below */
> +   dri3_surf->have_back = 0;
> +   dri3_surf->have_fake_front = 0;
> +   dri3_surf->first_init = true;
> +
> +   if (dri2_dpy->config)
> +      dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
> +                                "vblank_mode", &vblank_mode);
> +
> +   switch (vblank_mode) {
> +   case DRI_CONF_VBLANK_NEVER:
> +   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
> +      dri3_surf->base.SwapInterval = 0;
> +      break;
> +   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
> +   case DRI_CONF_VBLANK_ALWAYS_SYNC:
> +   default:
> +      dri3_surf->base.SwapInterval = 1;
> +      break;
> +   }
> +
> +   dri3_update_num_back(dri3_surf);
> +
> +   /* Create a new drawable */
> +   dri3_surf->dri_drawable =
> +      (*dri2_dpy->image_driver->createNewDrawable) (dri2_dpy->dri_screen,
> +                                                    type == EGL_WINDOW_BIT ?
> +                                                    dri2_conf->dri_double_config :
> +                                                    dri2_conf->dri_single_config,
> +                                                    dri3_surf);
> +
> +   if (!dri3_surf->dri_drawable) {
> +      _eglError(EGL_BAD_ALLOC, "dri3->createNewDrawable");
> +      goto cleanup_pixmap;
> +   }
> +
> +   if (type != EGL_PBUFFER_BIT) {
> +      cookie = xcb_get_geometry (dri2_dpy->conn, dri3_surf->drawable);
> +      reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
> +      if (reply == NULL || error != NULL) {
> +	 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
> +	 free(error);
> +	 goto cleanup_dri_drawable;
> +      }
> +
> +      dri3_surf->base.Width = reply->width;
> +      dri3_surf->base.Height = reply->height;
> +      dri3_surf->depth = reply->depth;
> +      free(reply);
> +   }
> +
> +   /*
> +    * Make sure server has the same swap interval we do for the new
> +    * drawable.
> +    */
> +   dri3_set_swap_interval(drv, disp, &dri3_surf->base,
> +                          dri3_surf->base.SwapInterval);
> +
> +   return &dri3_surf->base;
> +
> + cleanup_dri_drawable:
> +   dri2_dpy->core->destroyDrawable(dri3_surf->dri_drawable);
> + cleanup_pixmap:
> +   if (type == EGL_PBUFFER_BIT)
> +      xcb_free_pixmap(dri2_dpy->conn, dri3_surf->drawable);
> + cleanup_surf:
> +   free(dri3_surf);
> +
> +   return NULL;
> +}
> +
> +/**
> + * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
> + */
> +static _EGLSurface *
> +dri3_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
> +                           _EGLConfig *conf, void *native_window,
> +                           const EGLint *attrib_list)
> +{
> +   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> +   _EGLSurface *surf;
> +
> +   surf = dri3_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
> +                              native_window, attrib_list);
> +   if (surf != NULL)
> +      dri3_set_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
> +
> +   return surf;
> +}
> +
> +static _EGLSurface *
> +dri3_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
> +                           _EGLConfig *conf, void *native_pixmap,
> +                           const EGLint *attrib_list)
> +{
> +   return dri3_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
> +                              native_pixmap, attrib_list);
> +}
> +
> +static _EGLSurface *
> +dri3_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
> +                                _EGLConfig *conf, const EGLint *attrib_list)
> +{
> +   return dri3_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
> +                              XCB_WINDOW_NONE, attrib_list);
> +}
> +
> +/*
> + * Process one Present event
> + */
> +static void
> +dri3_handle_present_event(struct dri2_egl_display *dri2_dpy,
> +                          struct dri3_egl_surface *dri3_surf,
> +                          xcb_present_generic_event_t *ge)
> +{
> +   switch (ge->evtype) {
> +   case XCB_PRESENT_CONFIGURE_NOTIFY: {
> +      xcb_present_configure_notify_event_t *ce = (void *) ge;
> +
> +      dri3_surf->base.Width = ce->width;
> +      dri3_surf->base.Height = ce->height;
> +      break;
> +   }
> +   case XCB_PRESENT_COMPLETE_NOTIFY: {
> +      xcb_present_complete_notify_event_t *ce = (void *) ge;
> +
> +      /* Compute the processed SBC number from the received 32-bit serial number merged
> +       * with the upper 32-bits of the sent 64-bit serial number while checking for
> +       * wrap
> +       */
> +      if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
> +         dri3_surf->recv_sbc = (dri3_surf->send_sbc & 0xffffffff00000000LL) | ce->serial;
> +         if (dri3_surf->recv_sbc > dri3_surf->send_sbc)
> +            dri3_surf->recv_sbc -= 0x100000000;
> +         switch (ce->mode) {
> +         case XCB_PRESENT_COMPLETE_MODE_FLIP:
> +            dri3_surf->flipping = true;
> +            break;
> +         case XCB_PRESENT_COMPLETE_MODE_COPY:
> +            dri3_surf->flipping = false;
> +            break;
> +         }
> +         dri3_update_num_back(dri3_surf);
> +
> +         /*
> +         if (psc->show_fps_interval)
> +            show_fps(priv, ce->ust); */
> +
> +         dri3_surf->ust = ce->ust;
> +         dri3_surf->msc = ce->msc;
> +      } else {
> +         dri3_surf->recv_msc_serial = ce->serial;
> +         dri3_surf->notify_ust = ce->ust;
> +         dri3_surf->notify_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 (dri3_surf->buffers) / sizeof (dri3_surf->buffers[0]); b++) {
> +         struct dri3_buffer *buf = dri3_surf->buffers[b];
> +
> +         if (buf && buf->pixmap == ie->pixmap) {
> +            buf->busy = 0;
> +            if (dri3_surf->num_back <= b && b < DRI3_MAX_BACK) {
> +               dri3_free_render_buffer(dri2_dpy, dri3_surf, buf);
> +               dri3_surf->buffers[b] = NULL;
> +            }
> +            break;
> +         }
> +      }
> +      break;
> +   }
> +   }
> +   free(ge);
> +}
> +
> +static bool
> +dri3_wait_for_event(struct dri2_egl_display *dri2_dpy,
> +                    struct dri3_egl_surface *dri3_surf)
> +{
> +   xcb_generic_event_t *ev;
> +   xcb_present_generic_event_t *ge;
> +
> +   xcb_flush(dri2_dpy->conn);
> +   ev = xcb_wait_for_special_event(dri2_dpy->conn, dri3_surf->special_event);
> +   if (!ev)
> +      return false;
> +   ge = (void *) ev;
> +   dri3_handle_present_event(dri2_dpy, dri3_surf, ge);
> +   return true;
> +}
> +
> +/** dri3_wait_for_msc
> + *
> + * Get the X server to send an event when the target msc/divisor/remainder is
> + * reached.
> + */
> +static EGLBoolean
> +dri3_wait_for_msc(struct dri2_egl_display *dri2_dpy,
> +                  struct dri3_egl_surface *dri3_surf,
> +                  int64_t target_msc, int64_t divisor, int64_t remainder,
> +                  int64_t *ust, int64_t *msc, int64_t *sbc)
> +{
> +   uint32_t msc_serial;
> +
> +   msc_serial = ++dri3_surf->send_msc_serial;
> +   xcb_present_notify_msc(dri2_dpy->conn,
> +                          dri3_surf->drawable,
> +                          msc_serial,
> +                          target_msc,
> +                          divisor,
> +                          remainder);
> +
> +   xcb_flush(dri2_dpy->conn);
> +
> +   /* Wait for the event */
> +   if (dri3_surf->special_event) {
> +      while ((int32_t) (msc_serial - dri3_surf->recv_msc_serial) > 0) {
> +         if (!dri3_wait_for_event(dri2_dpy, dri3_surf))
> +            return EGL_FALSE;
> +      }
> +   }
> +
> +   *ust = dri3_surf->notify_ust;
> +   *msc = dri3_surf->notify_msc;
> +   *sbc = dri3_surf->recv_sbc;
> +
> +   return EGL_TRUE;
> +}
> +
> +static EGLBoolean
> +dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
> +                     EGLuint64KHR *ust, EGLuint64KHR *msc,
> +                     EGLuint64KHR *sbc)
> +{
> +   struct dri2_egl_display *dri2_dpy = dri2_egl_display(display);
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
> +
> +   return dri3_wait_for_msc(dri2_dpy, dri3_surf, 0, 0, 0, ust, msc, sbc);
> +}
> +
> +/**
> + * 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 dri2_egl_display *dri2_dpy,
> +           struct dri3_egl_surface *dri3_surf,
> +           unsigned flags,
> +           enum __DRI2throttleReason throttle_reason)
> +{
> +   _EGLContext *ctx = _eglGetCurrentContext();
> +   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
> +
> +   if (dri2_ctx)
> +      (*dri2_dpy->flush->flush_with_flags)(dri2_ctx->dri_context,
> +                                           dri3_surf->dri_drawable,
> +                                           flags, throttle_reason);
> +}
> +
> +static xcb_gcontext_t
> +dri3_drawable_gc(struct dri2_egl_display *dri2_dpy,
> +                 struct dri3_egl_surface *dri3_surf)
> +{
> +   if (!dri3_surf->gc) {
> +      uint32_t v = 0;
> +      xcb_create_gc(dri2_dpy->conn,
> +                    (dri3_surf->gc = xcb_generate_id(dri2_dpy->conn)),
> +                    dri3_surf->drawable,
> +                    XCB_GC_GRAPHICS_EXPOSURES,
> +                    &v);
> +   }
> +   return dri3_surf->gc;
> +}
> +
> +
> +static struct dri3_buffer *
> +dri3_back_buffer(struct dri3_egl_surface *dri3_surf)
> +{
> +   return dri3_surf->buffers[DRI3_BACK_ID(dri3_surf->cur_back)];
> +}
> +
> +static struct dri3_buffer *
> +dri3_fake_front_buffer(struct dri3_egl_surface *dri3_surf)
> +{
> +   return dri3_surf->buffers[DRI3_FRONT_ID];
> +}
> +
> +static void
> +dri3_copy_area (xcb_connection_t *c  /**< */,
Please, no space between function name and opening bracket.

> +                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  /**< */)
Add some comments or just drop the "/**< */"s ?

> +{
> +   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);
> +}
> +
> +/**
> + * 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)
> +{
> +#if 0
> +   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_flush(psc, pdraw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT);
> +
> +   dri3_wait_gl(gc);
> +#endif
> +   /* FIXME */
> +   (void) driDrawable;
> +   (void) loaderPrivate;
If we don't get to fixing this now, providing some feedback
(printf(foo)) would be appreciated. Same goes for other stubbed functions.

> +}
> +
> +static uint32_t
> +dri3_cpp_for_format(uint32_t format) {
> +   switch (format) {
> +   case  __DRI_IMAGE_FORMAT_R8:
> +      return 1;
> +   case  __DRI_IMAGE_FORMAT_RGB565:
> +   case  __DRI_IMAGE_FORMAT_GR88:
> +      return 2;
> +   case  __DRI_IMAGE_FORMAT_XRGB8888:
> +   case  __DRI_IMAGE_FORMAT_ARGB8888:
> +   case  __DRI_IMAGE_FORMAT_ABGR8888:
> +   case  __DRI_IMAGE_FORMAT_XBGR8888:
> +   case  __DRI_IMAGE_FORMAT_XRGB2101010:
> +   case  __DRI_IMAGE_FORMAT_ARGB2101010:
> +   case  __DRI_IMAGE_FORMAT_SARGB8:
> +      return 4;
> +   case  __DRI_IMAGE_FORMAT_NONE:
> +   default:
> +      return 0;
> +   }
> +}
> +
> +/** dri3_alloc_render_buffer
> + *
> + * Use the driver createImage function to construct a __DRIimage, then
> + * get a file descriptor for that and create an X pixmap from that
> + *
> + * Allocate an xshmfence for synchronization
> + */
> +static struct dri3_buffer *
> +dri3_alloc_render_buffer(struct dri2_egl_display *dri2_dpy, xcb_drawable_t draw,
> +                         unsigned int format, int width, int height, int depth)
> +{
> +   struct dri3_buffer *buffer;
> +   __DRIimage *pixmap_buffer;
> +   xcb_pixmap_t pixmap;
> +   xcb_sync_fence_t sync_fence;
> +   struct xshmfence *shm_fence;
> +   int buffer_fd, fence_fd;
> +   int stride;
> +
> +   /* Create an xshmfence object and
> +    * prepare to send that to the X server
> +    */
> +
> +   fence_fd = xshmfence_alloc_shm();
> +   if (fence_fd < 0) {
> +      _eglLog(_EGL_WARNING, "DRI3 Fence object allocation failure %s\n", strerror(errno));
> +      return NULL;
> +   }
> +   shm_fence = xshmfence_map_shm(fence_fd);
> +   if (shm_fence == NULL) {
> +      _eglLog(_EGL_WARNING, "DRI3 Fence object map failure %s\n", strerror(errno));
> +      goto no_shm_fence;
> +   }
> +
> +   /* Allocate the image from the driver
> +    */
> +   buffer = calloc(1, sizeof (struct dri3_buffer));
> +   if (!buffer)
> +      goto no_buffer;
> +
> +   buffer->cpp = dri3_cpp_for_format(format);
> +   if (!buffer->cpp) {
> +      _eglLog(_EGL_WARNING, "DRI3 buffer format %d invalid\n", format);
> +      goto no_image;
> +   }
> +
> +   if (!dri2_dpy->is_different_gpu) {
> +      buffer->image = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen,
> +                                                       width, height,
> +                                                       format,
> +                                                       __DRI_IMAGE_USE_SHARE |
> +                                                       __DRI_IMAGE_USE_SCANOUT,
> +                                                       buffer);
> +      pixmap_buffer = buffer->image;
> +
> +      if (!buffer->image) {
> +         _eglLog(_EGL_WARNING, "DRI3 gpu image creation failure\n");
> +         goto no_image;
> +      }
> +   } else {
> +      buffer->image = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen,
> +                                                       width, height,
> +                                                       format,
> +                                                       0,
> +                                                       buffer);
> +
> +      if (!buffer->image) {
> +         _eglLog(_EGL_WARNING, "DRI3 other gpu image creation failure\n");
> +         goto no_image;
> +      }
> +
> +      buffer->linear_buffer = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen,
> +                                                               width, height,
> +                                                               format,
> +                                                               __DRI_IMAGE_USE_SHARE |
> +                                                               __DRI_IMAGE_USE_LINEAR,
> +                                                               buffer);
> +      pixmap_buffer = buffer->linear_buffer;
> +
> +      if (!buffer->linear_buffer) {
> +         _eglLog(_EGL_WARNING, "DRI3 gpu linear image creation failure\n");
> +         goto no_linear_buffer;
> +      }
> +   }
> +
> +   /* X wants the stride, so ask the image for it
> +    */
> +   if (!(*dri2_dpy->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE, &stride)) {
> +      _eglLog(_EGL_WARNING, "DRI3 get image stride failed\n");
> +      goto no_buffer_attrib;
> +   }
> +
> +   buffer->pitch = stride;
> +
> +   if (!(*dri2_dpy->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD, &buffer_fd)) {
> +      _eglLog(_EGL_WARNING, "DRI3 get image FD failed\n");
> +      goto no_buffer_attrib;
> +   }
> +
> +   xcb_dri3_pixmap_from_buffer(dri2_dpy->conn,
> +                               (pixmap = xcb_generate_id(dri2_dpy->conn)),
> +                               draw,
> +                               buffer->size,
> +                               width, height, buffer->pitch,
> +                               depth, buffer->cpp * 8,
> +                               buffer_fd);
> +
> +   xcb_dri3_fence_from_fd(dri2_dpy->conn,
> +                          pixmap,
> +                          (sync_fence = xcb_generate_id(dri2_dpy->conn)),
> +                          false,
> +                          fence_fd);
> +
> +   buffer->pixmap = pixmap;
> +   buffer->own_pixmap = true;
> +   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:
> +   (*dri2_dpy->image->destroyImage)(pixmap_buffer);
> +no_linear_buffer:
> +   if (dri2_dpy->is_different_gpu)
> +      (*dri2_dpy->image->destroyImage)(buffer->image);
> +no_image:
> +   free(buffer);
> +no_buffer:
> +   xshmfence_unmap_shm(shm_fence);
> +no_shm_fence:
> +   close(fence_fd);
> +   _eglLog(_EGL_WARNING, "DRI3 alloc_render_buffer failed\n");
> +   return NULL;
> +}
> +
> +/** dri3_flush_present_events
> + *
> + * Process any present events that have been received from the X server
> + */
> +static void
> +dri3_flush_present_events(struct dri2_egl_display *dri2_dpy,
> +                          struct dri3_egl_surface *dri3_surf)
> +{
> +   /* Check to see if any configuration changes have occurred
> +    * since we were last invoked
> +    */
> +   if (dri3_surf->special_event) {
> +      xcb_generic_event_t    *ev;
> +
> +      while ((ev = xcb_poll_for_special_event(dri2_dpy->conn,
> +                                              dri3_surf->special_event)) != NULL) {
> +         xcb_present_generic_event_t *ge = (void *) ev;
> +         dri3_handle_present_event(dri2_dpy, dri3_surf, ge);
> +      }
> +   }
> +}
> +
> +/** dri3_update_drawable
> + *
> + * Called the first time we use the drawable and then
> + * after we receive present configure notify events to
> + * track the geometry of the drawable
> + */
> +static int
> +dri3_update_drawable(__DRIdrawable *driDrawable,
> +                     struct dri3_egl_surface *dri3_surf,
> +                     struct dri2_egl_display *dri2_dpy)
> +{
> +   /* First time through, go get the current drawable geometry
> +    */
> +   if (dri3_surf->first_init) {
> +      xcb_void_cookie_t                         cookie;
> +      xcb_generic_error_t                       *error;
> +      xcb_present_query_capabilities_cookie_t   present_capabilities_cookie;
> +      xcb_present_query_capabilities_reply_t    *present_capabilities_reply;
> +
> +      dri3_surf->first_init = false;
> +
> +      /* Try to select for input on the window.
> +       *
> +       * If the drawable is a window, this will get our events
> +       * delivered.
> +       *
> +       * Otherwise, we'll get a BadWindow error back from this request which
> +       * will let us know that the drawable is a pixmap instead.
> +       */
> +
> +
> +      cookie = xcb_present_select_input_checked(dri2_dpy->conn,
> +                                                (dri3_surf->eid = xcb_generate_id(dri2_dpy->conn)),
> +                                                dri3_surf->drawable,
> +                                                XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY|
> +                                                XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|
> +                                                XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
> +
> +      present_capabilities_cookie = xcb_present_query_capabilities(dri2_dpy->conn,
> +                                                                   dri3_surf->drawable);
> +
> +      /* Create an XCB event queue to hold present events outside of the usual
> +       * application event queue
> +       */
> +      dri3_surf->special_event = xcb_register_for_special_xge(dri2_dpy->conn,
> +                                                              &xcb_present_id,
> +                                                              dri3_surf->eid,
> +                                                              dri3_surf->stamp);
> +
> +      dri3_surf->is_pixmap = false;
> +
> +      /* Check to see if our select input call failed. If it failed with a
> +       * BadWindow error, then assume the drawable is a pixmap. Destroy the
> +       * special event queue created above and mark the drawable as a pixmap
> +       */
> +
> +      error = xcb_request_check(dri2_dpy->conn, cookie);
> +
> +      present_capabilities_reply = xcb_present_query_capabilities_reply(dri2_dpy->conn,
> +                                                                        present_capabilities_cookie,
> +                                                                        NULL);
> +
> +      if (present_capabilities_reply) {
> +         dri3_surf->present_capabilities = present_capabilities_reply->capabilities;
> +         free(present_capabilities_reply);
> +      } else
> +         dri3_surf->present_capabilities = 0;
> +
> +      if (error) {
> +         if (error->error_code != BadWindow) {
> +            free(error);
> +            return false;
> +         }
> +         dri3_surf->is_pixmap = true;
> +         xcb_unregister_for_special_event(dri2_dpy->conn, dri3_surf->special_event);
> +         dri3_surf->special_event = NULL;
> +      }
> +   }
> +   dri3_flush_present_events(dri2_dpy, dri3_surf);
> +   return true;
> +}
> +
> +/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
> + * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
> + * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
> + * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds
> + */
> +static int
> +image_format_to_fourcc(int format)
> +{
> +
> +   /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
> +   switch (format) {
> +   case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;
> +   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;
> +   }
> +   return 0;
> +}
> +
> +/** dri3_get_pixmap_buffer
> + *
> + * Get the DRM object for a pixmap from the X server and
> + * wrap that with a __DRIimage structure using createImageFromFds
> + */
> +static struct dri3_buffer *
> +dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,
> +                       unsigned int format,
> +                       enum dri3_buffer_type buffer_type,
> +                       struct dri3_egl_surface *dri3_surf,
> +                       struct dri2_egl_display *dri2_dpy)
> +{
> +   int                                  buf_id = dri3_pixmap_buf_id(buffer_type);
> +   struct dri3_buffer                   *buffer = dri3_surf->buffers[buf_id];
> +   xcb_drawable_t                       pixmap;
> +   xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
> +   xcb_dri3_buffer_from_pixmap_reply_t  *bp_reply;
> +   int                                  *fds;
> +   xcb_sync_fence_t                     sync_fence;
> +   struct xshmfence                     *shm_fence;
> +   int                                  fence_fd;
> +   __DRIimage                           *image_planar;
> +   int                                  stride, offset;
> +
> +   if (buffer)
> +      return buffer;
> +
> +   pixmap = dri3_surf->drawable;
> +
> +   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(dri2_dpy->conn,
> +                          pixmap,
> +                          (sync_fence = xcb_generate_id(dri2_dpy->conn)),
> +                          false,
> +                          fence_fd);
> +
> +   /* Get an FD for the pixmap object
> +    */
> +   bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, pixmap);
> +   bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,
> +                                                bp_cookie, NULL);
> +   if (!bp_reply)
> +      goto no_image;
> +   fds = xcb_dri3_buffer_from_pixmap_reply_fds(dri2_dpy->conn, bp_reply);
> +
> +   stride = bp_reply->stride;
> +   offset = 0;
> +
> +   /* createImageFromFds creates a wrapper __DRIimage structure which
> +    * can deal with multiple planes for things like Yuv images. So, once
> +    * we've gotten the planar wrapper, pull the single plane out of it and
> +    * discard the wrapper.
> +    */
> +   image_planar = (*dri2_dpy->image->createImageFromFds) (dri2_dpy->dri_screen,
> +                                                          bp_reply->width,
> +                                                          bp_reply->height,
> +                                                          image_format_to_fourcc(format),
> +                                                          fds, 1,
> +                                                          &stride, &offset, buffer);
> +   close(fds[0]);
> +   if (!image_planar)
> +      goto no_image;
> +
> +   buffer->image = (*dri2_dpy->image->fromPlanar)(image_planar, 0, buffer);
> +
> +   (*dri2_dpy->image->destroyImage)(image_planar);
> +
> +   if (!buffer->image)
> +      goto no_image;
> +
> +   buffer->pixmap = pixmap;
> +   buffer->own_pixmap = false;
> +   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;
> +
> +   dri3_surf->buffers[buf_id] = buffer;
> +   return buffer;
> +
> +no_image:
> +   xcb_sync_destroy_fence(dri2_dpy->conn, sync_fence);
> +   xshmfence_unmap_shm(shm_fence);
> +no_fence:
> +   free(buffer);
> +no_buffer:
> +   return NULL;
> +}
> +
> +/** dri3_find_back
> + *
> + * Find an idle back buffer. If there isn't one, then
> + * wait for a present idle notify event from the X server
> + */
> +static int
> +dri3_find_back(struct dri2_egl_display *dri2_dpy,
> +               struct dri3_egl_surface *dri3_surf)
> +{
> +   int  b;
> +   xcb_generic_event_t *ev;
> +   xcb_present_generic_event_t *ge;
> +
> +   for (;;) {
> +      for (b = 0; b < dri3_surf->num_back; b++) {
> +         int id = DRI3_BACK_ID((b + dri3_surf->cur_back) % dri3_surf->num_back);
> +         struct dri3_buffer *buffer = dri3_surf->buffers[id];
> +
> +         if (!buffer || !buffer->busy) {
> +            dri3_surf->cur_back = id;
> +            return id;
> +         }
> +      }
> +      xcb_flush(dri2_dpy->conn);
> +      ev = xcb_wait_for_special_event(dri2_dpy->conn, dri3_surf->special_event);
> +      if (!ev)
> +         return -1;
> +      ge = (void *) ev;
> +      dri3_handle_present_event(dri2_dpy, dri3_surf, ge);
> +   }
> +}
> +
> +/** dri3_get_buffer
> + *
> + * Find a front or back buffer, allocating new ones as necessary
> + */
> +static struct dri3_buffer *
> +dri3_get_buffer(__DRIdrawable *driDrawable,
> +                unsigned int format,
> +                enum dri3_buffer_type buffer_type,
> +                struct dri3_egl_surface *dri3_surf,
> +                struct dri2_egl_display *dri2_dpy)
> +{
> +   struct dri3_buffer      *buffer;
> +   _EGLContext *ctx = _eglGetCurrentContext();
> +   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
> +   int                  buf_id;
> +
> +   if (buffer_type == dri3_buffer_back) {
> +      buf_id = dri3_find_back(dri2_dpy, dri3_surf);
> +
> +      if (buf_id < 0)
> +         return NULL;
> +   } else {
> +      buf_id = DRI3_FRONT_ID;
> +   }
> +
> +   buffer = dri3_surf->buffers[buf_id];
> +
> +   /* Allocate a new buffer if there isn't an old one, or if that
> +    * old one is the wrong size
> +    */
> +   if (!buffer || buffer->width != dri3_surf->base.Width ||
> +       buffer->height != dri3_surf->base.Height) {
> +      struct dri3_buffer   *new_buffer;
> +
> +      /* Allocate the new buffers
> +       */
> +      new_buffer = dri3_alloc_render_buffer(dri2_dpy,
> +                                            dri3_surf->drawable,
> +                                            format,
> +                                            dri3_surf->base.Width,
> +                                            dri3_surf->base.Height,
> +                                            dri3_surf->depth);
> +      if (!new_buffer)
> +         return NULL;
> +
> +      /* When resizing, copy the contents of the old buffer, waiting for that
> +       * copy to complete using our fences before proceeding
> +       */
> +      switch (buffer_type) {
> +      case dri3_buffer_back:
> +         if (buffer) {
> +            if (!buffer->linear_buffer) {
> +               dri3_fence_reset(dri2_dpy->conn, new_buffer);
> +               dri3_fence_await(dri2_dpy->conn, buffer);
> +               dri3_copy_area(dri2_dpy->conn,
> +                              buffer->pixmap,
> +                              new_buffer->pixmap,
> +                              dri3_drawable_gc(dri2_dpy, dri3_surf),
> +                              0, 0, 0, 0,
> +                              dri3_surf->base.Width,
> +                              dri3_surf->base.Height);
> +            dri3_fence_trigger(dri2_dpy->conn, new_buffer);
> +            } else if (dri2_ctx->base.Resource.Display == dri3_surf->base.Resource.Display) {
> +               dri2_dpy->image->blitImage(dri2_ctx->dri_context,
> +                                         new_buffer->image,
> +                                         buffer->image,
> +                                         0, 0, dri3_surf->base.Width,
> +                                         dri3_surf->base.Height,
> +                                         0, 0, dri3_surf->base.Width,
> +                                         dri3_surf->base.Height, 0);
> +            }
> +            dri3_free_render_buffer(dri2_dpy, dri3_surf, buffer);
> +         }
> +         break;
> +      case dri3_buffer_front:
> +         dri3_fence_reset(dri2_dpy->conn, new_buffer);
> +         dri3_copy_area(dri2_dpy->conn,
> +                        dri3_surf->drawable,
> +                        new_buffer->pixmap,
> +                        dri3_drawable_gc(dri2_dpy, dri3_surf),
> +                        0, 0, 0, 0,
> +                        dri3_surf->base.Width,
> +                        dri3_surf->base.Height);
> +         dri3_fence_trigger(dri2_dpy->conn, new_buffer);
> +
> +         if (new_buffer->linear_buffer &&
> +             dri2_ctx->base.Resource.Display == dri3_surf->base.Resource.Display) {
> +            dri3_fence_await(dri2_dpy->conn, new_buffer);
> +            dri2_dpy->image->blitImage(dri2_ctx->dri_context,
> +                                       new_buffer->image,
> +                                       new_buffer->linear_buffer,
> +                                       0, 0, dri3_surf->base.Width,
> +                                       dri3_surf->base.Height,
> +                                       0, 0, dri3_surf->base.Width,
> +                                       dri3_surf->base.Height, 0);
> +         }
> +         break;
> +      }
> +      buffer = new_buffer;
> +      buffer->buffer_type = buffer_type;
> +      dri3_surf->buffers[buf_id] = buffer;
> +   }
> +   dri3_fence_await(dri2_dpy->conn, buffer);
> +
> +   /* Return the requested buffer */
> +   return buffer;
> +}
> +
> +/** dri3_free_buffers
> + *
> + * Free the front bufffer or all of the back buffers. Used
> + * when the application changes which buffers it needs
> + */
> +static void
> +dri3_free_buffers(__DRIdrawable *driDrawable,
> +                  enum dri3_buffer_type buffer_type,
> +                  struct dri3_egl_surface *dri3_surf,
> +                  struct dri2_egl_display *dri2_dpy)
> +{
> +   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 = dri3_surf->buffers[buf_id];
> +      if (buffer) {
> +         dri3_free_render_buffer(dri2_dpy, dri3_surf, buffer);
> +         dri3_surf->buffers[buf_id] = NULL;
> +      }
> +   }
> +}
> +
> +/** dri3_get_buffers
> + *
> + * The published buffer allocation API.
> + * Returns all of the necessary buffers, allocating
> + * as needed.
> + */
> +static int
> +dri3_get_buffers(__DRIdrawable *driDrawable,
> +                 unsigned int format,
> +                 uint32_t *stamp,
> +                 void *loaderPrivate,
> +                 uint32_t buffer_mask,
> +                 struct __DRIimageList *buffers)
> +{
> +   struct dri3_egl_surface *dri3_surf = loaderPrivate;
> +   struct dri2_egl_display *dri2_dpy =
> +      dri2_egl_display(dri3_surf->base.Resource.Display);
> +   struct dri3_buffer   *front, *back;
> +
> +   buffers->image_mask = 0;
> +   buffers->front = NULL;
> +   buffers->back = NULL;
> +
> +   front = NULL;
> +   back = NULL;
> +
> +   if (!dri3_update_drawable(driDrawable, dri3_surf, dri2_dpy))
> +      return false;
> +
> +   /* pixmaps always have front buffers */
> +   if (dri3_surf->is_pixmap)
> +      buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
> +
> +   if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
> +      /* All pixmaps are owned by the server gpu.
> +       * When we use a different gpu, we can't use the pixmap
> +       * as buffer since it is potentially tiled a way
> +       * our device can't understand. In this case, use
> +       * a fake front buffer. Hopefully the pixmap
> +       * content will get synced with the fake front
> +       * buffer.
> +       */
> +      if (dri3_surf->is_pixmap && !dri2_dpy->is_different_gpu)
> +         front = dri3_get_pixmap_buffer(driDrawable,
> +                                        format,
> +                                        dri3_buffer_front,
> +                                        dri3_surf,
> +                                        dri2_dpy);
> +      else
> +         front = dri3_get_buffer(driDrawable,
> +                                 format,
> +                                 dri3_buffer_front,
> +                                 dri3_surf,
> +                                 dri2_dpy);
> +
> +      if (!front)
> +         return false;
> +   } else {
> +      dri3_free_buffers(driDrawable, dri3_buffer_front, dri3_surf, dri2_dpy);
> +      dri3_surf->have_fake_front = 0;
> +   }
> +
> +   if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
> +      back = dri3_get_buffer(driDrawable,
> +                             format,
> +                             dri3_buffer_back,
> +                             dri3_surf,
> +                             dri2_dpy);
> +      if (!back)
> +         return false;
> +      dri3_surf->have_back = 1;
> +   } else {
> +      dri3_free_buffers(driDrawable, dri3_buffer_back, dri3_surf, dri2_dpy);
> +      dri3_surf->have_back = 0;
> +   }
> +
> +   if (front) {
> +      buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
> +      buffers->front = front->image;
> +      dri3_surf->have_fake_front = dri2_dpy->is_different_gpu || !dri3_surf->is_pixmap;
> +   }
> +
> +   if (back) {
> +      buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK;
> +      buffers->back = back->image;
> +   }
> +
> +   dri3_surf->stamp = stamp;
> +
> +   return true;
> +}
> +
> +const __DRIimageLoaderExtension dri3_image_loader_extension = {
> +   .base = { __DRI_IMAGE_LOADER, 1 },
> +
> +   .getBuffers          = dri3_get_buffers,
> +   .flushFrontBuffer    = dri3_flush_front_buffer,
> +};
> +
> +static int
> +dri3_get_ust(int64_t *ust)
> +{
> +   struct timeval tv;
> +
> +   if (ust == NULL)
> +      return -EFAULT;
> +
> +   if (gettimeofday(&tv, NULL) == 0) {
> +      ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
> +      return 0;
> +   } else
> +      return -errno;
> +}
> +
> +static GLboolean
> +dri3_get_msc_rate(__DRIdrawable *draw, int32_t *numerator,
> +                  int32_t *denominator, void *loaderPrivate)
> +{
> +#ifdef XF86VIDMODE
> +   dri3_egl_surface *dri3_surf = loaderPrivate;
> +   struct dri2_egl_display *dri2_dpy =
> +      dri2_egl_display(dri3_surf->base.Resource.Display);
> +   XF86VidModeModeLine mode_line;
> +   int dot_clock;
> +   int i;
> +
> +   if (XF86VidModeQueryVersion(dri2_dpy->dpy, &i, &i) &&
> +       XF86VidModeGetModeLine(dri2_dpy->dpy, dri2_dpy->screen,
> +                              &dot_clock, &mode_line)) {
> +      unsigned n = dot_clock * 1000;
> +      unsigned d = mode_line.vtotal * mode_line.htotal;
> +
> +# define V_INTERLACE 0x010
> +# define V_DBLSCAN   0x020
> +
> +      if (mode_line.flags & V_INTERLACE)
> +         n *= 2;
> +      else if (mode_line.flags & V_DBLSCAN)
> +         d *= 2;
> +
> +      /* The OML_sync_control spec requires that if the refresh rate is a
> +       * whole number, that the returned numerator be equal to the refresh
> +       * rate and the denominator be 1.
> +       */
> +
> +      if (n % d == 0) {
> +         n /= d;
> +         d = 1;
> +      }
> +      else {
> +         static const unsigned f[] = { 13, 11, 7, 5, 3, 2, 0 };
> +
> +         /* This is a poor man's way to reduce a fraction.  It's far from
> +          * perfect, but it will work well enough for this situation.
> +          */
> +
> +         for (i = 0; f[i] != 0; i++) {
> +            while (n % f[i] == 0 && d % f[i] == 0) {
> +               d /= f[i];
> +               n /= f[i];
> +            }
> +         }
> +      }
> +
> +      *numerator = n;
> +      *denominator = d;
> +
> +      return True;
> +
> +#endif
> +   return False;
> +}
> +
> +const __DRIsystemTimeExtension dri3_system_time_extension = {
> +   .base = { __DRI_SYSTEM_TIME, 1 },
> +
> +   .getUST              = dri3_get_ust,
> +   .getMSCRate          = dri3_get_msc_rate,
> +};
> +
> +/** dri3_swap_buffers_msc
> + *
> + * Make the current back buffer visible using the present extension
> + */
> +static int64_t
> +dri3_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
> +                      int64_t target_msc, int64_t divisor,
> +                      int64_t remainder)
> +{
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
> +   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> +   struct dri3_buffer *back;
> +   _EGLContext *ctx = _eglGetCurrentContext();
> +   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
> +   int64_t ret = 0;
> +   uint32_t options = XCB_PRESENT_OPTION_NONE;
> +
> +   dri2_flush_drawable_for_swapbuffers(disp, draw);
> +
> +   back = dri3_surf->buffers[DRI3_BACK_ID(dri3_surf->cur_back)];
> +   if (dri2_dpy->is_different_gpu && back) {
> +      /* Update the linear buffer before presenting the pixmap */
> +      dri2_dpy->image->blitImage(dri2_ctx->dri_context,
> +                                 back->linear_buffer,
> +                                 back->image,
> +                                 0, 0, back->width,
> +                                 back->height,
> +                                 0, 0, back->width,
> +                                 back->height, __BLIT_FLAG_FLUSH);
> +      /* Update the fake front */
> +      if (dri3_surf->have_fake_front)
> +         dri2_dpy->image->blitImage(dri2_ctx->dri_context,
> +                                    dri3_surf->buffers[DRI3_FRONT_ID]->image,
> +                                    back->image,
> +                                    0, 0, dri3_surf->base.Width,
> +                                    dri3_surf->base.Height,
> +                                    0, 0, dri3_surf->base.Width,
> +                                    dri3_surf->base.Height,
> +                                    __BLIT_FLAG_FLUSH);
> +   }
> +
> +   dri3_flush_present_events(dri2_dpy, dri3_surf);
> +
> +   if (back && !dri3_surf->is_pixmap) {
> +      dri3_fence_reset(dri2_dpy->conn, back);
> +
> +      /* 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.
> +       * target_msc=divisor=remainder=0 means "Use glXSwapBuffers() semantic"
> +       */
> +      ++dri3_surf->send_sbc;
> +      if (target_msc == 0 && divisor == 0 && remainder == 0)
> +         target_msc = dri3_surf->msc + dri3_surf->base.SwapInterval * (dri3_surf->send_sbc - dri3_surf->recv_sbc);
> +      else if (divisor == 0 && remainder > 0) {
> +         /*
> +          *     "If <divisor> = 0, the swap will occur when MSC becomes
> +          *      greater than or equal to <target_msc>."
> +          *
> +          * Note that there's no mention of the remainder.  The Present extension
> +          * throws BadValue for remainder != 0 with divisor == 0, so just drop
> +          * the passed in value.
> +          */
> +         remainder = 0;
> +      }
> +
> +      /* From the EGL 1.4 spec (page 53):
> +       *
> +       *     "If <interval> is set to a value of 0, buffer swaps are not
> +       *      synchronized to a video frame."
> +       *
> +       * Implementation note: It is possible to enable triple buffering behaviour
> +       * by not using XCB_PRESENT_OPTION_ASYNC, but this should not be the default.
> +       */
> +      if (dri3_surf->base.SwapInterval == 0)
> +          options |= XCB_PRESENT_OPTION_ASYNC;
> +
> +      back->busy = 1;
> +      back->last_swap = dri3_surf->send_sbc;
> +      xcb_present_pixmap(dri2_dpy->conn,
> +                         dri3_surf->drawable,
> +                         back->pixmap,
> +                         (uint32_t) dri3_surf->send_sbc,
> +                         0,                                    /* valid */
> +                         0,                                    /* update */
> +                         0,                                    /* x_off */
> +                         0,                                    /* y_off */
> +                         None,                                 /* target_crtc */
> +                         None,
> +                         back->sync_fence,
> +                         options,
> +                         target_msc,
> +                         divisor,
> +                         remainder, 0, NULL);
> +      ret = (int64_t) dri3_surf->send_sbc;
> +
> +      /* If there's a fake front, then copy the source back buffer
> +       * to the fake front to keep it up to date. This needs
> +       * to reset the fence and make future users block until
> +       * the X server is done copying the bits
> +       */
> +      if (dri3_surf->have_fake_front && !dri2_dpy->is_different_gpu) {
> +         dri3_fence_reset(dri2_dpy->conn, dri3_surf->buffers[DRI3_FRONT_ID]);
> +         dri3_copy_area(dri2_dpy->conn,
> +                        back->pixmap,
> +                        dri3_surf->buffers[DRI3_FRONT_ID]->pixmap,
> +                        dri3_drawable_gc(dri2_dpy, dri3_surf),
> +                        0, 0, 0, 0,
> +                        dri3_surf->base.Width,
> +                        dri3_surf->base.Height);
> +         dri3_fence_trigger(dri2_dpy->conn, dri3_surf->buffers[DRI3_FRONT_ID]);
> +      }
> +      xcb_flush(dri2_dpy->conn);
> +      if (dri3_surf->stamp)
> +         ++(*dri3_surf->stamp);
> +   }
> +
> +   (*dri2_dpy->flush->invalidate)(dri3_surf->dri_drawable);
> +
> +   return ret;
> +}
> +
> +static EGLBoolean
> +dri3_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
> +{
> +   return dri3_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1;
> +}
> +
> +static int
> +dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
> +{
> +   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +   int back_id = DRI3_BACK_ID(dri3_find_back(dri2_dpy, dri3_surf));
> +
> +   if (back_id < 0 || !dri3_surf->buffers[back_id])
> +      return 0;
> +
> +   if (dri3_surf->buffers[back_id]->last_swap != 0)
> +      return dri3_surf->send_sbc - dri3_surf->buffers[back_id]->last_swap + 1;
> +   else
> +      return 0;
> +}
> +
> +/* FIXME: Is this right? Seems problematic for WL_bind_wayland_display */
What seems to be the problem ?

Afaik xcb_dri3_open_reply_fds should return an FD which is ok (be that a
render_node device, or a master one with explicit auth).

> +static int
> +dri3_authenticate(_EGLDisplay *disp, uint32_t id)
> +{
> +   return 0;
> +}
> +
> +struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
static ?

> +   .authenticate = dri3_authenticate,
> +   .create_window_surface = dri3_create_window_surface,
> +   .create_pixmap_surface = dri3_create_pixmap_surface,
> +   .create_pbuffer_surface = dri3_create_pbuffer_surface,
> +   .destroy_surface = dri3_destroy_surface,
> +   .create_image = dri2_create_image_khr,
> +   .swap_interval = dri3_set_swap_interval,
> +   .swap_buffers = dri3_swap_buffers,
> +   .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
> +   .swap_buffers_region = dri2_fallback_swap_buffers_region,
> +   .post_sub_buffer = dri2_fallback_post_sub_buffer,
> +   .copy_buffers = dri2_fallback_copy_buffers,
> +   .query_buffer_age = dri3_query_buffer_age,
> +   .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
> +   .get_sync_values = dri3_get_sync_values,
> +};
> +
> +/** dri3_open
> + *
> + * Wrapper around xcb_dri3_open
> + */
> +static int
> +dri3_open(xcb_connection_t *conn,
> +          xcb_window_t root,
> +          uint32_t provider)
> +{
> +   xcb_dri3_open_cookie_t       cookie;
> +   xcb_dri3_open_reply_t        *reply;
> +   int                          fd;
> +
> +   cookie = xcb_dri3_open(conn,
> +                          root,
> +                          provider);
> +
> +   reply = xcb_dri3_open_reply(conn, cookie, NULL);
> +   if (!reply)
> +      return -1;
> +
> +   if (reply->nfd != 1) {
> +      free(reply);
> +      return -1;
> +   }
> +
> +   fd = xcb_dri3_open_reply_fds(conn, reply)[0];
> +   fcntl(fd, F_SETFD, FD_CLOEXEC);
I do recall looking at this (in src/glx) and wondering... aren't we
missing fcntl(F_GETFD) ?

> +
> +   return fd;
> +}
> +
> +EGLBoolean
> +dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
> +{
> +   xcb_dri3_query_version_reply_t *dri3_query;
> +   xcb_dri3_query_version_cookie_t dri3_query_cookie;
> +   xcb_present_query_version_reply_t *present_query;
> +   xcb_present_query_version_cookie_t present_query_cookie;
> +   xcb_generic_error_t *error;
> +   xcb_screen_iterator_t s;
> +   xcb_screen_t *screen;
> +   const xcb_query_extension_reply_t *extension;
> +
> +   xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
> +   xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);
> +
> +   extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);
> +   if (!(extension && extension->present))
> +      return EGL_FALSE;
> +
> +   extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);
> +   if (!(extension && extension->present))
> +      return EGL_FALSE;
> +
> +   dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,
> +                                              XCB_DRI3_MAJOR_VERSION,
> +                                              XCB_DRI3_MINOR_VERSION);
> +
> +   present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
> +                                                    XCB_PRESENT_MAJOR_VERSION,
> +                                                    XCB_PRESENT_MINOR_VERSION);
> +
> +   /* FIXME: a little bit memory leak here */
> +   dri3_query =
> +      xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
> +   if (dri3_query == NULL || error != NULL) {
> +      _eglLog(_EGL_WARNING, "DRI2: failed to query dri3 version");
> +      free(error);
> +      return EGL_FALSE;
> +   }
> +   dri2_dpy->dri3_major = dri3_query->major_version;
> +   dri2_dpy->dri3_minor = dri3_query->minor_version;
> +   free(dri3_query);
> +
> +   present_query =
> +      xcb_present_query_version_reply(dri2_dpy->conn,
> +                                      present_query_cookie, &error);
> +   if (present_query == NULL || error != NULL) {
> +      _eglLog(_EGL_WARNING, "DRI2: failed to query Present version");
> +      free(error);
> +      return EGL_FALSE;
> +   }
> +   dri2_dpy->present_major = present_query->major_version;
> +   dri2_dpy->present_minor = present_query->minor_version;
> +   free(present_query);
> +
> +   s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
> +   screen = get_xcb_screen(s, dri2_dpy->screen);
> +   if (!screen) {
> +      _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_x11_connect");
> +      return EGL_FALSE;
> +   }
> +
> +   dri2_dpy->fd = dri3_open(dri2_dpy->conn, screen->root, 0);
> +   if (dri2_dpy->fd < 0) {
> +      int conn_error = xcb_connection_has_error(dri2_dpy->conn);
> +      _eglLog(_EGL_WARNING, "DRI2: Screen seem not DRI3 capable");
> +
> +      if (conn_error)
> +         _eglLog(_EGL_WARNING, "DRI2: Failed to initialize DRI3");
> +
> +      return EGL_FALSE;
> +   }
> +
> +   dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
> +
> +   dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);
> +   if (!dri2_dpy->driver_name) {
> +      _eglLog(_EGL_WARNING, "DRI2: No driver found");
> +      close(dri2_dpy->fd);
> +      return EGL_FALSE;
> +   }
> +
> +   dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
Seems like wayland_drm_init is the only user of device_name in the whole
of EGL. Wondering if it'll be worth keeping it wayland specific and
ripping it out of platform_{drm,x11}.

Cheers,
Emil



More information about the mesa-dev mailing list