diff options
author | Eric Engestrom <eric@igalia.com> | 2022-12-09 20:52:15 +0000 |
---|---|---|
committer | Marge Bot <emma+marge@anholt.net> | 2023-02-12 17:11:16 +0000 |
commit | 013f05872c81ba2ac98b03fa4b8711e1b95b64b6 (patch) | |
tree | e6aac2385c0d31e4d6327612a9ce9d43a635839d /src/gallium/auxiliary/util/u_screen.c | |
parent | 1dea6aea204929d044f852c92f7441336ca500b9 (diff) |
gallium: move etnaviv screen_lookup_or_create function to common code
Signed-off-by: Eric Engestrom <eric@igalia.com>
Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20180>
Diffstat (limited to 'src/gallium/auxiliary/util/u_screen.c')
-rw-r--r-- | src/gallium/auxiliary/util/u_screen.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/gallium/auxiliary/util/u_screen.c b/src/gallium/auxiliary/util/u_screen.c index c66bf9c9b70..235b544f5a3 100644 --- a/src/gallium/auxiliary/util/u_screen.c +++ b/src/gallium/auxiliary/util/u_screen.c @@ -21,10 +21,16 @@ * IN THE SOFTWARE. */ +#include <sys/stat.h> + #include "pipe/p_screen.h" #include "util/u_screen.h" #include "util/u_debug.h" +#include "util/os_file.h" #include "util/os_time.h" +#include "util/simple_mtx.h" +#include "util/u_hash_table.h" +#include "util/u_pointer.h" /** * Helper to use from a pipe_screen->get_param() implementation to return @@ -536,3 +542,129 @@ uint64_t u_default_get_timestamp(UNUSED struct pipe_screen *screen) { return os_time_get_nano(); } + +static uint32_t +hash_file_description(const void *key) +{ + int fd = pointer_to_intptr(key); + struct stat stat; + + // File descriptions can't be hashed, but it should be safe to assume + // that the same file description will always refer to he same file + if (fstat(fd, &stat) == -1) + return ~0; // Make sure fstat failing won't result in a random hash + + return stat.st_dev ^ stat.st_ino ^ stat.st_rdev; +} + + +static bool +equal_file_description(const void *key1, const void *key2) +{ + int ret; + int fd1 = pointer_to_intptr(key1); + int fd2 = pointer_to_intptr(key2); + struct stat stat1, stat2; + + // If the file descriptors are the same, the file description will be too + // This will also catch sentinels, such as -1 + if (fd1 == fd2) + return true; + + ret = os_same_file_description(fd1, fd2); + if (ret >= 0) + return (ret == 0); + + { + static bool has_warned; + if (!has_warned) + fprintf(stderr, "os_same_file_description couldn't determine if " + "two DRM fds reference the same file description. (%s)\n" + "Let's just assume that file descriptors for the same file probably" + "share the file description instead. This may cause problems when" + "that isn't the case.\n", strerror(errno)); + has_warned = true; + } + + // Let's at least check that it's the same file, different files can't + // have the same file descriptions + fstat(fd1, &stat1); + fstat(fd2, &stat2); + + return stat1.st_dev == stat2.st_dev && + stat1.st_ino == stat2.st_ino && + stat1.st_rdev == stat2.st_rdev; +} + + +static struct hash_table * +hash_table_create_file_description_keys(void) +{ + return _mesa_hash_table_create(NULL, hash_file_description, equal_file_description); +} + +static struct hash_table *fd_tab = NULL; + +static simple_mtx_t screen_mutex = SIMPLE_MTX_INITIALIZER; + +static void +drm_screen_destroy(struct pipe_screen *pscreen) +{ + boolean destroy; + + simple_mtx_lock(&screen_mutex); + destroy = --pscreen->refcnt == 0; + if (destroy) { + int fd = pscreen->get_screen_fd(pscreen); + _mesa_hash_table_remove_key(fd_tab, intptr_to_pointer(fd)); + + if (!fd_tab->entries) { + _mesa_hash_table_destroy(fd_tab, NULL); + fd_tab = NULL; + } + } + simple_mtx_unlock(&screen_mutex); + + if (destroy) { + pscreen->destroy = pscreen->winsys_priv; + pscreen->destroy(pscreen); + } +} + +struct pipe_screen * +u_pipe_screen_lookup_or_create(int gpu_fd, + const struct pipe_screen_config *config, + struct renderonly *ro, + pipe_screen_create_function screen_create) +{ + struct pipe_screen *pscreen = NULL; + + simple_mtx_lock(&screen_mutex); + if (!fd_tab) { + fd_tab = hash_table_create_file_description_keys(); + if (!fd_tab) + goto unlock; + } + + pscreen = util_hash_table_get(fd_tab, intptr_to_pointer(gpu_fd)); + if (pscreen) { + pscreen->refcnt++; + } else { + pscreen = screen_create(gpu_fd, config, ro); + if (pscreen) { + pscreen->refcnt = 1; + int fd = pscreen->get_screen_fd(pscreen); + _mesa_hash_table_insert(fd_tab, intptr_to_pointer(fd), pscreen); + + /* Bit of a hack, to avoid circular linkage dependency, + * ie. pipe driver having to call in to winsys, we + * override the pipe drivers screen->destroy() */ + pscreen->winsys_priv = pscreen->destroy; + pscreen->destroy = drm_screen_destroy; + } + } + +unlock: + simple_mtx_unlock(&screen_mutex); + return pscreen; +} |