Some gallium drivers have implemented reference counting of pipe_screen to avoid creating multiple screens for a device. Move this into the pipe-loader where it can be shared.
Not completely sure, but it should not necessary to dup() the fd as dri2_create_screen does that for us already. Signed-off-by: Rob Herring <r...@kernel.org> Cc: Emil Velikov <emil.l.veli...@gmail.com> --- .../auxiliary/pipe-loader/pipe_loader_drm.c | 66 +++++++++++++++++++++- src/gallium/include/pipe/p_screen.h | 1 + 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c b/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c index 62f109f..71169ed 100644 --- a/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c +++ b/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c @@ -34,6 +34,7 @@ #include <stdio.h> #include <xf86drm.h> #include <unistd.h> +#include <sys/stat.h> #include "loader.h" #include "target-helpers/drm_helper_public.h" @@ -41,9 +42,12 @@ #include "pipe_loader_priv.h" #include "pipe/p_screen.h" +#include "os/os_thread.h" #include "util/u_memory.h" #include "util/u_dl.h" #include "util/u_debug.h" +#include "util/u_pointer.h" +#include "util/u_hash_table.h" #define DRM_RENDER_NODE_DEV_NAME_FORMAT "%s/renderD%d" #define DRM_RENDER_NODE_MAX_NODES 63 @@ -266,14 +270,50 @@ pipe_loader_drm_probe(struct pipe_loader_device **devs, int ndev) return j; } +static struct util_hash_table *fd_tab = NULL; +pipe_static_mutex(loader_mutex); +static int refcnt; + +static unsigned hash_fd(void *key) +{ + int fd = pointer_to_intptr(key); + struct stat stat; + fstat(fd, &stat); + + return stat.st_dev ^ stat.st_ino ^ stat.st_rdev; +} + +static int compare_fd(void *key1, void *key2) +{ + int fd1 = pointer_to_intptr(key1); + int fd2 = pointer_to_intptr(key2); + struct stat stat1, stat2; + 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 void pipe_loader_drm_release(struct pipe_loader_device **dev) { struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(*dev); struct pipe_screen *pscreen = ddev->base.pscreen; + int fd = ddev->fd; - pscreen->destroy(pscreen); + pipe_mutex_lock(loader_mutex); + if (pscreen) { + if (--pscreen->refcnt != 0) { + pipe_mutex_unlock(loader_mutex); + return; + } + pscreen->destroy(pscreen); + + util_hash_table_remove(fd_tab, intptr_to_pointer(fd)); + } #ifndef GALLIUM_STATIC_TARGETS if (ddev->lib) util_dl_close(ddev->lib); @@ -283,6 +323,8 @@ pipe_loader_drm_release(struct pipe_loader_device **dev) FREE(ddev->base.driver_name); FREE(ddev); *dev = NULL; + + pipe_mutex_unlock(loader_mutex); } static const struct drm_conf_ret * @@ -301,10 +343,30 @@ static struct pipe_screen * pipe_loader_drm_create_screen(struct pipe_loader_device *dev) { struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(dev); + int fd = ddev->fd; struct pipe_screen *pscreen = NULL; - pscreen = ddev->dd->create_screen(fd); + pipe_mutex_lock(loader_mutex); + if (!fd_tab) { + fd_tab = util_hash_table_create(hash_fd, compare_fd); + if (!fd_tab) + goto unlock; + } + + pscreen = util_hash_table_get(fd_tab, intptr_to_pointer(fd)); + if (pscreen) { + pscreen->refcnt++; + goto unlock; + } else { + pscreen = ddev->dd->create_screen(fd); + if (pscreen) + util_hash_table_set(fd_tab, intptr_to_pointer(fd), pscreen); + pscreen->refcnt = 1; + } + +unlock: ddev->base.pscreen = pscreen; + pipe_mutex_unlock(loader_mutex); return pscreen; } diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h index 755291a..28a3f71 100644 --- a/src/gallium/include/pipe/p_screen.h +++ b/src/gallium/include/pipe/p_screen.h @@ -66,6 +66,7 @@ struct pipe_memory_info; * context. */ struct pipe_screen { + int refcnt; void (*destroy)( struct pipe_screen * ); const char *(*get_name)( struct pipe_screen * ); -- 2.7.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev