[Mesa-dev] [PATCH RFC 7/9] egl/x11: Implement dri3 support with loader's dri3 helper

Emil Velikov emil.l.velikov at gmail.com
Tue Jul 28 05:35:02 PDT 2015


On 21 July 2015 at 16:44, Boyan Ding <boyan.j.ding at gmail.com> wrote:
> Signed-off-by: Boyan Ding <boyan.j.ding at gmail.com>
> ---
>  configure.ac                             |   6 +
>  src/egl/drivers/dri2/Makefile.am         |   5 +
>  src/egl/drivers/dri2/egl_dri2.c          |  66 +++-
>  src/egl/drivers/dri2/egl_dri2.h          |  14 +-
>  src/egl/drivers/dri2/platform_x11.c      | 105 ++++++-
>  src/egl/drivers/dri2/platform_x11_dri3.c | 517 +++++++++++++++++++++++++++++++
>  src/egl/drivers/dri2/platform_x11_dri3.h |  44 +++
>  7 files changed, 748 insertions(+), 9 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 872f15b..5727db9 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -72,6 +72,7 @@ LIBDRM_INTEL_REQUIRED=2.4.61
>  LIBDRM_NVVIEUX_REQUIRED=2.4.33
>  LIBDRM_NOUVEAU_REQUIRED=2.4.62
>  LIBDRM_FREEDRENO_REQUIRED=2.4.57
> +LIBDRM_EGL_DRI3_REQUIRED=2.4.60
I wouldn't bother with this, but directly bump LIBDRM_REQUIRED.

>  DRI2PROTO_REQUIRED=2.6
>  DRI3PROTO_REQUIRED=1.0
>  PRESENTPROTO_REQUIRED=1.0
> @@ -1771,6 +1772,11 @@ for plat in $egl_platforms; do
>
>         x11)
>                 PKG_CHECK_MODULES([XCB_DRI2], [x11-xcb xcb xcb-dri2 >= $XCBDRI2_REQUIRED xcb-xfixes])
> +
> +               PKG_CHECK_EXISTS([libdrm >= LIBDRM_EGL_DRI3_REQUIRED], [libdrm_render_node=yes], [libdrm_render_node=no])
> +               if test "x$libdrm_render_node" = xyes; then
> +                       DEFINES="$DEFINES -DLIBDRM_HAS_RENDERNODE_SUPPORT"
> +               fi
>                 ;;
>
>         drm)
> 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
I did reshuffle things recently so I fear that there'll be some conflicts here.

>  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 dcce04c..139fe29 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,25 @@ dri2_open_driver(_EGLDisplay *disp)
>  }
>
>  EGLBoolean
> +dri2_load_driver_dri3(_EGLDisplay *disp)
> +{
> +   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);
> +      return EGL_FALSE;
> +   }
> +   dri2_dpy->driver_extensions = extensions;
> +
> +   return EGL_TRUE;
> +}
> +
> +EGLBoolean
>  dri2_load_driver(_EGLDisplay *disp)
>  {
>     struct dri2_egl_display *dri2_dpy = disp->DriverData;
> @@ -507,7 +532,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 +554,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 +619,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 +662,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 +1006,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 435c670..238e81d 100644
> --- a/src/egl/drivers/dri2/egl_dri2.h
> +++ b/src/egl/drivers/dri2/egl_dri2.h
> @@ -35,6 +35,10 @@
>  #include <xcb/dri2.h>
>  #include <xcb/xfixes.h>
>  #include <X11/Xlib-xcb.h>
> +
> +#ifdef HAVE_DRI3
> +#include "loader_dri3_helper.h"
> +#endif
>  #endif
>
>  #ifdef HAVE_WAYLAND_PLATFORM
> @@ -160,6 +164,7 @@ struct dri2_egl_display
>     const __DRIconfig       **driver_configs;
>     void                     *driver;
>     const __DRIcoreExtension       *core;
> +   const __DRIimageDriverExtension *image_driver;
>     const __DRIdri2Extension       *dri2;
>     const __DRIswrastExtension     *swrast;
>     const __DRI2flushExtension     *flush;
> @@ -191,6 +196,9 @@ struct dri2_egl_display
>  #ifdef HAVE_X11_PLATFORM
>     xcb_connection_t         *conn;
>     int                      screen;
> +#ifdef HAVE_DRI3
> +   struct loader_dri3_extensions loader_dri3_ext;
> +#endif
>  #endif
>
>  #ifdef HAVE_WAYLAND_PLATFORM
> @@ -204,8 +212,9 @@ struct dri2_egl_display
>     int                      formats;
>     uint32_t                  capabilities;
>     int                      is_render_node;
> -   int                      is_different_gpu;
>  #endif
> +
> +   int                      is_different_gpu;
>  };
>
>  struct dri2_egl_context
> @@ -326,6 +335,9 @@ EGLBoolean
>  dri2_load_driver_swrast(_EGLDisplay *disp);
>
>  EGLBoolean
> +dri2_load_driver_dri3(_EGLDisplay *disp);
> +
> +EGLBoolean
>  dri2_create_screen(_EGLDisplay *disp);
>
>  __DRIdrawable *
> diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c
> index 7e1e9e1..a3bc8e1 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);
> @@ -1204,6 +1208,96 @@ dri2_x11_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
>     }
>  }
>
> +#ifdef HAVE_DRI3
> +static EGLBoolean
> +dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp)
> +{
> +   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->conn = xcb_connect(0, &dri2_dpy->screen);
> +      dri2_dpy->own_device = true;
> +   } else {
> +      Display *dpy = disp->PlatformDisplay;
> +
> +      dri2_dpy->conn = XGetXCBConnection(dpy);
> +      dri2_dpy->screen = DefaultScreen(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] = &use_invalidate.base;
> +   dri2_dpy->extensions[2] = &image_lookup_extension.base;
> +   dri2_dpy->extensions[3] = 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;
> +   }
> +
> +   dri2_dpy->loader_dri3_ext.core = dri2_dpy->core;
> +   dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver;
> +   dri2_dpy->loader_dri3_ext.flush = dri2_dpy->flush;
> +   dri2_dpy->loader_dri3_ext.tex_buffer = dri2_dpy->tex_buffer;
> +   dri2_dpy->loader_dri3_ext.image = dri2_dpy->image;
> +   dri2_dpy->loader_dri3_ext.config = dri2_dpy->config;
> +
> +   /* 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);
> + cleanup_dpy:
> +   free(dri2_dpy);
> +
> +   return EGL_FALSE;
> +}
> +#endif
> +
>  static EGLBoolean
>  dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
>  {
> @@ -1323,9 +1417,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_DISABLE") != 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..b570a57
> --- /dev/null
> +++ b/src/egl/drivers/dri2/platform_x11_dri3.c
> @@ -0,0 +1,517 @@
> +/*
> + * Copyright © 2015 Boyan Ding
> + *
> + * 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 <stdbool.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include <xcb/xcb.h>
> +#include <xcb/dri3.h>
> +#include <xcb/present.h>
> +
> +#ifdef HAVE_LIBDRM
While correct, we can drop the guard as we require libdrm.

> +#include <xf86drm.h>
> +#endif
> +
> +#include "egl_dri2.h"
> +#include "egl_dri2_fallbacks.h"
> +#include "platform_x11_dri3.h"
> +
> +#include "loader.h"
> +#include "loader_dri3_helper.h"
> +
> +static int
> +egl_dri3_get_swap_interval(struct loader_dri3_drawable *draw)
> +{
> +   struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> +   return dri3_surf->base.SwapInterval;
> +}
> +
> +static int
> +egl_dri3_clamp_swap_interval(struct loader_dri3_drawable *draw, int interval)
> +{
> +   struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> +   if (interval > dri3_surf->base.Config->MaxSwapInterval)
> +      interval = dri3_surf->base.Config->MaxSwapInterval;
> +   else if (interval < dri3_surf->base.Config->MinSwapInterval)
> +      interval = dri3_surf->base.Config->MinSwapInterval;
> +
> +   return interval;
> +}
> +
> +static void
> +egl_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval)
> +{
> +   struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> +   dri3_surf->base.SwapInterval = interval;
> +}
> +
> +static void
> +egl_dri3_set_drawable_size(struct loader_dri3_drawable *draw,
> +                           int width, int height)
> +{
> +   struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> +   dri3_surf->base.Width = width;
> +   dri3_surf->base.Height = height;
> +}
> +
> +static int
> +egl_dri3_get_width(struct loader_dri3_drawable *draw)
> +{
> +   struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> +   return dri3_surf->base.Width;
> +}
> +
> +static int
> +egl_dri3_get_height(struct loader_dri3_drawable *draw)
> +{
> +   struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> +   return dri3_surf->base.Height;
> +}
> +
> +static bool
> +egl_dri3_is_different_gpu(struct loader_dri3_drawable *draw)
> +{
> +   struct dri3_egl_surface *dri3_surf = draw->priv;
> +   struct dri2_egl_display *dri2_dpy =
> +      dri2_egl_display(dri3_surf->base.Resource.Display);
> +
> +   return dri2_dpy->is_different_gpu;
> +}
> +
> +static bool
> +egl_dri3_in_current_context(struct loader_dri3_drawable *draw)
> +{
> +   struct dri3_egl_surface *dri3_surf = draw->priv;
> +   _EGLContext *ctx = _eglGetCurrentContext();
> +
> +   return ctx->Resource.Display == dri3_surf->base.Resource.Display;
> +}
> +
> +static __DRIcontext *
> +egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
> +{
> +   _EGLContext *ctx = _eglGetCurrentContext();
> +   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
> +
> +   return dri2_ctx->dri_context;
> +}
> +
> +static __DRIscreen *
> +egl_dri3_get_dri_screen(struct loader_dri3_drawable *draw)
> +{
> +   struct dri3_egl_surface *dri3_surf = draw->priv;
> +   struct dri2_egl_display *dri2_dpy =
> +      dri2_egl_display(dri3_surf->base.Resource.Display);
> +
> +   return dri2_dpy->dri_screen;
> +}
> +
> +static void
> +egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
> +{
> +   struct dri3_egl_surface *dri3_surf = draw->priv;
> +   _EGLDisplay *disp = dri3_surf->base.Resource.Display;
> +
> +   dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->base);
> +}
> +
> +static struct loader_dri3_vtable egl_dri3_vtable = {
> +   .get_swap_interval = egl_dri3_get_swap_interval,
> +   .clamp_swap_interval = egl_dri3_clamp_swap_interval,
> +   .set_swap_interval = egl_dri3_set_swap_interval,
> +   .set_drawable_size = egl_dri3_set_drawable_size,
> +   .get_width = egl_dri3_get_width,
> +   .get_height = egl_dri3_get_height,
> +   .is_different_gpu = egl_dri3_is_different_gpu,
> +   .in_current_context = egl_dri3_in_current_context,
> +   .get_dri_context = egl_dri3_get_dri_context,
> +   .get_dri_screen = egl_dri3_get_dri_screen,
> +   .flush_drawable = egl_dri3_flush_drawable,
> +   .show_fps = NULL,
> +};
> +
> +static EGLBoolean
> +dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
> +{
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +
> +   (void) drv;
> +
> +   if (!_eglPutSurface(surf))
> +      return EGL_TRUE;
> +
> +   loader_dri3_destroy_drawable(dri3_surf->loader_drawable);
> +
> +   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);
> +
> +   loader_dri3_set_swap_interval(dri3_surf->loader_drawable, interval);
> +
> +   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;
> +}
> +
> +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_screen_iterator_t s;
> +   xcb_screen_t *screen;
> +
> +   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;
> +      }
> +
> +      drawable = xcb_generate_id(dri2_dpy->conn);
> +      xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
> +                        drawable, screen->root,
> +                        dri3_surf->base.Width, dri3_surf->base.Height);
> +   }
> +
> +   dri3_surf->loader_drawable =
> +      loader_dri3_create_drawable(dri2_dpy->conn, drawable,
> +                                  dri2_dpy->dri_screen,
> +                                  type == EGL_WINDOW_BIT ?
> +                                  dri2_conf->dri_double_config :
> +                                  dri2_conf->dri_single_config,
> +                                  &dri2_dpy->loader_dri3_ext,
> +                                  &egl_dri3_vtable,
> +                                  dri3_surf);
> +   if (!dri3_surf->loader_drawable) {
> +      _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
> +      goto cleanup_pixmap;
> +   }
> +
> +   return &dri3_surf->base;
> +
> + cleanup_pixmap:
> +   if (type == EGL_PBUFFER_BIT)
> +      xcb_free_pixmap(dri2_dpy->conn, 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);
> +}
> +
> +static EGLBoolean
> +dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
> +                     EGLuint64KHR *ust, EGLuint64KHR *msc,
> +                     EGLuint64KHR *sbc)
> +{
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
> +
> +   return loader_dri3_wait_for_msc(dri3_surf->loader_drawable, 0, 0, 0,
> +                                   ust, msc, sbc) ? EGL_TRUE : EGL_FALSE;
> +}
> +
> +/**
> + * 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)
> +{
> +   /* FIXME: Does EGL support front buffer rendering at all? */
> +   _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
I believe that EGL does not support front buffer rendering. Although I
could be wrong.

> +   (void) driDrawable;
> +   (void) loaderPrivate;
> +}
> +
> +const __DRIimageLoaderExtension dri3_image_loader_extension = {
> +   .base = { __DRI_IMAGE_LOADER, 1 },
> +
> +   .getBuffers          = loader_dri3_get_buffers,
> +   .flushFrontBuffer    = dri3_flush_front_buffer,
> +};
> +
> +static EGLBoolean
> +dri3_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
> +{
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
> +
> +   /* No-op for a pixmap or pbuffer surface */
> +   if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
> +      return 0;
> +
> +   return loader_dri3_swap_buffers_msc(dri3_surf->loader_drawable,
> +                                       0, 0, 0, 0,
> +                                       draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
> +}
> +
> +static EGLBoolean
> +dri3_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
> +                  void *native_pixmap_target)
> +{
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +   xcb_pixmap_t target;
> +
> +   STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
> +   target = (uintptr_t) native_pixmap_target;
> +
> +   loader_dri3_copy_drawable(dri3_surf->loader_drawable, target,
> +                             dri3_surf->loader_drawable->drawable);
> +
> +   return EGL_TRUE;
> +}
> +
> +static int
> +dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
> +{
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +
> +   return loader_dri3_query_buffer_age(dri3_surf->loader_drawable);
> +}
> +
> +static int
> +dri3_authenticate(_EGLDisplay *disp, uint32_t id)
> +{
> +   /* If the device is render node, authentication is not needed, if it is
> +    * master, authentication won't succeed anyway.
> +    */
> +   _eglLog(_EGL_WARNING, "authentication shouldn't be called on dri3");
> +
Last time I've looked (a little while ago) one can just omit this
function, and set the vtbl entry to NULL.

> +   return 0;
> +}
> +
> +static __DRIdrawable *
> +dri3_get_dri_drawable(_EGLSurface *surf)
> +{
> +   struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +
> +   return dri3_surf->loader_drawable->dri_drawable;
> +}
> +
> +struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
> +   .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 = dri3_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,
> +   .get_dri_drawable = dri3_get_dri_drawable,
> +};
> +
> +static char *
> +dri3_get_device_name(int fd)
> +{
> +   char *ret = NULL;
> +
> +#ifdef LIBDRM_HAS_RENDERNODE_SUPPORT
> +   ret = drmGetRenderDeviceNameFromFd(fd);
> +#endif
> +   if (ret)
> +      return ret;
> +
> +   /* For dri3, render node support is required for WL_bind_wayland_display.
> +    * In order not to regress on older systems without kernel or libdrm
> +    * support, fall back to dri2. User can override it with environment
> +    * variable if they don't need to use that extension.
> +    */
Can we just disable the extension, if the above call fails ?

> +   if (getenv("EGL_FORCE_DRI3") == NULL) {
> +      _eglLog(_EGL_WARNING, "Render node support not available, falling back to dri2");
> +      _eglLog(_EGL_WARNING, "If you want to force dri3, set EGL_FORCE_DRI3 environment variable");
> +   } else
> +      ret = loader_get_device_name_for_fd(fd);
> +
> +   return ret;
> +}
> +
> +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);
> +
> +   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(dri3_query);
> +      free(error);
> +      return EGL_FALSE;
> +   }
> +   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(present_query);
> +      free(error);
> +      return EGL_FALSE;
> +   }
> +   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 = loader_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 = dri3_get_device_name(dri2_dpy->fd);
> +   if (!dri2_dpy->device_name) {
> +      close(dri2_dpy->fd);
> +      return EGL_FALSE;
> +   }
> +
> +   return EGL_TRUE;
> +}
> diff --git a/src/egl/drivers/dri2/platform_x11_dri3.h b/src/egl/drivers/dri2/platform_x11_dri3.h
> new file mode 100644
> index 0000000..b9d0f3d
> --- /dev/null
> +++ b/src/egl/drivers/dri2/platform_x11_dri3.h
> @@ -0,0 +1,44 @@
> +/*
> + * Copyright © 2015 Boyan Ding
> + *
> + * 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.
> + */
> +
> +#ifndef EGL_X11_DRI3_INCLUDED
> +#define EGL_X11_DRI3_INCLUDED
> +
> +#include <GL/gl.h>
This include feels a bit odd. We don't seem to (directly) require it
by of the following code.

> +#include <GL/internal/dri_interface.h>
> +
> +#include "egl_dri2.h"
> +
> +_EGL_DRIVER_TYPECAST(dri3_egl_surface, _EGLSurface, obj)
> +
> +struct dri3_egl_surface {
> +   _EGLSurface base;
> +   struct loader_dri3_drawable *loader_drawable;
> +};
> +
> +extern const __DRIimageLoaderExtension dri3_image_loader_extension;
> +extern struct dri2_egl_display_vtbl dri3_x11_display_vtbl;
> +
> +EGLBoolean
> +dri3_x11_connect(struct dri2_egl_display *dri2_dpy);
> +
> +#endif
> --
> 2.4.4
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list