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:
James Jones
2019-12-13 18:05:39 -08:00
committed by Marge Bot
parent 8c935464ad
commit 68902822d6
3 changed files with 125 additions and 1 deletions

View File

@@ -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);
}