diff --git a/src/gallium/drivers/nouveau/nouveau_screen.c b/src/gallium/drivers/nouveau/nouveau_screen.c index 21b31e0..088ce9b 100644 --- a/src/gallium/drivers/nouveau/nouveau_screen.c +++ b/src/gallium/drivers/nouveau/nouveau_screen.c @@ -144,6 +144,7 @@ nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev) if (nv_dbg) nouveau_mesa_debug = atoi(nv_dbg); + pipe_reference_init(&screen->reference, 1); if (dev->chipset < 0xc0) { data = &nv04_data; size = sizeof(nv04_data); diff --git a/src/gallium/drivers/nouveau/nouveau_screen.h b/src/gallium/drivers/nouveau/nouveau_screen.h index 51e24fa..d731d41 100644 --- a/src/gallium/drivers/nouveau/nouveau_screen.h +++ b/src/gallium/drivers/nouveau/nouveau_screen.h @@ -3,6 +3,7 @@ #include "pipe/p_screen.h" #include "util/u_memory.h" +#include "util/u_inlines.h" #ifdef DEBUG # define NOUVEAU_ENABLE_DRIVER_STATISTICS @@ -17,6 +18,7 @@ struct nouveau_bo; struct nouveau_screen { struct pipe_screen base; + struct pipe_reference reference; struct nouveau_device *device; struct nouveau_object *channel; struct nouveau_client *client; @@ -112,6 +114,8 @@ nouveau_screen(struct pipe_screen *pscreen) return (struct nouveau_screen *)pscreen; } +boolean nouveau_drm_screen_unref(struct nouveau_screen *screen); + boolean nouveau_screen_bo_get_handle(struct pipe_screen *pscreen, struct nouveau_bo *bo, diff --git a/src/gallium/drivers/nouveau/nv30/nv30_screen.c b/src/gallium/drivers/nouveau/nv30/nv30_screen.c index 8eee06b..c22acfd 100644 --- a/src/gallium/drivers/nouveau/nv30/nv30_screen.c +++ b/src/gallium/drivers/nouveau/nv30/nv30_screen.c @@ -300,6 +300,9 @@ nv30_screen_destroy(struct pipe_screen *pscreen) { struct nv30_screen *screen = nv30_screen(pscreen); + if (!nouveau_drm_screen_unref(&screen->base)) + return; + if (screen->base.fence.current && screen->base.fence.current->state >= NOUVEAU_FENCE_STATE_EMITTED) { nouveau_fence_wait(screen->base.fence.current); diff --git a/src/gallium/drivers/nouveau/nv50/nv50_screen.c b/src/gallium/drivers/nouveau/nv50/nv50_screen.c index e636bf8..db3265f 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_screen.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_screen.c @@ -287,6 +287,9 @@ nv50_screen_destroy(struct pipe_screen *pscreen) { struct nv50_screen *screen = nv50_screen(pscreen); + if (!nouveau_drm_screen_unref(&screen->base)) + return; + if (screen->base.fence.current) { nouveau_fence_wait(screen->base.fence.current); nouveau_fence_ref (NULL, &screen->base.fence.current); diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c index f84c41b..0af3429 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c @@ -331,6 +331,9 @@ nvc0_screen_destroy(struct pipe_screen *pscreen) { struct nvc0_screen *screen = nvc0_screen(pscreen); + if (!nouveau_drm_screen_unref(&screen->base)) + return; + if (screen->base.fence.current) { nouveau_fence_wait(screen->base.fence.current); nouveau_fence_ref(NULL, &screen->base.fence.current); diff --git a/src/gallium/targets/dri-nouveau/Makefile.am b/src/gallium/targets/dri-nouveau/Makefile.am index 1988067..6fdd35c 100644 --- a/src/gallium/targets/dri-nouveau/Makefile.am +++ b/src/gallium/targets/dri-nouveau/Makefile.am @@ -34,7 +34,7 @@ dri_LTLIBRARIES = nouveau_dri.la nodist_EXTRA_nouveau_dri_la_SOURCES = dummy.cpp nouveau_dri_la_SOURCES = target.c -nouveau_dri_la_LDFLAGS = $(GALLIUM_DRI_LINKER_FLAGS) +nouveau_dri_la_LDFLAGS = $(GALLIUM_DRI_LINKER_FLAGS) -Wl,--dynamic-list=$(srcdir)/nouveau_dri.dyn nouveau_dri_la_LIBADD = \ $(top_builddir)/src/mesa/drivers/dri/common/libdricommon.la \ diff --git a/src/gallium/targets/dri-nouveau/nouveau_dri.dyn b/src/gallium/targets/dri-nouveau/nouveau_dri.dyn new file mode 100644 index 0000000..630a321 --- /dev/null +++ b/src/gallium/targets/dri-nouveau/nouveau_dri.dyn @@ -0,0 +1,4 @@ +{ + nouveau_drm_screen_create; +}; + diff --git a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c index e4f27f6..5a3b100 100644 --- a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c +++ b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c @@ -1,21 +1,66 @@ +#include #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 "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; + +boolean nouveau_drm_screen_unref(struct nouveau_screen *screen) +{ + bool ret = pipe_reference(&screen->reference, NULL); + if (ret && fd_tab) + util_hash_table_remove(fd_tab, intptr_to_pointer(screen->device->fd)); + return ret; +} + +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; + if (!fd_tab) { + fd_tab = util_hash_table_create(hash_fd, compare_fd); + } + + screen = util_hash_table_get(fd_tab, intptr_to_pointer(fd)); + if (screen) { + pipe_reference(NULL, &screen->reference); + return &screen->base; + } + ret = nouveau_device_wrap(fd, 0, &dev); if (ret) return NULL; @@ -45,5 +90,8 @@ nouveau_drm_screen_create(int fd) return NULL; } - return init(dev); + screen = (struct nouveau_screen*)init(dev); + if (screen) + util_hash_table_set(fd_tab, intptr_to_pointer(fd), screen); + return &screen->base; }