[PATCH 2/3] egl/dri: Add gbm platform

Ander Conselvan de Oliveira ander.conselvan.de.oliveira at intel.com
Tue Nov 5 08:32:57 PST 2013


This adds a GBM platform that doesn't depend on gbm's dri backend. This
can be used, for instance, with the intel backend.

This also adds a gbm_bo_export entrypoint to gbm, so that the EGL code
can access the buffer. This is necessary since EGL won't share the fd
width gbm when using the new platform.

The new platform is mostly a copy from platform-drm.c
---
 configure.ac                        |    5 +-
 src/egl/drivers/dri2/Makefile.am    |    5 +
 src/egl/drivers/dri2/egl_dri2.c     |    6 +
 src/egl/drivers/dri2/egl_dri2.h     |   11 +-
 src/egl/drivers/dri2/platform_gbm.c |  545 +++++++++++++++++++++++++++++++++++
 src/egl/main/Makefile.am            |    5 +
 src/egl/main/egldisplay.c           |    3 +-
 src/egl/main/egldisplay.h           |    1 +
 src/gbm/backends/dri/gbm_dri.c      |    7 +
 src/gbm/backends/intel/gbm_intel.c  |   21 ++
 src/gbm/backends/intel/gbm_intel.h  |    1 +
 src/gbm/main/gbm.c                  |   29 +-
 src/gbm/main/gbm.h                  |    4 +
 src/gbm/main/gbmint.h               |    3 +
 14 files changed, 638 insertions(+), 8 deletions(-)
 create mode 100644 src/egl/drivers/dri2/platform_gbm.c

diff --git a/configure.ac b/configure.ac
index 91b9871..e6beb5b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1442,9 +1442,9 @@ for plat in $egl_platforms; do
                 fi
 		;;
 
-	drm)
+	drm|gbm)
 		test "x$enable_gbm" = "xno" &&
-			AC_MSG_ERROR([EGL platform drm needs gbm])
+			AC_MSG_ERROR([EGL platform '$plat' needs gbm])
 		;;
 
 	android|fbdev|gdi|null)
@@ -1478,6 +1478,7 @@ AM_CONDITIONAL(HAVE_EGL_PLATFORM_WAYLAND, echo "$egl_platforms" | grep 'wayland'
 AM_CONDITIONAL(HAVE_EGL_PLATFORM_DRM, echo "$egl_platforms" | grep 'drm' >/dev/null 2>&1)
 AM_CONDITIONAL(HAVE_EGL_PLATFORM_FBDEV, echo "$egl_platforms" | grep 'fbdev' >/dev/null 2>&1)
 AM_CONDITIONAL(HAVE_EGL_PLATFORM_NULL, echo "$egl_platforms" | grep 'null' >/dev/null 2>&1)
+AM_CONDITIONAL(HAVE_EGL_PLATFORM_GBM, echo "$egl_platforms" | grep 'gbm' >/dev/null 2>&1)
 
 AM_CONDITIONAL(HAVE_EGL_DRIVER_DRI2, test "x$HAVE_EGL_DRIVER_DRI2" != "x")
 AM_CONDITIONAL(HAVE_EGL_DRIVER_GLX, test "x$HAVE_EGL_DRIVER_GLX" != "x")
diff --git a/src/egl/drivers/dri2/Makefile.am b/src/egl/drivers/dri2/Makefile.am
index 823ef5e..5482a57 100644
--- a/src/egl/drivers/dri2/Makefile.am
+++ b/src/egl/drivers/dri2/Makefile.am
@@ -63,3 +63,8 @@ if HAVE_EGL_PLATFORM_DRM
 libegl_dri2_la_SOURCES += platform_drm.c
 AM_CFLAGS += -DHAVE_DRM_PLATFORM
 endif
+
+if HAVE_EGL_PLATFORM_GBM
+libegl_dri2_la_SOURCES += platform_gbm.c
+AM_CFLAGS += -DHAVE_GBM_PLATFORM
+endif
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 903a1a6..b0797a4 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -626,6 +626,12 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp)
          return EGL_TRUE;
       return dri2_initialize_drm(drv, disp);
 #endif
+#ifdef HAVE_GBM_PLATFORM
+   case _EGL_PLATFORM_GBM:
+      if (disp->Options.TestOnly)
+         return EGL_TRUE;
+      return dri2_initialize_gbm(drv, disp);
+#endif
 #ifdef HAVE_WAYLAND_PLATFORM
    case _EGL_PLATFORM_WAYLAND:
       if (disp->Options.TestOnly)
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index a72e7b2..ede72e6 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -183,7 +183,11 @@ struct dri2_egl_surface
    struct gbm_dri_surface *gbm_dri_surf;
 #endif
 
-#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM)
+#ifdef HAVE_GBM_PLATFORM
+   struct gbm_surface *gbm_surf;
+#endif
+
+#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM) || defined(HAVE_GBM_PLATFORM)
    __DRIbuffer           *dri_buffers[__DRI_BUFFER_COUNT];
    struct {
 #ifdef HAVE_WAYLAND_PLATFORM
@@ -191,7 +195,7 @@ struct dri2_egl_surface
       __DRIimage         *dri_image;
       int                 pitch, name;
 #endif
-#ifdef HAVE_DRM_PLATFORM
+#if defined(HAVE_DRM_PLATFORM) || defined(HAVE_GBM_PLATFORM)
       struct gbm_bo       *bo;
 #endif
       int                 locked;
@@ -262,6 +266,9 @@ EGLBoolean
 dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp);
 
 EGLBoolean
+dri2_initialize_gbm(_EGLDriver *drv, _EGLDisplay *disp);
+
+EGLBoolean
 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp);
 
 EGLBoolean
diff --git a/src/egl/drivers/dri2/platform_gbm.c b/src/egl/drivers/dri2/platform_gbm.c
new file mode 100644
index 0000000..c28bc4a
--- /dev/null
+++ b/src/egl/drivers/dri2/platform_gbm.c
@@ -0,0 +1,545 @@
+/*
+ * Copyright © 2011-2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Ander Conselvan de Oliveira <ander.conselvan.de.oliveira at intel.com>
+ *    Kristian Høgsberg <krh at bitplanet.net>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <xf86drm.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "egl_dri2.h"
+
+#include "gbmint.h"
+
+static struct gbm_bo *
+lock_front_buffer(struct gbm_surface *surf)
+{
+   struct dri2_egl_surface *dri2_surf = surf->priv;
+   struct gbm_bo *bo;
+
+   if (dri2_surf->current == NULL) {
+      _eglError(EGL_BAD_SURFACE, "no front buffer");
+      return NULL;
+   }
+
+   bo = dri2_surf->current->bo;
+   dri2_surf->current->locked = 1;
+   dri2_surf->current = NULL;
+
+   return bo;
+}
+
+static void
+release_buffer(struct gbm_surface *surf, struct gbm_bo *bo)
+{
+   struct dri2_egl_surface *dri2_surf = surf->priv;
+   int i;
+
+   for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
+      if (dri2_surf->color_buffers[i].bo == bo) {
+	 dri2_surf->color_buffers[i].locked = 0;
+      }
+   }
+}
+
+static int
+has_free_buffers(struct gbm_surface *surf)
+{
+   struct dri2_egl_surface *dri2_surf = surf->priv;
+   int i;
+
+   for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
+      if (!dri2_surf->color_buffers[i].locked)
+	 return 1;
+
+   return 0;
+}
+
+static _EGLSurface *
+dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
+		    _EGLConfig *conf, EGLNativeWindowType window,
+		    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 dri2_egl_surface *dri2_surf;
+   struct gbm_surface *surf;
+
+   (void) drv;
+
+   dri2_surf = calloc(1, sizeof *dri2_surf);
+   if (!dri2_surf) {
+      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
+      return NULL;
+   }
+
+   if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
+      goto cleanup_surf;
+
+   switch (type) {
+   case EGL_WINDOW_BIT:
+      if (!window)
+         return NULL;
+      surf = (struct gbm_surface *) window;
+      dri2_surf->gbm_surf = surf;
+      dri2_surf->base.Width =  surf->width;
+      dri2_surf->base.Height = surf->height;
+      surf->priv = dri2_surf;
+      break;
+   default:
+      goto cleanup_surf;
+   }
+
+   dri2_surf->dri_drawable =
+      (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
+					    dri2_conf->dri_double_config,
+					    dri2_surf);
+
+   if (dri2_surf->dri_drawable == NULL) {
+      _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
+      goto cleanup_surf;
+   }
+
+   return &dri2_surf->base;
+
+ cleanup_surf:
+   free(dri2_surf);
+
+   return NULL;
+}
+
+static _EGLSurface *
+dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
+			   _EGLConfig *conf, EGLNativeWindowType window,
+			   const EGLint *attrib_list)
+{
+   return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
+			      window, attrib_list);
+}
+
+static EGLBoolean
+dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
+   int i;
+
+   if (!_eglPutSurface(surf))
+      return EGL_TRUE;
+
+   (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
+
+   for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
+      if (dri2_surf->color_buffers[i].bo)
+	 gbm_bo_destroy(dri2_surf->color_buffers[i].bo);
+   }
+
+   for (i = 0; i < __DRI_BUFFER_COUNT; i++) {
+      if (dri2_surf->dri_buffers[i])
+         dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
+                                       dri2_surf->dri_buffers[i]);
+   }
+
+   free(surf);
+
+   return EGL_TRUE;
+}
+
+static int
+get_back_bo(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
+{
+   struct gbm_bo *bo;
+   struct gbm_surface *surf;
+   int i, name, pitch;
+
+   if (dri2_surf->back == NULL) {
+      for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
+	 if (!dri2_surf->color_buffers[i].locked) {
+	    dri2_surf->back = &dri2_surf->color_buffers[i];
+	    break;
+	 }
+      }
+   }
+
+   surf = dri2_surf->gbm_surf;
+
+   if (dri2_surf->back == NULL)
+      return -1;
+   if (dri2_surf->back->bo == NULL)
+      dri2_surf->back->bo =
+	 gbm_bo_create(surf->gbm, surf->width, surf->height,
+		       surf->format, surf->flags);
+   if (dri2_surf->back->bo == NULL)
+      return -1;
+
+   bo = dri2_surf->back->bo;
+
+   if (gbm_bo_export(bo, GBM_BO_IMPORT_GEM_NAME, (void **) &name) < 0)
+      return -1;
+
+   pitch = gbm_bo_get_stride(bo);
+
+   buffer->attachment = __DRI_BUFFER_BACK_LEFT;
+   buffer->name = name;
+   buffer->pitch = pitch;
+   buffer->cpp = 4;
+   buffer->flags = 0;
+
+   return 0;
+}
+
+static int
+get_aux_bo(struct dri2_egl_surface *dri2_surf,
+	   unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
+{
+   struct dri2_egl_display *dri2_dpy =
+      dri2_egl_display(dri2_surf->base.Resource.Display);
+   __DRIbuffer *b = dri2_surf->dri_buffers[attachment];
+
+   if (b == NULL) {
+      b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
+					 attachment, format,
+					 dri2_surf->base.Width,
+					 dri2_surf->base.Height);
+      dri2_surf->dri_buffers[attachment] = b;
+   }
+   if (b == NULL)
+      return -1;
+
+   memcpy(buffer, b, sizeof *buffer);
+
+   return 0;
+}
+
+static __DRIbuffer *
+dri2_get_buffers_with_format(__DRIdrawable *driDrawable,
+			     int *width, int *height,
+			     unsigned int *attachments, int count,
+			     int *out_count, void *loaderPrivate)
+{
+   struct dri2_egl_surface *dri2_surf = loaderPrivate;
+   int i, j;
+
+   dri2_surf->buffer_count = 0;
+   for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
+      assert(attachments[i] < __DRI_BUFFER_COUNT);
+      assert(dri2_surf->buffer_count < 5);
+
+      switch (attachments[i]) {
+      case __DRI_BUFFER_BACK_LEFT:
+	 if (get_back_bo(dri2_surf, &dri2_surf->buffers[j]) < 0) {
+	    _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
+	    return NULL;
+	 }
+	 break;
+      default:
+	 if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
+			&dri2_surf->buffers[j]) < 0) {
+	    _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
+	    return NULL;
+	 }
+	 break;
+      }
+   }
+
+   *out_count = j;
+   if (j == 0)
+      return NULL;
+
+   *width = dri2_surf->base.Width;
+   *height = dri2_surf->base.Height;
+
+   return dri2_surf->buffers;
+}
+
+static __DRIbuffer *
+dri2_get_buffers(__DRIdrawable * driDrawable,
+		 int *width, int *height,
+		 unsigned int *attachments, int count,
+		 int *out_count, void *loaderPrivate)
+{
+   unsigned int *attachments_with_format;
+   __DRIbuffer *buffer;
+   const unsigned int format = 32;
+   int i;
+
+   attachments_with_format = calloc(count * 2, sizeof(unsigned int));
+   if (!attachments_with_format) {
+      *out_count = 0;
+      return NULL;
+   }
+
+   for (i = 0; i < count; ++i) {
+      attachments_with_format[2*i] = attachments[i];
+      attachments_with_format[2*i + 1] = format;
+   }
+
+   buffer =
+      dri2_get_buffers_with_format(driDrawable,
+				   width, height,
+				   attachments_with_format, count,
+				   out_count, loaderPrivate);
+
+   free(attachments_with_format);
+
+   return buffer;
+}
+
+static void
+dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
+{
+   (void) driDrawable;
+   (void) loaderPrivate;
+}
+
+static EGLBoolean
+dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
+   int i;
+
+   if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
+      if (dri2_surf->current)
+	 _eglError(EGL_BAD_SURFACE, "dri2_swap_buffers");
+      for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
+         if (dri2_surf->color_buffers[i].age > 0)
+            dri2_surf->color_buffers[i].age++;
+      dri2_surf->current = dri2_surf->back;
+      dri2_surf->current->age = 1;
+      dri2_surf->back = NULL;
+   }
+
+   (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
+   (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
+
+   return EGL_TRUE;
+}
+
+static EGLint
+dri2_query_buffer_age(_EGLDriver *drv,
+                      _EGLDisplay *disp, _EGLSurface *surface)
+{
+   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
+   __DRIbuffer buffer;
+
+   if (get_back_bo(dri2_surf, &buffer) < 0) {
+      _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
+      return 0;
+   }
+
+   return dri2_surf->back->age;
+}
+
+static _EGLImage *
+dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
+			     EGLClientBuffer buffer, const EGLint *attr_list)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct gbm_bo *bo = (struct gbm_bo *) buffer;
+   struct dri2_egl_image *dri2_img;
+   uint32_t name;
+   int width, height, pitch, format, cpp;
+
+   if (gbm_bo_export(bo, GBM_BO_IMPORT_GEM_NAME, (void **) &name) < 0) {
+      _eglError(EGL_BAD_NATIVE_PIXMAP, "dri2_create_image_khr_pixmap");
+      return NULL;
+   }
+
+   dri2_img = malloc(sizeof *dri2_img);
+   if (!dri2_img) {
+      _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
+      return NULL;
+   }
+
+   if (!_eglInitImage(&dri2_img->base, disp)) {
+      free(dri2_img);
+      return NULL;
+   }
+
+   width = gbm_bo_get_width(bo);
+   height = gbm_bo_get_height(bo);
+
+   switch (gbm_bo_get_format(bo)) {
+   case GBM_FORMAT_RGB565:
+      cpp = 2;
+      format = __DRI_IMAGE_FORMAT_RGB565;
+      break;
+   case GBM_FORMAT_XRGB8888:
+   case GBM_BO_FORMAT_XRGB8888:
+      cpp = 4;
+      format = __DRI_IMAGE_FORMAT_XRGB8888;
+      break;
+   case GBM_BO_FORMAT_ARGB8888:
+   case GBM_FORMAT_ARGB8888:
+      cpp = 4;
+      format = __DRI_IMAGE_FORMAT_ARGB8888;
+      break;
+   default:
+      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr_pixmap");
+      return NULL;
+   }
+
+   pitch = gbm_bo_get_stride(bo) / cpp;
+
+   dri2_img->dri_image =
+      dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
+                                           width, height, format,
+                                           name, pitch, dri2_img);
+   if (dri2_img->dri_image == NULL) {
+      free(dri2_img);
+      _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
+      return NULL;
+   }
+
+   return &dri2_img->base;
+}
+
+static _EGLImage *
+dri2_drm_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
+                          _EGLContext *ctx, EGLenum target,
+                          EGLClientBuffer buffer, const EGLint *attr_list)
+{
+   (void) drv;
+
+   switch (target) {
+   case EGL_NATIVE_PIXMAP_KHR:
+      return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
+   default:
+      return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
+   }
+}
+
+static int
+dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id)
+{
+   struct gbm_device *gbm = disp->PlatformDisplay;
+   int fd = gbm_device_get_fd(gbm);
+
+   return drmAuthMagic(fd, id);
+}
+
+EGLBoolean
+dri2_initialize_gbm(_EGLDriver *drv, _EGLDisplay *disp)
+{
+   struct dri2_egl_display *dri2_dpy;
+   struct gbm_device *gbm;
+   drm_magic_t magic;
+   int fd = -1;
+   int i;
+
+   dri2_dpy = calloc(1, sizeof *dri2_dpy);
+   if (!dri2_dpy)
+      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
+
+   disp->DriverData = (void *) dri2_dpy;
+
+   gbm = disp->PlatformDisplay;
+   if (gbm == NULL) {
+      fd = open("/dev/dri/card0", O_RDWR);
+      dri2_dpy->own_device = 1;
+      gbm = gbm_create_device(fd);
+      if (gbm == NULL)
+         return EGL_FALSE;
+   }
+
+   fd = gbm_device_get_fd(gbm);
+
+   dri2_dpy->device_name = dri2_get_device_name_for_fd(fd);
+
+   fd = open(dri2_dpy->device_name, O_RDWR);
+   if (fd < 0) {
+      free(dri2_dpy->device_name);
+      free(dri2_dpy);
+      return EGL_FALSE;
+   }
+
+   drmGetMagic(fd, &magic);
+   drmAuthMagic(gbm_device_get_fd(gbm), magic);
+
+   dri2_dpy->fd = fd;
+   dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd);
+
+   if (!dri2_load_driver(disp)) {
+      free(dri2_dpy->device_name);
+      free(dri2_dpy->driver_name);
+      free(dri2_dpy);
+      return EGL_FALSE;
+   }
+
+   dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
+   dri2_dpy->dri2_loader_extension.base.version = 3;
+   dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
+   dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
+   dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
+      dri2_get_buffers_with_format;
+
+   dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
+   dri2_dpy->extensions[1] = &image_lookup_extension.base;
+   dri2_dpy->extensions[2] = &use_invalidate.base;
+   dri2_dpy->extensions[3] = NULL;
+
+   if (!dri2_create_screen(disp)) {
+      dlclose(dri2_dpy->driver);
+      free(dri2_dpy->device_name);
+      free(dri2_dpy->driver_name);
+      free(dri2_dpy);
+      return EGL_FALSE;
+   }
+
+   gbm->surface_lock_front_buffer = lock_front_buffer;
+   gbm->surface_release_buffer = release_buffer;
+   gbm->surface_has_free_buffers = has_free_buffers;
+
+   for (i = 0; dri2_dpy->driver_configs[i]; i++)
+      dri2_add_config(disp, dri2_dpy->driver_configs[i],
+                      i + 1, EGL_WINDOW_BIT, NULL, NULL);
+
+   drv->API.CreateWindowSurface = dri2_create_window_surface;
+   drv->API.DestroySurface = dri2_destroy_surface;
+   drv->API.SwapBuffers = dri2_swap_buffers;
+   drv->API.CreateImageKHR = dri2_drm_create_image_khr;
+   drv->API.QueryBufferAge = dri2_query_buffer_age;
+
+   disp->Extensions.EXT_buffer_age = EGL_TRUE;
+
+#ifdef HAVE_WAYLAND_PLATFORM
+   disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
+#endif
+   dri2_dpy->authenticate = dri2_drm_authenticate;
+
+   /* we're supporting EGL 1.4 */
+   disp->VersionMajor = 1;
+   disp->VersionMinor = 4;
+
+   return EGL_TRUE;
+}
diff --git a/src/egl/main/Makefile.am b/src/egl/main/Makefile.am
index 60cb600..b10359b 100644
--- a/src/egl/main/Makefile.am
+++ b/src/egl/main/Makefile.am
@@ -94,6 +94,11 @@ AM_CFLAGS += -DHAVE_DRM_PLATFORM
 libEGL_la_LIBADD += ../../gbm/libgbm.la
 endif
 
+if HAVE_EGL_PLATFORM_GBM
+AM_CFLAGS += -DHAVE_GBM_PLATFORM
+libEGL_la_LIBADD += ../../gbm/libgbm.la
+endif
+
 if HAVE_EGL_PLATFORM_FBDEV
 AM_CFLAGS += -DHAVE_FBDEV_PLATFORM
 endif
diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c
index 985e781..d974457 100644
--- a/src/egl/main/egldisplay.c
+++ b/src/egl/main/egldisplay.c
@@ -74,7 +74,8 @@ static const struct {
    { _EGL_PLATFORM_DRM, "drm" },
    { _EGL_PLATFORM_FBDEV, "fbdev" },
    { _EGL_PLATFORM_NULL, "null" },
-   { _EGL_PLATFORM_ANDROID, "android" }
+   { _EGL_PLATFORM_ANDROID, "android" },
+   { _EGL_PLATFORM_GBM, "gbm" }
 };
 
 
diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h
index fefd19c..242a187 100644
--- a/src/egl/main/egldisplay.h
+++ b/src/egl/main/egldisplay.h
@@ -46,6 +46,7 @@ enum _egl_platform_type {
    _EGL_PLATFORM_FBDEV,
    _EGL_PLATFORM_NULL,
    _EGL_PLATFORM_ANDROID,
+   _EGL_PLATFORM_GBM,
 
    _EGL_NUM_PLATFORMS,
    _EGL_INVALID_PLATFORM = -1
diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c
index e95fcc7..9998308 100644
--- a/src/gbm/backends/dri/gbm_dri.c
+++ b/src/gbm/backends/dri/gbm_dri.c
@@ -475,6 +475,12 @@ gbm_dri_bo_import(struct gbm_device *gbm,
    return &bo->base.base;
 }
 
+static int
+gbm_dri_bo_export(struct gbm_bo *_bo, uint32_t type, void **buffer)
+{
+   return -1;
+}
+
 static struct gbm_bo *
 create_dumb(struct gbm_device *gbm,
                   uint32_t width, uint32_t height,
@@ -660,6 +666,7 @@ dri_device_create(int fd)
    dri->base.base.fd = fd;
    dri->base.base.bo_create = gbm_dri_bo_create;
    dri->base.base.bo_import = gbm_dri_bo_import;
+   dri->base.base.bo_export = gbm_dri_bo_export;
    dri->base.base.is_format_supported = gbm_dri_is_format_supported;
    dri->base.base.bo_write = gbm_dri_bo_write;
    dri->base.base.bo_destroy = gbm_dri_bo_destroy;
diff --git a/src/gbm/backends/intel/gbm_intel.c b/src/gbm/backends/intel/gbm_intel.c
index dc9f174..9f17df7 100644
--- a/src/gbm/backends/intel/gbm_intel.c
+++ b/src/gbm/backends/intel/gbm_intel.c
@@ -156,6 +156,26 @@ gbm_intel_bo_import(struct gbm_device *gbm,
    return NULL;
 }
 
+static int
+gbm_intel_bo_export(struct gbm_bo *bo, uint32_t type, void **buffer)
+{
+   struct gbm_intel_bo *ibo = gbm_intel_bo(bo);
+   int ret;
+
+   if (type != GBM_BO_IMPORT_GEM_NAME)
+      return -1;
+
+   if (ibo->name == 0) {
+      ret = drm_intel_bo_flink(ibo->bo, &ibo->name);
+      if (ret < 0)
+	 return ret;
+   }
+
+   *((uint32_t *) buffer) = ibo->name;
+
+   return 0;
+}
+
 static struct gbm_surface *
 gbm_intel_surface_create(struct gbm_device *gbm,
                        uint32_t width, uint32_t height,
@@ -202,6 +222,7 @@ gbm_intel_device_create(int fd)
    igbm->base.base.fd = fd;
    igbm->base.base.bo_create = gbm_intel_bo_create;
    igbm->base.base.bo_import = gbm_intel_bo_import;
+   igbm->base.base.bo_export = gbm_intel_bo_export;
    igbm->base.base.is_format_supported = gbm_intel_is_format_supported;
    igbm->base.base.bo_write = gbm_intel_bo_write;
    igbm->base.base.bo_destroy = gbm_intel_bo_destroy;
diff --git a/src/gbm/backends/intel/gbm_intel.h b/src/gbm/backends/intel/gbm_intel.h
index 80bc394..4691ecc 100644
--- a/src/gbm/backends/intel/gbm_intel.h
+++ b/src/gbm/backends/intel/gbm_intel.h
@@ -47,6 +47,7 @@ struct gbm_intel_bo {
    struct gbm_drm_bo base;
 
    drm_intel_bo *bo;
+   uint32_t name;
 };
 
 struct gbm_intel_surface {
diff --git a/src/gbm/main/gbm.c b/src/gbm/main/gbm.c
index c58576d..b68ead0 100644
--- a/src/gbm/main/gbm.c
+++ b/src/gbm/main/gbm.c
@@ -340,12 +340,13 @@ gbm_bo_create(struct gbm_device *gbm,
  * Create a gbm buffer object from an foreign object
  *
  * This function imports a foreign object and creates a new gbm bo for it.
- * This enabled using the foreign object with a display API such as KMS.
- * Currently two types of foreign objects are supported, indicated by the type
- * argument:
+ * This enables using the foreign object with a display API such as KMS.
+ * Currently the following types of foreign objects are supported, indicated
+ * by the type argument:
  *
  *   GBM_BO_IMPORT_WL_BUFFER
  *   GBM_BO_IMPORT_EGL_IMAGE
+ *   GBM_BO_IMPORT_GEM_NAME
  *
  * The the gbm bo shares the underlying pixels but its life-time is
  * independent of the foreign object.
@@ -368,6 +369,28 @@ gbm_bo_import(struct gbm_device *gbm,
 }
 
 /**
+ * Create a foreign object from a gbm buffer object
+ *
+ * This function exports a gbm bo as a foreign object. The types of
+ * foreign object supported are the same as the ones supported by the
+ * \ref gbm_bo_import() function.
+ *
+ * The foreign object shares the underlying pixels but its life-time is
+ * independent of the gbm bo.
+ *
+ * \param bo The gbm bo to be exported
+ * \param type The type of object to export to
+ * \param buffer Pointer to the external object
+ *
+ * \return Returns -1 on error, 0 otherwise
+ */
+GBM_EXPORT int
+gbm_bo_export(struct gbm_bo *bo, uint32_t type, void **buffer)
+{
+   return bo->gbm->bo_export(bo, type, buffer);
+}
+
+/**
  * Allocate a surface object
  *
  * \param gbm The gbm device returned from gbm_create_device()
diff --git a/src/gbm/main/gbm.h b/src/gbm/main/gbm.h
index 9d2a030..3854c4c 100644
--- a/src/gbm/main/gbm.h
+++ b/src/gbm/main/gbm.h
@@ -232,11 +232,15 @@ gbm_bo_create(struct gbm_device *gbm,
 
 #define GBM_BO_IMPORT_WL_BUFFER         0x5501
 #define GBM_BO_IMPORT_EGL_IMAGE         0x5502
+#define GBM_BO_IMPORT_GEM_NAME          0x5503
 
 struct gbm_bo *
 gbm_bo_import(struct gbm_device *gbm, uint32_t type,
               void *buffer, uint32_t usage);
 
+int
+gbm_bo_export(struct gbm_bo *bo, uint32_t type, void **buffer);
+
 uint32_t
 gbm_bo_get_width(struct gbm_bo *bo);
 
diff --git a/src/gbm/main/gbmint.h b/src/gbm/main/gbmint.h
index a467bea..a8cf49e 100644
--- a/src/gbm/main/gbmint.h
+++ b/src/gbm/main/gbmint.h
@@ -68,6 +68,7 @@ struct gbm_device {
                                uint32_t usage);
    struct gbm_bo *(*bo_import)(struct gbm_device *gbm, uint32_t type,
                                void *buffer, uint32_t usage);
+   int (*bo_export)(struct gbm_bo *bo, uint32_t type, void **buffer);
    int (*bo_write)(struct gbm_bo *bo, const void *buf, size_t data);
    void (*bo_destroy)(struct gbm_bo *bo);
 
@@ -103,6 +104,8 @@ struct gbm_surface {
    uint32_t height;
    uint32_t format;
    uint32_t flags;
+
+   void *priv;
 };
 
 struct gbm_backend {
-- 
1.7.9.5



More information about the wayland-devel mailing list