Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
4573 views
1
#include <sys/stat.h>
2
#include <unistd.h>
3
#include <fcntl.h>
4
#include "pipe/p_context.h"
5
#include "pipe/p_state.h"
6
#include "util/format/u_format.h"
7
#include "util/os_file.h"
8
#include "util/u_memory.h"
9
#include "util/u_inlines.h"
10
#include "util/u_hash_table.h"
11
#include "util/u_pointer.h"
12
#include "os/os_thread.h"
13
14
#include "nouveau_drm_public.h"
15
16
#include "nouveau/nouveau_winsys.h"
17
#include "nouveau/nouveau_screen.h"
18
19
#include <nvif/class.h>
20
#include <nvif/cl0080.h>
21
22
static struct hash_table *fd_tab = NULL;
23
24
static mtx_t nouveau_screen_mutex = _MTX_INITIALIZER_NP;
25
26
bool nouveau_drm_screen_unref(struct nouveau_screen *screen)
27
{
28
int ret;
29
if (screen->refcount == -1)
30
return true;
31
32
mtx_lock(&nouveau_screen_mutex);
33
ret = --screen->refcount;
34
assert(ret >= 0);
35
if (ret == 0)
36
_mesa_hash_table_remove_key(fd_tab, intptr_to_pointer(screen->drm->fd));
37
mtx_unlock(&nouveau_screen_mutex);
38
return ret == 0;
39
}
40
41
PUBLIC struct pipe_screen *
42
nouveau_drm_screen_create(int fd)
43
{
44
struct nouveau_drm *drm = NULL;
45
struct nouveau_device *dev = NULL;
46
struct nouveau_screen *(*init)(struct nouveau_device *);
47
struct nouveau_screen *screen = NULL;
48
int ret, dupfd;
49
50
mtx_lock(&nouveau_screen_mutex);
51
if (!fd_tab) {
52
fd_tab = util_hash_table_create_fd_keys();
53
if (!fd_tab) {
54
mtx_unlock(&nouveau_screen_mutex);
55
return NULL;
56
}
57
}
58
59
screen = util_hash_table_get(fd_tab, intptr_to_pointer(fd));
60
if (screen) {
61
screen->refcount++;
62
mtx_unlock(&nouveau_screen_mutex);
63
return &screen->base;
64
}
65
66
/* Since the screen re-use is based on the device node and not the fd,
67
* create a copy of the fd to be owned by the device. Otherwise a
68
* scenario could occur where two screens are created, and the first
69
* one is shut down, along with the fd being closed. The second
70
* (identical) screen would now have a reference to the closed fd. We
71
* avoid this by duplicating the original fd. Note that
72
* nouveau_device_wrap does not close the fd in case of a device
73
* creation error.
74
*/
75
dupfd = os_dupfd_cloexec(fd);
76
77
ret = nouveau_drm_new(dupfd, &drm);
78
if (ret)
79
goto err;
80
81
ret = nouveau_device_new(&drm->client, NV_DEVICE,
82
&(struct nv_device_v0) {
83
.device = ~0ULL,
84
}, sizeof(struct nv_device_v0), &dev);
85
if (ret)
86
goto err;
87
88
switch (dev->chipset & ~0xf) {
89
case 0x30:
90
case 0x40:
91
case 0x60:
92
init = nv30_screen_create;
93
break;
94
case 0x50:
95
case 0x80:
96
case 0x90:
97
case 0xa0:
98
init = nv50_screen_create;
99
break;
100
case 0xc0:
101
case 0xd0:
102
case 0xe0:
103
case 0xf0:
104
case 0x100:
105
case 0x110:
106
case 0x120:
107
case 0x130:
108
case 0x140:
109
case 0x160:
110
init = nvc0_screen_create;
111
break;
112
default:
113
debug_printf("%s: unknown chipset nv%02x\n", __func__,
114
dev->chipset);
115
goto err;
116
}
117
118
screen = init(dev);
119
if (!screen || !screen->base.context_create)
120
goto err;
121
122
/* Use dupfd in hash table, to avoid errors if the original fd gets
123
* closed by its owner. The hash key needs to live at least as long as
124
* the screen.
125
*/
126
_mesa_hash_table_insert(fd_tab, intptr_to_pointer(dupfd), screen);
127
screen->refcount = 1;
128
mtx_unlock(&nouveau_screen_mutex);
129
return &screen->base;
130
131
err:
132
if (screen) {
133
screen->base.destroy(&screen->base);
134
} else {
135
nouveau_device_del(&dev);
136
nouveau_drm_del(&drm);
137
close(dupfd);
138
}
139
mtx_unlock(&nouveau_screen_mutex);
140
return NULL;
141
}
142
143