diff options
Diffstat (limited to 'src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c')
-rw-r--r-- | src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c | 78 |
1 files changed, 74 insertions, 4 deletions
diff --git a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c index e4f27f6cb24..a077c48c206 100644 --- a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c +++ b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c @@ -1,24 +1,83 @@ +#include <sys/stat.h> #include "pipe/p_context.h" #include "pipe/p_state.h" #include "util/u_format.h" #include "util/u_memory.h" #include "util/u_inlines.h" +#include "util/u_hash_table.h" +#include "os/os_thread.h" #include "nouveau_drm_public.h" #include "nouveau/nouveau_winsys.h" #include "nouveau/nouveau_screen.h" -struct pipe_screen * +static struct util_hash_table *fd_tab = NULL; + +pipe_static_mutex(nouveau_screen_mutex); + +boolean nouveau_drm_screen_unref(struct nouveau_screen *screen) +{ + int ret; + if (screen->refcount == -1) + return true; + + pipe_mutex_lock(nouveau_screen_mutex); + ret = --screen->refcount; + assert(ret >= 0); + if (ret == 0) + util_hash_table_remove(fd_tab, intptr_to_pointer(screen->device->fd)); + pipe_mutex_unlock(nouveau_screen_mutex); + return ret == 0; +} + +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; +} + +PUBLIC struct pipe_screen * nouveau_drm_screen_create(int fd) { struct nouveau_device *dev = NULL; struct pipe_screen *(*init)(struct nouveau_device *); + struct nouveau_screen *screen; int ret; + pipe_mutex_lock(nouveau_screen_mutex); + if (!fd_tab) { + fd_tab = util_hash_table_create(hash_fd, compare_fd); + if (!fd_tab) + goto err; + } + + screen = util_hash_table_get(fd_tab, intptr_to_pointer(fd)); + if (screen) { + screen->refcount++; + pipe_mutex_unlock(nouveau_screen_mutex); + return &screen->base; + } + ret = nouveau_device_wrap(fd, 0, &dev); if (ret) - return NULL; + goto err; switch (dev->chipset & ~0xf) { case 0x30: @@ -42,8 +101,19 @@ nouveau_drm_screen_create(int fd) default: debug_printf("%s: unknown chipset nv%02x\n", __func__, dev->chipset); - return NULL; + goto err; } - return init(dev); + screen = (struct nouveau_screen*)init(dev); + if (!screen) + goto err; + + util_hash_table_set(fd_tab, intptr_to_pointer(fd), screen); + screen->refcount = 1; + pipe_mutex_unlock(nouveau_screen_mutex); + return &screen->base; + +err: + pipe_mutex_unlock(nouveau_screen_mutex); + return NULL; } |