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>
This commit is contained in:
@@ -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,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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user