nouveau: create only 1 shared screen between vdpau and opengl
[mesa.git] / src / gallium / winsys / nouveau / drm / nouveau_drm_winsys.c
1 #include <sys/stat.h>
2 #include "pipe/p_context.h"
3 #include "pipe/p_state.h"
4 #include "util/u_format.h"
5 #include "util/u_memory.h"
6 #include "util/u_inlines.h"
7 #include "util/u_hash_table.h"
8 #include "os/os_thread.h"
9
10 #include "nouveau_drm_public.h"
11
12 #include "nouveau/nouveau_winsys.h"
13 #include "nouveau/nouveau_screen.h"
14
15 static struct util_hash_table *fd_tab = NULL;
16
17 pipe_static_mutex(nouveau_screen_mutex);
18
19 boolean nouveau_drm_screen_unref(struct nouveau_screen *screen)
20 {
21 int ret;
22 if (screen->refcount == -1)
23 return true;
24
25 pipe_mutex_lock(nouveau_screen_mutex);
26 ret = --screen->refcount;
27 assert(ret >= 0);
28 if (ret == 0)
29 util_hash_table_remove(fd_tab, intptr_to_pointer(screen->device->fd));
30 pipe_mutex_unlock(nouveau_screen_mutex);
31 return ret == 0;
32 }
33
34 static unsigned hash_fd(void *key)
35 {
36 int fd = pointer_to_intptr(key);
37 struct stat stat;
38 fstat(fd, &stat);
39
40 return stat.st_dev ^ stat.st_ino ^ stat.st_rdev;
41 }
42
43 static int compare_fd(void *key1, void *key2)
44 {
45 int fd1 = pointer_to_intptr(key1);
46 int fd2 = pointer_to_intptr(key2);
47 struct stat stat1, stat2;
48 fstat(fd1, &stat1);
49 fstat(fd2, &stat2);
50
51 return stat1.st_dev != stat2.st_dev ||
52 stat1.st_ino != stat2.st_ino ||
53 stat1.st_rdev != stat2.st_rdev;
54 }
55
56 PUBLIC struct pipe_screen *
57 nouveau_drm_screen_create(int fd)
58 {
59 struct nouveau_device *dev = NULL;
60 struct pipe_screen *(*init)(struct nouveau_device *);
61 struct nouveau_screen *screen;
62 int ret;
63
64 pipe_mutex_lock(nouveau_screen_mutex);
65 if (!fd_tab) {
66 fd_tab = util_hash_table_create(hash_fd, compare_fd);
67 if (!fd_tab)
68 goto err;
69 }
70
71 screen = util_hash_table_get(fd_tab, intptr_to_pointer(fd));
72 if (screen) {
73 screen->refcount++;
74 pipe_mutex_unlock(nouveau_screen_mutex);
75 return &screen->base;
76 }
77
78 ret = nouveau_device_wrap(fd, 0, &dev);
79 if (ret)
80 goto err;
81
82 switch (dev->chipset & ~0xf) {
83 case 0x30:
84 case 0x40:
85 case 0x60:
86 init = nv30_screen_create;
87 break;
88 case 0x50:
89 case 0x80:
90 case 0x90:
91 case 0xa0:
92 init = nv50_screen_create;
93 break;
94 case 0xc0:
95 case 0xd0:
96 case 0xe0:
97 case 0xf0:
98 case 0x100:
99 init = nvc0_screen_create;
100 break;
101 default:
102 debug_printf("%s: unknown chipset nv%02x\n", __func__,
103 dev->chipset);
104 goto err;
105 }
106
107 screen = (struct nouveau_screen*)init(dev);
108 if (!screen)
109 goto err;
110
111 util_hash_table_set(fd_tab, intptr_to_pointer(fd), screen);
112 screen->refcount = 1;
113 pipe_mutex_unlock(nouveau_screen_mutex);
114 return &screen->base;
115
116 err:
117 pipe_mutex_unlock(nouveau_screen_mutex);
118 return NULL;
119 }