From fee0686c21c631d96d6042741267a3c218c23ffc Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 12 Feb 2014 14:56:53 +0100 Subject: nouveau: create only 1 shared screen between vdpau and opengl This fixes bug 73200 "vdpau-GL interop fails due to different screen objects" in the same way radeon does. Signed-off-by: Maarten Lankhorst Reviewed-by: Emil Velikov --- src/gallium/drivers/nouveau/nouveau_screen.c | 6 ++ src/gallium/drivers/nouveau/nouveau_screen.h | 4 ++ src/gallium/drivers/nouveau/nv30/nv30_screen.c | 3 + src/gallium/drivers/nouveau/nv50/nv50_screen.c | 3 + src/gallium/drivers/nouveau/nvc0/nvc0_screen.c | 3 + src/gallium/targets/dri-nouveau/Makefile.am | 1 + src/gallium/targets/dri-nouveau/nouveau_dri.link | 6 ++ .../winsys/nouveau/drm/nouveau_drm_winsys.c | 78 ++++++++++++++++++++-- 8 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 src/gallium/targets/dri-nouveau/nouveau_dri.link (limited to 'src') diff --git a/src/gallium/drivers/nouveau/nouveau_screen.c b/src/gallium/drivers/nouveau/nouveau_screen.c index 21b31e04f0a..f742a9483b1 100644 --- a/src/gallium/drivers/nouveau/nouveau_screen.c +++ b/src/gallium/drivers/nouveau/nouveau_screen.c @@ -144,6 +144,12 @@ nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev) if (nv_dbg) nouveau_mesa_debug = atoi(nv_dbg); + /* + * this is initialized to 1 in nouveau_drm_screen_create after screen + * is fully constructed and added to the global screen list. + */ + screen->refcount = -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 51e24fa05a4..cf06f7e88aa 100644 --- a/src/gallium/drivers/nouveau/nouveau_screen.h +++ b/src/gallium/drivers/nouveau/nouveau_screen.h @@ -22,6 +22,8 @@ struct nouveau_screen { struct nouveau_client *client; struct nouveau_pushbuf *pushbuf; + int refcount; + unsigned vidmem_bindings; /* PIPE_BIND_* where VRAM placement is desired */ unsigned sysmem_bindings; /* PIPE_BIND_* where GART placement is desired */ unsigned lowmem_bindings; /* PIPE_BIND_* that require an address < 4 GiB */ @@ -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 c027a5f3130..9854708b371 100644 --- a/src/gallium/drivers/nouveau/nv30/nv30_screen.c +++ b/src/gallium/drivers/nouveau/nv30/nv30_screen.c @@ -302,6 +302,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 e636bf8be33..db3265fb29e 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 28d9be24bbe..f04771de452 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c @@ -333,6 +333,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 19880679bae..4bd4e21953c 100644 --- a/src/gallium/targets/dri-nouveau/Makefile.am +++ b/src/gallium/targets/dri-nouveau/Makefile.am @@ -20,6 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. +DRI_VERSION_SCRIPT = $(srcdir)/nouveau_dri.link include $(top_srcdir)/src/gallium/Automake.inc AM_CFLAGS = \ diff --git a/src/gallium/targets/dri-nouveau/nouveau_dri.link b/src/gallium/targets/dri-nouveau/nouveau_dri.link new file mode 100644 index 00000000000..16015aa3d81 --- /dev/null +++ b/src/gallium/targets/dri-nouveau/nouveau_dri.link @@ -0,0 +1,6 @@ +VERSION { + global: + __driDriverExtensions; + nouveau_drm_screen_create; + local: *; +}; 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 #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; } -- cgit v1.2.3