[Mesa-dev] [PATCH] gbm: add support for loading third-party backend

Qiang Yu Qiang.Yu at amd.com
Tue Jan 24 03:36:48 UTC 2017


Third-party can put their backend to a directory configured with
'--with-gbm-backenddir' and create a /etc/gbm.conf.d/*.conf file
which contains the backend so file name to overwrite the default
builtin DRI backend.

The /etc/gbm.conf.d/*.conf will be sorted and the backends added
will be tried one-by-one until one can successfully create a gbm
device. The default DRI backend is tried at last.

People can still use GBM_BACKEND to overwrite the backend try
order.

Signed-off-by: Qiang Yu <Qiang.Yu at amd.com>
---
 configure.ac           |  7 +++++
 src/gbm/Makefile.am    |  1 +
 src/gbm/main/backend.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 82 insertions(+), 6 deletions(-)

diff --git a/configure.ac b/configure.ac
index 64ace9d..21aea75 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2201,6 +2201,13 @@ AC_ARG_WITH([d3d-libdir],
     [D3D_DRIVER_INSTALL_DIR="${libdir}/d3d"])
 AC_SUBST([D3D_DRIVER_INSTALL_DIR])
 
+AC_ARG_WITH([gbm-backenddir],
+    [AS_HELP_STRING([--with-gbm-backenddir=DIR],
+        [directory for the GBM backends @<:@${libdir}/gbm@:>@])],
+    [GBM_BACKEND_DIR="$withval"],
+    [GBM_BACKEND_DIR='${libdir}/gbm'])
+AC_SUBST([GBM_BACKEND_DIR])
+
 dnl
 dnl Gallium helper functions
 dnl
diff --git a/src/gbm/Makefile.am b/src/gbm/Makefile.am
index e34c1d4..a613005 100644
--- a/src/gbm/Makefile.am
+++ b/src/gbm/Makefile.am
@@ -39,6 +39,7 @@ libgbm_la_SOURCES += \
 
 AM_CFLAGS += \
 	-DDEFAULT_DRIVER_DIR='"$(DRI_DRIVER_SEARCH_DIR)"' \
+	-DGBM_BACKEND_DIR='"$(GBM_BACKEND_DIR)"' \
 	$(LIBDRM_CFLAGS) \
 	$(PTHREADSTUBS_CFLAGS)
 
diff --git a/src/gbm/main/backend.c b/src/gbm/main/backend.c
index 37ec9c1..0b89dde 100644
--- a/src/gbm/main/backend.c
+++ b/src/gbm/main/backend.c
@@ -31,6 +31,10 @@
 #include <string.h>
 #include <limits.h>
 
+#include <dirent.h>
+#include <fnmatch.h>
+#include <dlfcn.h>
+
 #include "backend.h"
 
 #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
@@ -42,12 +46,18 @@ struct backend_desc {
    const struct gbm_backend *builtin;
 };
 
-static const struct backend_desc backends[] = {
+static const struct backend_desc builtin_backends[] = {
    { "gbm_dri.so", &gbm_dri_backend },
 };
 
+#define MAX_BACKENDS 10
+static struct backend_desc backends[MAX_BACKENDS];
+static int num_backends = 0;
+
+#define CONFIG_DIR "/etc/gbm.conf.d"
+
 static const void *
-load_backend(const struct backend_desc *backend)
+load_backend(struct backend_desc *backend)
 {
    const void *init = NULL;
 
@@ -57,17 +67,28 @@ load_backend(const struct backend_desc *backend)
    if (backend->builtin) {
       init = backend->builtin;
    }
+   else {
+      char path[PATH_MAX];
+      void *module;
+
+      snprintf(path, PATH_MAX, "%s/%s", GBM_BACKEND_DIR, backend->name);
+      module = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
+      if (module) {
+         backend->builtin = dlsym(module, "gbm_backend");
+         init = backend->builtin;
+      }
+   }
 
    return init;
 }
 
-static const struct backend_desc *
+static struct backend_desc *
 find_backend(const char *name)
 {
-   const struct backend_desc *backend = NULL;
+   struct backend_desc *backend = NULL;
    unsigned i;
 
-   for (i = 0; i < ARRAY_SIZE(backends); ++i) {
+   for (i = 0; i < num_backends; ++i) {
       if (strcmp(backends[i].name, name) == 0) {
          backend = &backends[i];
          break;
@@ -77,6 +98,50 @@ find_backend(const char *name)
    return backend;
 }
 
+static int
+scandir_filter(const struct dirent *ent)
+{
+    if (ent->d_type != DT_REG && ent->d_type != DT_LNK &&
+        ent->d_type != DT_UNKNOWN)
+       return 0;
+
+    if (fnmatch("*.conf", ent->d_name, 0))
+       return 0;
+
+    return 1;
+}
+
+static void
+init_backends(void)
+{
+   int i, count;
+   struct dirent **entries = NULL;
+
+   count = scandir(CONFIG_DIR, &entries, scandir_filter, alphasort);
+   for (i = 0; i < count; i++) {
+      char path[PATH_MAX];
+      FILE *file;
+
+      snprintf(path, PATH_MAX, "%s/%s", CONFIG_DIR, entries[i]->d_name);
+      if ((file = fopen(path, "r"))) {
+         while (fgets(path, PATH_MAX, file)) {
+            int n = strlen(path);
+            if (path[n - 1] == '\n')
+               path[n - 1] = '\0';
+            if (!fnmatch("*.so", path, 0) &&
+                num_backends < MAX_BACKENDS - ARRAY_SIZE(builtin_backends)) {
+               backends[num_backends].name = strdup(path);
+               backends[num_backends++].builtin = NULL;
+            }
+         }
+         fclose(file);
+      }
+   }
+
+   memcpy(backends + num_backends, builtin_backends, sizeof(builtin_backends));
+   num_backends += ARRAY_SIZE(builtin_backends);
+}
+
 struct gbm_device *
 _gbm_create_device(int fd)
 {
@@ -85,6 +150,9 @@ _gbm_create_device(int fd)
    unsigned i;
    const char *b;
 
+   if (!num_backends)
+      init_backends();
+
    b = getenv("GBM_BACKEND");
    if (b)
       backend = load_backend(find_backend(b));
@@ -92,7 +160,7 @@ _gbm_create_device(int fd)
    if (backend)
       dev = backend->create_device(fd);
 
-   for (i = 0; i < ARRAY_SIZE(backends) && dev == NULL; ++i) {
+   for (i = 0; i < num_backends && dev == NULL; ++i) {
       backend = load_backend(&backends[i]);
       if (backend == NULL)
          continue;
-- 
2.7.4



More information about the mesa-dev mailing list