[Mesa-dev] [PATCH v2] gbm: add support for loading third-party backend (v2)
Qiang Yu
Qiang.Yu at amd.com
Fri Apr 7 07:28:04 UTC 2017
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.Yu at 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 <benjaminfranzke at 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 <benjaminfranzke at 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
More information about the mesa-dev
mailing list