[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