Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/egl/main/egldevice.c
4560 views
1
/**************************************************************************
2
*
3
* Copyright 2015, 2018 Collabora
4
* All Rights Reserved.
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the
8
* "Software"), to deal in the Software without restriction, including
9
* without limitation the rights to use, copy, modify, merge, publish,
10
* distribute, sub license, and/or sell copies of the Software, and to
11
* permit persons to whom the Software is furnished to do so, subject to
12
* the following conditions:
13
*
14
* The above copyright notice and this permission notice (including the
15
* next paragraph) shall be included in all copies or substantial portions
16
* of the Software.
17
*
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
* DEALINGS IN THE SOFTWARE.
25
*
26
**************************************************************************/
27
28
#ifdef HAVE_LIBDRM
29
#include <xf86drm.h>
30
#endif
31
#include "util/compiler.h"
32
#include "util/macros.h"
33
34
#include "eglcurrent.h"
35
#include "egldevice.h"
36
#include "egllog.h"
37
#include "eglglobals.h"
38
#include "egltypedefs.h"
39
40
41
struct _egl_device {
42
_EGLDevice *Next;
43
44
const char *extensions;
45
46
EGLBoolean MESA_device_software;
47
EGLBoolean EXT_device_drm;
48
49
#ifdef HAVE_LIBDRM
50
drmDevicePtr device;
51
#endif
52
};
53
54
void
55
_eglFiniDevice(void)
56
{
57
_EGLDevice *dev_list, *dev;
58
59
/* atexit function is called with global mutex locked */
60
61
dev_list = _eglGlobal.DeviceList;
62
63
/* The first device is static allocated SW device */
64
assert(dev_list);
65
assert(_eglDeviceSupports(dev_list, _EGL_DEVICE_SOFTWARE));
66
dev_list = dev_list->Next;
67
68
while (dev_list) {
69
/* pop list head */
70
dev = dev_list;
71
dev_list = dev_list->Next;
72
73
#ifdef HAVE_LIBDRM
74
assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM));
75
drmFreeDevice(&dev->device);
76
#endif
77
free(dev);
78
}
79
80
_eglGlobal.DeviceList = NULL;
81
}
82
83
EGLBoolean
84
_eglCheckDeviceHandle(EGLDeviceEXT device)
85
{
86
_EGLDevice *cur;
87
88
mtx_lock(_eglGlobal.Mutex);
89
cur = _eglGlobal.DeviceList;
90
while (cur) {
91
if (cur == (_EGLDevice *) device)
92
break;
93
cur = cur->Next;
94
}
95
mtx_unlock(_eglGlobal.Mutex);
96
return (cur != NULL);
97
}
98
99
_EGLDevice _eglSoftwareDevice = {
100
.extensions = "EGL_MESA_device_software",
101
.MESA_device_software = EGL_TRUE,
102
};
103
104
#ifdef HAVE_LIBDRM
105
/*
106
* Negative value on error, zero if newly added, one if already in list.
107
*/
108
static int
109
_eglAddDRMDevice(drmDevicePtr device, _EGLDevice **out_dev)
110
{
111
_EGLDevice *dev;
112
113
if ((device->available_nodes & (1 << DRM_NODE_PRIMARY |
114
1 << DRM_NODE_RENDER)) == 0)
115
return -1;
116
117
dev = _eglGlobal.DeviceList;
118
119
/* The first device is always software */
120
assert(dev);
121
assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
122
123
while (dev->Next) {
124
dev = dev->Next;
125
126
assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM));
127
if (drmDevicesEqual(device, dev->device) != 0) {
128
if (out_dev)
129
*out_dev = dev;
130
return 1;
131
}
132
}
133
134
dev->Next = calloc(1, sizeof(_EGLDevice));
135
if (!dev->Next) {
136
if (out_dev)
137
*out_dev = NULL;
138
return -1;
139
}
140
141
dev = dev->Next;
142
dev->extensions = "EGL_EXT_device_drm";
143
dev->EXT_device_drm = EGL_TRUE;
144
dev->device = device;
145
146
if (out_dev)
147
*out_dev = dev;
148
149
return 0;
150
}
151
#endif
152
153
/* Adds a device in DeviceList, if needed for the given fd.
154
*
155
* If a software device, the fd is ignored.
156
*/
157
_EGLDevice *
158
_eglAddDevice(int fd, bool software)
159
{
160
_EGLDevice *dev;
161
162
mtx_lock(_eglGlobal.Mutex);
163
dev = _eglGlobal.DeviceList;
164
165
/* The first device is always software */
166
assert(dev);
167
assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
168
if (software)
169
goto out;
170
171
#ifdef HAVE_LIBDRM
172
drmDevicePtr device;
173
174
if (drmGetDevice2(fd, 0, &device) != 0) {
175
dev = NULL;
176
goto out;
177
}
178
179
/* Device is not added - error or already present */
180
if (_eglAddDRMDevice(device, &dev) != 0)
181
drmFreeDevice(&device);
182
#else
183
_eglLog(_EGL_FATAL, "Driver bug: Built without libdrm, yet looking for HW device");
184
dev = NULL;
185
#endif
186
187
out:
188
mtx_unlock(_eglGlobal.Mutex);
189
return dev;
190
}
191
192
EGLBoolean
193
_eglDeviceSupports(_EGLDevice *dev, _EGLDeviceExtension ext)
194
{
195
switch (ext) {
196
case _EGL_DEVICE_SOFTWARE:
197
return dev->MESA_device_software;
198
case _EGL_DEVICE_DRM:
199
return dev->EXT_device_drm;
200
default:
201
assert(0);
202
return EGL_FALSE;
203
};
204
}
205
206
/* Ideally we'll have an extension which passes the render node,
207
* instead of the card one + magic.
208
*
209
* Then we can move this in _eglQueryDeviceStringEXT below. Until then
210
* keep it separate.
211
*/
212
const char *
213
_eglGetDRMDeviceRenderNode(_EGLDevice *dev)
214
{
215
#ifdef HAVE_LIBDRM
216
return dev->device->nodes[DRM_NODE_RENDER];
217
#else
218
return NULL;
219
#endif
220
}
221
222
EGLBoolean
223
_eglQueryDeviceAttribEXT(_EGLDevice *dev, EGLint attribute,
224
EGLAttrib *value)
225
{
226
switch (attribute) {
227
default:
228
_eglError(EGL_BAD_ATTRIBUTE, "eglQueryDeviceAttribEXT");
229
return EGL_FALSE;
230
}
231
}
232
233
const char *
234
_eglQueryDeviceStringEXT(_EGLDevice *dev, EGLint name)
235
{
236
switch (name) {
237
case EGL_EXTENSIONS:
238
return dev->extensions;
239
#ifdef HAVE_LIBDRM
240
case EGL_DRM_DEVICE_FILE_EXT:
241
if (_eglDeviceSupports(dev, _EGL_DEVICE_DRM))
242
return dev->device->nodes[DRM_NODE_PRIMARY];
243
#endif
244
FALLTHROUGH;
245
default:
246
_eglError(EGL_BAD_PARAMETER, "eglQueryDeviceStringEXT");
247
return NULL;
248
};
249
}
250
251
/* Do a fresh lookup for devices.
252
*
253
* Walks through the DeviceList, discarding no longer available ones
254
* and adding new ones as applicable.
255
*
256
* Must be called with the global lock held.
257
*/
258
static int
259
_eglRefreshDeviceList(void)
260
{
261
ASSERTED _EGLDevice *dev;
262
int count = 0;
263
264
dev = _eglGlobal.DeviceList;
265
266
/* The first device is always software */
267
assert(dev);
268
assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
269
count++;
270
271
#ifdef HAVE_LIBDRM
272
drmDevicePtr devices[64];
273
int num_devs, ret;
274
275
num_devs = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
276
for (int i = 0; i < num_devs; i++) {
277
if (!(devices[i]->available_nodes & (1 << DRM_NODE_RENDER)))
278
continue;
279
280
ret = _eglAddDRMDevice(devices[i], NULL);
281
282
/* Device is not added - error or already present */
283
if (ret != 0)
284
drmFreeDevice(&devices[i]);
285
286
if (ret >= 0)
287
count++;
288
}
289
#endif
290
291
return count;
292
}
293
294
EGLBoolean
295
_eglQueryDevicesEXT(EGLint max_devices,
296
_EGLDevice **devices,
297
EGLint *num_devices)
298
{
299
_EGLDevice *dev, *devs;
300
int i = 0, num_devs;
301
302
if ((devices && max_devices <= 0) || !num_devices)
303
return _eglError(EGL_BAD_PARAMETER, "eglQueryDevicesEXT");
304
305
mtx_lock(_eglGlobal.Mutex);
306
307
num_devs = _eglRefreshDeviceList();
308
devs = _eglGlobal.DeviceList;
309
310
/* bail early if we only care about the count */
311
if (!devices) {
312
*num_devices = num_devs;
313
goto out;
314
}
315
316
/* Push the first device (the software one) to the end of the list.
317
* Sending it to the user only if they've requested the full list.
318
*
319
* By default, the user is likely to pick the first device so having the
320
* software (aka least performant) one is not a good idea.
321
*/
322
*num_devices = MIN2(num_devs, max_devices);
323
324
for (i = 0, dev = devs->Next; dev && i < max_devices; i++) {
325
devices[i] = dev;
326
dev = dev->Next;
327
}
328
329
/* User requested the full device list, add the sofware device. */
330
if (max_devices >= num_devs) {
331
assert(_eglDeviceSupports(devs, _EGL_DEVICE_SOFTWARE));
332
devices[num_devs - 1] = devs;
333
}
334
335
out:
336
mtx_unlock(_eglGlobal.Mutex);
337
338
return EGL_TRUE;
339
}
340
341