Mesa (main): gbm: Support dynamically loading named backends

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Jul 6 17:27:21 UTC 2021


Module: Mesa
Branch: main
Commit: 68902822d6e0133f3e51f08b9ce86c86b34bc651
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=68902822d6e0133f3e51f08b9ce86c86b34bc651

Author: James Jones <jajones at nvidia.com>
Date:   Fri Dec 13 18:05:39 2019 -0800

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 at nvidia.com>
Reviewed-by: Emil Velikov <emil.l.velikov at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9902>

---

 src/gbm/main/backend.c         | 94 +++++++++++++++++++++++++++++++++++++++++-
 src/gbm/main/gbm_abi_check.c   | 16 +++++++
 src/gbm/main/gbm_backend_abi.h | 16 +++++++
 3 files changed, 125 insertions(+), 1 deletion(-)

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 at googlemail.com>
+ *    James Jones <jajones at 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,18 +99,53 @@ 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;
    }
 
    return dev;
 }
 
+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



More information about the mesa-commit mailing list