summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Jones <jajones@nvidia.com>2019-12-13 18:05:39 -0800
committerMarge Bot <eric+marge@anholt.net>2021-07-06 16:57:59 +0000
commit68902822d6e0133f3e51f08b9ce86c86b34bc651 (patch)
tree39f9ad5193efe62647689ecae0a15bc9efa28d76
parent8c935464ad2d3cf11f03d896a7fcb9d147c61e56 (diff)
gbm: Support dynamically loading named backends
If the user specifies a backend name explicitly via an environment variable and it is not in the list of built-in backends, attempt to load it at runtime. runtime-loaded backends get a new gbm_backend_desc struct instance for each device using them (A small increase in memory usage to eliminate the need for the locking and bookkeeping sharing them would require), so these structures need to be freed when destroying devices using runtime-loaded backends. Signed-off-by: James Jones <jajones@nvidia.com> Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9902>
-rw-r--r--src/gbm/main/backend.c94
-rw-r--r--src/gbm/main/gbm_abi_check.c16
-rw-r--r--src/gbm/main/gbm_backend_abi.h16
3 files changed, 125 insertions, 1 deletions
diff --git a/src/gbm/main/backend.c b/src/gbm/main/backend.c
index b002df92e16..b628c403faa 100644
--- a/src/gbm/main/backend.c
+++ b/src/gbm/main/backend.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2011 Intel Corporation
+ * Copyright © 2021 NVIDIA Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -23,6 +24,7 @@
*
* Authors:
* Benjamin Franzke <benjaminfranzke@googlemail.com>
+ * James Jones <jajones@nvidia.com>
*/
#include <stdio.h>
@@ -31,7 +33,9 @@
#include <string.h>
#include <limits.h>
#include <assert.h>
+#include <dlfcn.h>
+#include "loader.h"
#include "backend.h"
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
@@ -42,12 +46,51 @@ extern const struct gbm_backend gbm_dri_backend;
struct gbm_backend_desc {
const char *name;
const struct gbm_backend *backend;
+ void *lib;
};
static const struct gbm_backend_desc builtin_backends[] = {
{ "dri", &gbm_dri_backend },
};
+static const char *backend_search_path_vars[] = {
+ "GBM_BACKENDS_PATH",
+ NULL
+};
+
+static void
+free_backend_desc(const struct gbm_backend_desc *backend_desc)
+{
+ assert(backend_desc->lib);
+
+ dlclose(backend_desc->lib);
+ free((void *)backend_desc->name);
+ free((void *)backend_desc);
+}
+
+static struct gbm_backend_desc *
+create_backend_desc(const char *name,
+ const struct gbm_backend *backend,
+ void *lib)
+{
+ struct gbm_backend_desc *new_desc = calloc(1, sizeof(*new_desc));
+
+ if (!new_desc)
+ return NULL;
+
+ new_desc->name = strdup(name);
+
+ if (!new_desc->name) {
+ free(new_desc);
+ return NULL;
+ }
+
+ new_desc->backend = backend;
+ new_desc->lib = lib;
+
+ return new_desc;
+}
+
static struct gbm_device *
backend_create_device(const struct gbm_backend_desc *bd, int fd)
{
@@ -56,7 +99,10 @@ backend_create_device(const struct gbm_backend_desc *bd, int fd)
struct gbm_device *dev = bd->backend->v0.create_device(fd, abi_ver);
if (dev) {
- assert(abi_ver == dev->v0.backend_version);
+ if (abi_ver != dev->v0.backend_version) {
+ _gbm_device_destroy(dev);
+ return NULL;
+ }
dev->v0.backend_desc = bd;
}
@@ -64,10 +110,42 @@ backend_create_device(const struct gbm_backend_desc *bd, int fd)
}
static struct gbm_device *
+load_backend(void *lib, int fd, const char *name)
+{
+ struct gbm_device *dev = NULL;
+ struct gbm_backend_desc *backend_desc;
+ const struct gbm_backend *gbm_backend;
+ GBM_GET_BACKEND_PROC_PTR get_backend;
+
+ get_backend = dlsym(lib, GBM_GET_BACKEND_PROC_NAME);
+
+ if (!get_backend)
+ goto fail;
+
+ gbm_backend = get_backend(&gbm_core);
+ backend_desc = create_backend_desc(name, gbm_backend, lib);
+
+ if (!backend_desc)
+ goto fail;
+
+ dev = backend_create_device(backend_desc, fd);
+
+ if (!dev)
+ free_backend_desc(backend_desc);
+
+ return dev;
+
+fail:
+ dlclose(lib);
+ return NULL;
+}
+
+static struct gbm_device *
find_backend(const char *name, int fd)
{
struct gbm_device *dev = NULL;
const struct gbm_backend_desc *bd;
+ void *lib;
unsigned i;
for (i = 0; i < ARRAY_SIZE(builtin_backends); ++i) {
@@ -82,6 +160,16 @@ find_backend(const char *name, int fd)
break;
}
+ if (name && !dev) {
+ lib = loader_open_driver_lib(name, "_gbm",
+ backend_search_path_vars,
+ DEFAULT_BACKENDS_PATH,
+ true);
+
+ if (lib)
+ dev = load_backend(lib, fd, name);
+ }
+
return dev;
}
@@ -114,5 +202,9 @@ _gbm_create_device(int fd)
void
_gbm_device_destroy(struct gbm_device *gbm)
{
+ const struct gbm_backend_desc *backend_desc = gbm->v0.backend_desc;
gbm->v0.destroy(gbm);
+
+ if (backend_desc && backend_desc->lib)
+ free_backend_desc(backend_desc);
}
diff --git a/src/gbm/main/gbm_abi_check.c b/src/gbm/main/gbm_abi_check.c
index 590599a095f..f1137be7baf 100644
--- a/src/gbm/main/gbm_abi_check.c
+++ b/src/gbm/main/gbm_abi_check.c
@@ -216,6 +216,8 @@ struct gbm_core_abi0 {
struct gbm_core_v0_abi0 v0;
};
+typedef const struct gbm_backend *(*GBM_GET_BACKEND_PROC_PTR_abi0)(const struct gbm_core *gbm_core);
+
/*
* Structure/member ABI-checking helper macros
*/
@@ -310,6 +312,17 @@ struct gbm_core_abi0 {
} \
} while (0)
+#define CHECK_PROC(proc, a_ver, b_ver) \
+ do { \
+ proc ## a_ver a; \
+ proc ## b_ver b = NULL; \
+ a = b; \
+ (void)a; \
+ } while (0)
+
+#define CHECK_PROC_CURRENT(proc, a_ver) \
+ CHECK_PROC(proc, a_ver,)
+
int main(int argc, char **argv)
{
/********************************************/
@@ -401,5 +414,8 @@ int main(int argc, char **argv)
/* Size of ABI-versioned substructures verified by above member checks */
CHECK_SIZE_CURRENT (gbm_core, _abi0);
+
+ CHECK_PROC_CURRENT (GBM_GET_BACKEND_PROC_PTR, _abi0);
+
return 0;
}
diff --git a/src/gbm/main/gbm_backend_abi.h b/src/gbm/main/gbm_backend_abi.h
index 1bf73b75120..962ee74f003 100644
--- a/src/gbm/main/gbm_backend_abi.h
+++ b/src/gbm/main/gbm_backend_abi.h
@@ -278,4 +278,20 @@ struct gbm_core {
struct gbm_core_v0 v0;
};
+/**
+ * The entrypoint an external GBM backend exports.
+ *
+ * Prior to creating any devices using the backend, GBM will look up and call
+ * this function to request the backend's interface and convey the loader's
+ * version and exported interface to the backend.
+ *
+ * DO NOT MODIFY THIS FUNCTION NAME OR PROTOTYPE. It must remain unchanged to
+ * preserve backwards compatibility with existing GBM backends.
+ */
+#define GBM_GET_BACKEND_PROC gbmint_get_backend
+#define _GBM_MKSTRX(s) _GBM_MKSTR(s)
+#define _GBM_MKSTR(s) #s
+#define GBM_GET_BACKEND_PROC_NAME _GBM_MKSTRX(GBM_GET_BACKEND_PROC)
+typedef const struct gbm_backend *(*GBM_GET_BACKEND_PROC_PTR)(const struct gbm_core *gbm_core);
+
#endif