V2: 1. export gbmint.h and test backend/libgbm ABI compatible 2. drop GBM_BACKEND_DIR, specify backend path in config file 3. add GBM_CONFIG_DIR for config file 4. add per backend priority 5. take care of thread safe
Third-party can put their backend to a directory and create a /etc/gbm.conf.d/*.conf file which contains the backend so file path 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. /etc/gbm.conf.d/*.conf can also contain a "priority" field. backend with bigger number will be tried first. Default priority is 1000 inlcuding the builtin backend. GBM config file example: lib:/opt/amdgpu-pro/lib/gbm/amdgpu.so priority:2000 People can still use GBM_BACKEND to overwrite the backend try order. Signed-off-by: Qiang Yu <qiang...@amd.com> --- configure.ac | 9 +++ src/gbm/Makefile.am | 11 +++- src/gbm/backends/dri/gbm_dri.c | 1 + src/gbm/main/backend.c | 130 ++++++++++++++++++++++++++++++++++++++--- src/gbm/main/gbmint.h | 7 ++- 5 files changed, 146 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 70885fb..792d1b2 100644 --- a/configure.ac +++ b/configure.ac @@ -2221,6 +2221,15 @@ AC_ARG_WITH([d3d-libdir], [D3D_DRIVER_INSTALL_DIR="${libdir}/d3d"]) AC_SUBST([D3D_DRIVER_INSTALL_DIR]) +dnl Directory for GBM + +AC_ARG_WITH([gbm-configdir], + [AS_HELP_STRING([--with-gbm-configdir=DIR], + [directory for the GBM configs @<:@/etc/gbm.conf.d@:>@])], + [GBM_CONFIG_DIR="$withval"], + [GBM_CONFIG_DIR='/etc/gbm.conf.d']) +AC_SUBST([GBM_CONFIG_DIR]) + dnl dnl r300 doesn't strictly require LLVM, but for performance reasons we dnl highly recommend LLVM usage. So require it at least on x86 and x86_64 diff --git a/src/gbm/Makefile.am b/src/gbm/Makefile.am index e34c1d4..2e29931 100644 --- a/src/gbm/Makefile.am +++ b/src/gbm/Makefile.am @@ -8,11 +8,17 @@ AM_CFLAGS = \ -I$(top_srcdir)/src/loader \ -I$(top_srcdir)/src/gbm/main \ $(DLOPEN_CFLAGS) \ + $(PTHREAD_CFLAGS) \ $(DEFINES) \ $(VISIBILITY_CFLAGS) +AM_CFLAGS += \ + -DGBM_CONFIG_DIR='"$(GBM_CONFIG_DIR)"' + lib_LTLIBRARIES = libgbm.la -include_HEADERS = main/gbm.h +include_HEADERS = \ + main/gbm.h \ + main/gbmint.h libgbm_la_SOURCES = \ $(gbm_core_FILES) @@ -25,7 +31,8 @@ libgbm_la_LDFLAGS = \ libgbm_la_LIBADD = \ $(top_builddir)/src/loader/libloader.la \ - $(DLOPEN_LIBS) + $(DLOPEN_LIBS) \ + $(PTHREAD_LIBS) if HAVE_PLATFORM_WAYLAND AM_CPPFLAGS = -DHAVE_WAYLAND_PLATFORM diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c index 189a8fc..f8d90bd 100644 --- a/src/gbm/backends/dri/gbm_dri.c +++ b/src/gbm/backends/dri/gbm_dri.c @@ -1393,4 +1393,5 @@ err_dri: struct gbm_backend gbm_dri_backend = { .backend_name = "dri", .create_device = dri_device_create, + .abi_version = GBM_BACKEND_ABI_VERSION, }; diff --git a/src/gbm/main/backend.c b/src/gbm/main/backend.c index 37ec9c1..687fda6 100644 --- a/src/gbm/main/backend.c +++ b/src/gbm/main/backend.c @@ -25,13 +25,20 @@ * Benjamin Franzke <benjaminfran...@googlemail.com> */ +#include <stdbool.h> #include <stdio.h> #include <stddef.h> #include <stdlib.h> #include <string.h> #include <limits.h> +#include <dirent.h> +#include <fnmatch.h> +#include <dlfcn.h> +#include <pthread.h> + #include "backend.h" +#include "gbmint.h" #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) @@ -40,34 +47,69 @@ extern const struct gbm_backend gbm_dri_backend; struct backend_desc { const char *name; const struct gbm_backend *builtin; + int priority; + bool bad; }; -static const struct backend_desc backends[] = { - { "gbm_dri.so", &gbm_dri_backend }, +#define GBM_BACKEND_DEFAULT_PRIORITY 1000 + +static const struct backend_desc builtin_backends[] = { + { + .name = "gbm_dri.so", + .builtin = &gbm_dri_backend, + .priority = GBM_BACKEND_DEFAULT_PRIORITY, + }, }; +#define MAX_BACKENDS 16 +static struct backend_desc backends[MAX_BACKENDS]; +static int num_backends = 0; + static const void * -load_backend(const struct backend_desc *backend) +load_backend(struct backend_desc *backend) { const void *init = NULL; + static pthread_mutex_t backends_mutex = PTHREAD_MUTEX_INITIALIZER; if (backend == NULL) return NULL; + pthread_mutex_lock(&backends_mutex); + if (backend->builtin) { init = backend->builtin; } + else if (!backend->bad) { + void *module; + + module = dlopen(backend->name, RTLD_NOW | RTLD_GLOBAL); + if (module) { + backend->builtin = dlsym(module, "gbm_backend"); + if (backend->builtin && + backend->builtin->abi_version == GBM_BACKEND_ABI_VERSION) + init = backend->builtin; + else { + backend->builtin = NULL; + backend->bad = true; + dlclose(module); + } + } + else + backend->bad = true; + } + + pthread_mutex_unlock(&backends_mutex); 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 +119,75 @@ 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, j, count; + struct dirent **entries = NULL; + + count = scandir(GBM_CONFIG_DIR, &entries, scandir_filter, alphasort); + for (i = 0; i < count; i++) { + char line[PATH_MAX]; + FILE *file; + + snprintf(line, PATH_MAX, "%s/%s", GBM_CONFIG_DIR, entries[i]->d_name); + if ((file = fopen(line, "r"))) { + char *name = NULL; + int p = GBM_BACKEND_DEFAULT_PRIORITY; + + while (fgets(line, PATH_MAX, file)) { + int n = strlen(line); + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + + if (!strncmp("lib:", line, 4) && !fnmatch("*.so", line + 4, 0)) + name = strdup(line + 4); + else if (!strncmp("priority:", line, 9)) { + int v = atoi(line + 9); + if (v > 0) + p = v; + } + } + fclose(file); + + if (name && num_backends < MAX_BACKENDS - ARRAY_SIZE(builtin_backends)) { + backends[num_backends].name = name; + backends[num_backends].builtin = NULL; + backends[num_backends].priority = p; + backends[num_backends].bad = false; + num_backends++; + } + } + } + + memcpy(backends + num_backends, builtin_backends, sizeof(builtin_backends)); + num_backends += ARRAY_SIZE(builtin_backends); + + /* sort backends by priority */ + for (i = num_backends - 1; i > 0; i--) { + for (j = i; j > 0; j--) { + if (backends[j].priority > backends[j - 1].priority) { + struct backend_desc t = backends[j - 1]; + backends[j - 1] = backends[j]; + backends[j] = t; + } + } + } +} + struct gbm_device * _gbm_create_device(int fd) { @@ -84,6 +195,9 @@ _gbm_create_device(int fd) struct gbm_device *dev = NULL; unsigned i; const char *b; + static pthread_once_t backends_is_initialized = PTHREAD_ONCE_INIT; + + pthread_once(&backends_is_initialized, init_backends); b = getenv("GBM_BACKEND"); if (b) @@ -92,13 +206,13 @@ _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; dev = backend->create_device(fd); } - + return dev; } diff --git a/src/gbm/main/gbmint.h b/src/gbm/main/gbmint.h index c27a7a5..0fde5f6 100644 --- a/src/gbm/main/gbmint.h +++ b/src/gbm/main/gbmint.h @@ -25,8 +25,8 @@ * Benjamin Franzke <benjaminfran...@googlemail.com> */ -#ifndef INTERNAL_H_ -#define INTERNAL_H_ +#ifndef _GBM_INTERNAL_H_ +#define _GBM_INTERNAL_H_ #include "gbm.h" #include <sys/stat.h> @@ -125,7 +125,10 @@ struct gbm_surface { }; }; +#define GBM_BACKEND_ABI_VERSION 1 + struct gbm_backend { + uint64_t abi_version; const char *backend_name; struct gbm_device *(*create_device)(int fd); }; -- 2.7.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev