Mesa (master): gbm: Add dri backend

Benjamin Franzke bnf at kemper.freedesktop.org
Thu Jun 23 19:07:59 UTC 2011


Module: Mesa
Branch: master
Commit: 2ff797060d4ffbe1c1bf5b605ea5d4f9e588da41
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=2ff797060d4ffbe1c1bf5b605ea5d4f9e588da41

Author: Benjamin Franzke <benjaminfranzke at googlemail.com>
Date:   Thu May 26 15:10:50 2011 +0200

gbm: Add dri backend

---

 configure.ac                       |    7 +
 src/gbm/backends/dri/Makefile      |   22 ++
 src/gbm/backends/dri/driver_name.c |   89 +++++++++
 src/gbm/backends/dri/gbm_dri.c     |  378 ++++++++++++++++++++++++++++++++++++
 src/gbm/backends/dri/gbm_driint.h  |   78 ++++++++
 src/gbm/main/Makefile              |    5 +
 src/gbm/main/backend.c             |    3 +
 7 files changed, 582 insertions(+), 0 deletions(-)

diff --git a/configure.ac b/configure.ac
index b5dee9d..249a689 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1271,6 +1271,13 @@ if test "x$enable_gbm" = xyes; then
     PKG_CHECK_MODULES([LIBUDEV], [libudev], [],
                       AC_MSG_ERROR([gbm needs udev]))
     GBM_LIB_DEPS="$DLOPEN_LIBS $LIBUDEV_LIBS"
+
+    if test "$mesa_driver" = dri; then
+        GBM_BACKEND_DIRS="$GBM_BACKEND_DIRS dri"
+        if test "$SHARED_GLAPI" -eq 0; then
+            AC_MSG_ERROR([gbm_dri requires --enable-shared-glapi])
+        fi
+    fi
 fi
 AC_SUBST([GBM_LIB_DEPS])
 AC_SUBST([GBM_BACKEND_DIRS])
diff --git a/src/gbm/backends/dri/Makefile b/src/gbm/backends/dri/Makefile
new file mode 100644
index 0000000..78fb329
--- /dev/null
+++ b/src/gbm/backends/dri/Makefile
@@ -0,0 +1,22 @@
+# src/gbm/backends/dri/Makefile
+
+TOP = ../../../..
+include $(TOP)/configs/current
+
+GBM_BACKEND = gbm_dri
+GBM_SOURCES = gbm_dri.c driver_name.c
+
+GBM_INCLUDES = \
+	-I$(TOP)/include \
+	-I$(TOP)/src/gbm/main \
+
+GBM_LIBS = $(LIBUDEV_LIBS) $(LIBDRM_LIB) -L$(TOP)/lib -lglapi 
+
+GBM_CFLAGS = \
+	-DDEFAULT_DRIVER_DIR=\"$(DRI_DRIVER_SEARCH_DIR)\" \
+	$(LIBUDEV_CFLAGS) \
+	$(LIBDRM_CFLAGS)
+
+GBM_BUILTIN=true
+
+include ../Makefile.template
diff --git a/src/gbm/backends/dri/driver_name.c b/src/gbm/backends/dri/driver_name.c
new file mode 100644
index 0000000..2ed209f
--- /dev/null
+++ b/src/gbm/backends/dri/driver_name.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Kristian Høgsberg <krh at bitplanet.net>
+ *    Benjamin Franzke <benjaminfranzke at googlemail.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <libudev.h>
+
+#include "gbm_driint.h"
+#define DRIVER_MAP_DRI2_ONLY
+#include "pci_ids/pci_id_driver_map.h"
+
+char *
+dri_fd_get_driver_name(int fd)
+{
+   struct udev *udev;
+   struct udev_device *device, *parent;
+   const char *pci_id;
+   char *driver = NULL;
+   int vendor_id, chip_id, i, j;
+
+   udev = udev_new();
+   device = _gbm_udev_device_new_from_fd(udev, fd);
+   if (device == NULL)
+      return NULL;
+
+   parent = udev_device_get_parent(device);
+   if (parent == NULL) {
+      fprintf(stderr, "gbm: could not get parent device");
+      goto out;
+   }
+
+   pci_id = udev_device_get_property_value(parent, "PCI_ID");
+   if (pci_id == NULL ||
+       sscanf(pci_id, "%x:%x", &vendor_id, &chip_id) != 2) {
+      fprintf(stderr, "gbm: malformed or no PCI ID");
+      goto out;
+   }
+
+   for (i = 0; driver_map[i].driver; i++) {
+      if (vendor_id != driver_map[i].vendor_id)
+         continue;
+      if (driver_map[i].num_chips_ids == -1) {
+         driver = strdup(driver_map[i].driver);
+         _gbm_log("pci id for %d: %04x:%04x, driver %s",
+                  fd, vendor_id, chip_id, driver);
+         goto out;
+      }
+
+      for (j = 0; j < driver_map[i].num_chips_ids; j++)
+         if (driver_map[i].chip_ids[j] == chip_id) {
+            driver = strdup(driver_map[i].driver);
+            _gbm_log("pci id for %d: %04x:%04x, driver %s",
+                     fd, vendor_id, chip_id, driver);
+            goto out;
+         }
+   }
+
+out:
+   udev_device_unref(device);
+   udev_unref(udev);
+
+   return driver;
+}
diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c
new file mode 100644
index 0000000..6bb7848
--- /dev/null
+++ b/src/gbm/backends/dri/gbm_dri.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Benjamin Franzke <benjaminfranzke at googlemail.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include <GL/gl.h> /* dri_interface needs GL types */
+#include <GL/internal/dri_interface.h>
+
+#include "gbm_driint.h"
+
+#include "gbmint.h"
+
+static __DRIimage *
+dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
+{
+   struct gbm_dri_device *dri = data;
+
+   if (dri->lookup_image == NULL)
+      return NULL;
+
+   return dri->lookup_image(screen, image, dri->lookup_user_data);
+}
+
+const __DRIuseInvalidateExtension use_invalidate = {
+   { __DRI_USE_INVALIDATE, 1 }
+};
+
+const __DRIimageLookupExtension image_lookup_extension = {
+   { __DRI_IMAGE_LOOKUP, 1 },
+   dri_lookup_egl_image
+};
+
+struct dri_extension_match {
+   const char *name;
+   int version;
+   int offset;
+};
+
+static struct dri_extension_match dri_core_extensions[] = {
+   { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) },
+   { NULL, 0, 0 }
+};
+
+static struct dri_extension_match gbm_dri_device_extensions[] = {
+   { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) },
+   { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) },
+   { NULL, 0, 0 }
+};
+
+static int
+dri_bind_extensions(struct gbm_dri_device *dri,
+                    struct dri_extension_match *matches,
+                    const __DRIextension **extensions)
+{
+   int i, j, ret = 0;
+   void *field;
+
+   for (i = 0; extensions[i]; i++) {
+      for (j = 0; matches[j].name; j++) {
+         if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
+             extensions[i]->version >= matches[j].version) {
+            field = ((char *) dri + matches[j].offset);
+            *(const __DRIextension **) field = extensions[i];
+         }
+      }
+   }
+
+   for (j = 0; matches[j].name; j++) {
+      field = ((char *) dri + matches[j].offset);
+      if (*(const __DRIextension **) field == NULL) {
+         ret = -1;
+      }
+   }
+
+   return ret;
+}
+
+static int
+dri_load_driver(struct gbm_dri_device *dri)
+{
+   const __DRIextension **extensions;
+   char path[PATH_MAX], *search_paths, *p, *next, *end;
+
+   search_paths = NULL;
+   if (geteuid() == getuid()) {
+      /* don't allow setuid apps to use GBM_DRIVERS_PATH */
+      search_paths = getenv("GBM_DRIVERS_PATH");
+   }
+   if (search_paths == NULL)
+      search_paths = DEFAULT_DRIVER_DIR;
+
+   dri->driver = NULL;
+   end = search_paths + strlen(search_paths);
+   for (p = search_paths; p < end && dri->driver == NULL; p = next + 1) {
+      int len;
+      next = strchr(p, ':');
+      if (next == NULL)
+         next = end;
+
+      len = next - p;
+#if GLX_USE_TLS
+      snprintf(path, sizeof path,
+               "%.*s/tls/%s_dri.so", len, p, dri->base.driver_name);
+      dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
+#endif
+      if (dri->driver == NULL) {
+         snprintf(path, sizeof path,
+                  "%.*s/%s_dri.so", len, p, dri->base.driver_name);
+         dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
+         if (dri->driver == NULL)
+            fprintf(stderr, "failed to open %s: %s\n", path, dlerror());
+      }
+   }
+
+   if (dri->driver == NULL) {
+      fprintf(stderr, "gbm: failed to open any driver (search paths %s)",
+              search_paths);
+      return -1;
+   }
+
+   extensions = dlsym(dri->driver, __DRI_DRIVER_EXTENSIONS);
+   if (extensions == NULL) {
+      fprintf(stderr, "gbm: driver exports no extensions (%s)", dlerror());
+      dlclose(dri->driver);
+      return -1;
+   }
+
+
+   if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
+      dlclose(dri->driver);
+      fprintf(stderr, "failed to bind extensions\n");
+      return -1;
+   }
+
+   return 0;
+}
+
+static int
+dri_screen_create(struct gbm_dri_device *dri)
+{
+   const __DRIextension **extensions;
+   int ret = 0;
+
+   dri->base.driver_name = dri_fd_get_driver_name(dri->base.base.fd);
+   if (dri->base.driver_name == NULL)
+      return -1;
+
+   ret = dri_load_driver(dri);
+   if (ret) {
+      fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name);
+      return ret;
+   };
+
+   dri->extensions[0] = &image_lookup_extension.base;
+   dri->extensions[1] = &use_invalidate.base;
+   dri->extensions[2] = NULL;
+
+   if (dri->dri2 == NULL)
+      return -1;
+
+   dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd,
+                                            dri->extensions,
+                                            &dri->driver_configs, dri);
+
+   extensions = dri->core->getExtensions(dri->screen);
+   if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
+      ret = -1;
+      goto free_screen;
+   }
+
+   dri->lookup_image = NULL;
+   dri->lookup_user_data = NULL;
+
+   return 0;
+
+free_screen:
+   dri->core->destroyScreen(dri->screen);
+
+   return ret;
+}
+
+static int
+gbm_dri_is_format_supported(struct gbm_device *gbm,
+                            enum gbm_bo_format format,
+                            uint32_t usage)
+{
+   switch (format) {
+   case GBM_BO_FORMAT_XRGB8888:
+      break;
+   case GBM_BO_FORMAT_ARGB8888:
+      if (usage & GBM_BO_USE_SCANOUT)
+         return 0;
+      break;
+   default:
+      return 0;
+   }
+
+   if (usage & GBM_BO_USE_CURSOR_64X64 &&
+       usage & GBM_BO_USE_RENDERING)
+      return 0;
+
+   return 1;
+}
+
+static void
+gbm_dri_bo_destroy(struct gbm_bo *_bo)
+{
+   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
+   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
+
+   dri->image->destroyImage(bo->image);
+   free(bo);
+}
+
+static struct gbm_bo *
+gbm_dri_bo_create_from_egl_image(struct gbm_device *gbm,
+                                 void *egl_dpy, void *egl_img,
+                                 uint32_t width, uint32_t height,
+                                 uint32_t usage)
+{
+   struct gbm_dri_device *dri = gbm_dri_device(gbm);
+   struct gbm_dri_bo *bo;
+
+   (void) egl_dpy;
+
+   if (dri->lookup_image == NULL)
+      return NULL;
+
+   bo = calloc(1, sizeof *bo);
+   if (bo == NULL)
+      return NULL;
+
+   bo->base.base.gbm = gbm;
+   bo->base.base.width = width;
+   bo->base.base.height = height;
+
+   __DRIimage *tmp = dri->lookup_image(dri->screen, egl_img,
+                                       dri->lookup_user_data);
+
+   bo->image = dri->image->dupImage(tmp, bo);
+   if (bo->image == NULL)
+      return NULL;
+   
+   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
+                          &bo->base.base.handle.s32);
+   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
+                          (int *) &bo->base.base.pitch);
+
+   return &bo->base.base;
+}
+
+static struct gbm_bo *
+gbm_dri_bo_create(struct gbm_device *gbm,
+                  uint32_t width, uint32_t height,
+                  enum gbm_bo_format format, uint32_t usage)
+{
+   struct gbm_dri_device *dri = gbm_dri_device(gbm);
+   struct gbm_dri_bo *bo;
+   int dri_format;
+   unsigned dri_use = 0;
+
+   bo = calloc(1, sizeof *bo);
+   if (bo == NULL)
+      return NULL;
+
+   bo->base.base.gbm = gbm;
+   bo->base.base.width = width;
+   bo->base.base.height = height;
+
+   switch (format) {
+   case GBM_BO_FORMAT_XRGB8888:
+      dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
+      break;
+   case GBM_BO_FORMAT_ARGB8888:
+      dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
+      break;
+   default:
+      return NULL;
+   }
+
+   if (usage & GBM_BO_USE_SCANOUT)
+      dri_use |= __DRI_IMAGE_USE_SCANOUT;
+   if (usage & GBM_BO_USE_CURSOR_64X64)
+      dri_use |= __DRI_IMAGE_USE_CURSOR;
+
+   bo->image =
+      dri->image->createImage(dri->screen,
+                              width, height,
+                              dri_format, dri_use,
+                              bo);
+   if (bo->image == NULL)
+      return NULL;
+
+   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
+                          &bo->base.base.handle.s32);
+   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
+                          (int *) &bo->base.base.pitch);
+
+   return &bo->base.base;
+}
+
+static void
+dri_destroy(struct gbm_device *gbm)
+{
+   struct gbm_dri_device *dri = gbm_dri_device(gbm);
+
+   dri->core->destroyScreen(dri->screen);
+   free(dri->driver_configs);
+   dlclose(dri->driver);
+   free(dri->base.driver_name);
+
+   free(dri);
+}
+
+static struct gbm_device *
+dri_device_create(int fd)
+{
+   struct gbm_dri_device *dri;
+   int ret;
+
+   dri = calloc(1, sizeof *dri);
+
+   dri->base.base.fd = fd;
+   dri->base.base.bo_create = gbm_dri_bo_create;
+   dri->base.base.bo_create_from_egl_image = gbm_dri_bo_create_from_egl_image;
+   dri->base.base.is_format_supported = gbm_dri_is_format_supported;
+   dri->base.base.bo_destroy = gbm_dri_bo_destroy;
+   dri->base.base.destroy = dri_destroy;
+
+   dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
+   dri->base.base.name = "drm";
+
+   ret = dri_screen_create(dri);
+   if (ret) {
+      free(dri);
+      return NULL;
+   }
+
+   return &dri->base.base;
+}
+
+struct gbm_backend gbm_dri_backend = {
+   .backend_name = "dri",
+   .create_device = dri_device_create,
+};
diff --git a/src/gbm/backends/dri/gbm_driint.h b/src/gbm/backends/dri/gbm_driint.h
new file mode 100644
index 0000000..c5b5e17
--- /dev/null
+++ b/src/gbm/backends/dri/gbm_driint.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Benjamin Franzke <benjaminfranzke at googlemail.com>
+ */
+
+#ifndef _GBM_DRI_INTERNAL_H_
+#define _GBM_DRI_INTERNAL_H_
+
+#include "gbmint.h"
+
+#include "common.h"
+#include "common_drm.h"
+
+#include <GL/gl.h> /* dri_interface needs GL types */
+#include "GL/internal/dri_interface.h"
+
+struct gbm_dri_device {
+   struct gbm_drm_device base;
+
+   void *driver;
+
+   __DRIscreen *screen;
+
+   __DRIcoreExtension   *core;
+   __DRIdri2Extension   *dri2;
+   __DRIimageExtension  *image;
+
+   const __DRIconfig   **driver_configs;
+   const __DRIextension *extensions[3];
+
+   __DRIimage *(*lookup_image)(__DRIscreen *screen, void *image, void *data);
+   void *lookup_user_data;
+};
+
+struct gbm_dri_bo {
+   struct gbm_drm_bo base;
+
+   __DRIimage *image;
+};
+
+static inline struct gbm_dri_device *
+gbm_dri_device(struct gbm_device *gbm)
+{
+   return (struct gbm_dri_device *) gbm;
+}
+
+static inline struct gbm_dri_bo *
+gbm_dri_bo(struct gbm_bo *bo)
+{
+   return (struct gbm_dri_bo *) bo;
+}
+
+char *
+dri_fd_get_driver_name(int fd);
+
+#endif
diff --git a/src/gbm/main/Makefile b/src/gbm/main/Makefile
index 277fba1..5130b9b 100644
--- a/src/gbm/main/Makefile
+++ b/src/gbm/main/Makefile
@@ -23,6 +23,11 @@ LOCAL_CFLAGS = $(LIBUDEV_CFLAGS) $(DLOPEN_CFLAGS) \
 	       -D_OS_UNIX=1 -DMODULEDIR='"$(GBM_BACKEND_INSTALL_DIR)"'
 LOCAL_LIBS =
 
+# Builtin backends
+ifeq ($(filter dri, $(GBM_BACKEND_DIRS)),dri)
+LOCAL_LIBS += $(TOP)/src/gbm/backends/dri/libgbm_dri.a
+endif
+
 .c.o:
 	$(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $(LOCAL_CFLAGS) $< -o $@
 
diff --git a/src/gbm/main/backend.c b/src/gbm/main/backend.c
index 2079bbb..84db9e8 100644
--- a/src/gbm/main/backend.c
+++ b/src/gbm/main/backend.c
@@ -36,12 +36,15 @@
 
 #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
 
+extern const struct gbm_backend gbm_dri_backend;
+
 struct backend_desc {
    const char *name;
    const struct gbm_backend *builtin;
 };
 
 static const struct backend_desc backends[] = {
+   { "gbm_dri.so", &gbm_dri_backend },
 };
 
 static const void *




More information about the mesa-commit mailing list