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>
This commit is contained in:
Eric Engestrom 2022-12-09 20:52:15 +00:00 committed by Marge Bot
parent 1dea6aea20
commit 013f05872c
6 changed files with 165 additions and 131 deletions

View file

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

View file

@ -24,6 +24,8 @@
#include <stdint.h>
struct pipe_screen;
struct pipe_screen_config;
struct renderonly;
enum pipe_cap;
#ifdef __cplusplus
@ -36,6 +38,15 @@ u_pipe_screen_get_param_defaults(struct pipe_screen *pscreen,
uint64_t u_default_get_timestamp(struct pipe_screen *screen);
typedef struct pipe_screen * (*pipe_screen_create_function)
(int fd, const struct pipe_screen_config *config, struct renderonly *ro);
struct pipe_screen *
u_pipe_screen_lookup_or_create(int fd,
const struct pipe_screen_config *config,
struct renderonly *ro,
pipe_screen_create_function screen_create);
#ifdef __cplusplus
};
#endif

View file

@ -1076,6 +1076,13 @@ etna_get_disk_shader_cache(struct pipe_screen *pscreen)
return compiler->disk_cache;
}
static int
etna_screen_get_fd(struct pipe_screen *pscreen)
{
struct etna_screen *screen = etna_screen(pscreen);
return etna_device_fd(screen->dev);
}
struct pipe_screen *
etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu,
struct renderonly *ro)
@ -1091,7 +1098,6 @@ etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu,
screen->dev = dev;
screen->gpu = gpu;
screen->ro = ro;
screen->refcnt = 1;
screen->drm_version = etnaviv_device_version(screen->dev);
etna_mesa_debug = debug_get_option_etna_mesa_debug();
@ -1218,6 +1224,7 @@ etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu,
screen->features[viv_chipMinorFeatures2] &= ~chipMinorFeatures2_LINEAR_PE;
pscreen->destroy = etna_screen_destroy;
pscreen->get_screen_fd = etna_screen_get_fd;
pscreen->get_param = etna_screen_get_param;
pscreen->get_paramf = etna_screen_get_paramf;
pscreen->get_shader_param = etna_screen_get_shader_param;

View file

@ -72,9 +72,6 @@ enum viv_features_word {
struct etna_screen {
struct pipe_screen base;
int refcnt;
void *winsys_priv;
struct etna_device *dev;
struct etna_gpu *gpu;
struct etna_pipe *pipe;

View file

@ -86,6 +86,16 @@ typedef void (*pipe_driver_thread_func)(void *job, void *gdata, int thread_index
* context.
*/
struct pipe_screen {
int refcnt;
void *winsys_priv;
/**
* Get the fd associated with the screen
* The fd returned is considered read-only, and in particular will not
* be close()d. It must remain valid for as long as the screen exists.
*/
int (*get_screen_fd)(struct pipe_screen *);
/**
* Atomically incremented by drivers to track the number of contexts.
* If it's 0, it can be assumed that contexts are not tracked.

View file

@ -26,10 +26,7 @@
#include <sys/stat.h>
#include "util/os_file.h"
#include "util/simple_mtx.h"
#include "util/u_hash_table.h"
#include "util/u_pointer.h"
#include "util/u_screen.h"
#include "etnaviv/etnaviv_screen.h"
#include "etnaviv/hw/common.xml.h"
@ -37,66 +34,9 @@
#include <stdio.h>
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 pipe_screen *
screen_create(int gpu_fd, struct renderonly *ro)
screen_create(int gpu_fd, const struct pipe_screen_config *config, struct renderonly *ro)
{
struct etna_device *dev;
struct etna_gpu *gpu;
@ -127,77 +67,14 @@ screen_create(int gpu_fd, struct renderonly *ro)
return etna_screen_create(dev, gpu, ro);
}
static struct hash_table *fd_tab = NULL;
static simple_mtx_t etna_screen_mutex = SIMPLE_MTX_INITIALIZER;
static void
etna_drm_screen_destroy(struct pipe_screen *pscreen)
{
struct etna_screen *screen = etna_screen(pscreen);
boolean destroy;
simple_mtx_lock(&etna_screen_mutex);
destroy = --screen->refcnt == 0;
if (destroy) {
int fd = etna_device_fd(screen->dev);
_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(&etna_screen_mutex);
if (destroy) {
pscreen->destroy = screen->winsys_priv;
pscreen->destroy(pscreen);
}
}
static struct pipe_screen *
etna_lookup_or_create_screen(int gpu_fd, struct renderonly *ro)
{
struct pipe_screen *pscreen = NULL;
simple_mtx_lock(&etna_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) {
etna_screen(pscreen)->refcnt++;
} else {
pscreen = screen_create(gpu_fd, ro);
if (pscreen) {
int fd = etna_device_fd(etna_screen(pscreen)->dev);
_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() */
etna_screen(pscreen)->winsys_priv = pscreen->destroy;
pscreen->destroy = etna_drm_screen_destroy;
}
}
unlock:
simple_mtx_unlock(&etna_screen_mutex);
return pscreen;
}
struct pipe_screen *
etna_drm_screen_create_renderonly(struct renderonly *ro)
{
return etna_lookup_or_create_screen(ro->gpu_fd, ro);
return u_pipe_screen_lookup_or_create(ro->gpu_fd, NULL, ro, screen_create);
}
struct pipe_screen *
etna_drm_screen_create(int fd)
{
return etna_lookup_or_create_screen(fd, NULL);
return u_pipe_screen_lookup_or_create(fd, NULL, NULL, screen_create);
}