1 /**************************************************************************
3 * Copyright 2015, 2018 Collabora
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
31 #include "util/macros.h"
33 #include "eglcurrent.h"
34 #include "egldevice.h"
36 #include "eglglobals.h"
37 #include "egltypedefs.h"
43 const char *extensions
;
45 EGLBoolean MESA_device_software
;
46 EGLBoolean EXT_device_drm
;
56 _EGLDevice
*dev_list
, *dev
;
58 /* atexit function is called with global mutex locked */
60 dev_list
= _eglGlobal
.DeviceList
;
62 /* The first device is static allocated SW device */
64 assert(_eglDeviceSupports(dev_list
, _EGL_DEVICE_SOFTWARE
));
65 dev_list
= dev_list
->Next
;
70 dev_list
= dev_list
->Next
;
73 assert(_eglDeviceSupports(dev
, _EGL_DEVICE_DRM
));
74 drmFreeDevice(&dev
->device
);
79 _eglGlobal
.DeviceList
= NULL
;
83 _eglCheckDeviceHandle(EGLDeviceEXT device
)
87 mtx_lock(_eglGlobal
.Mutex
);
88 cur
= _eglGlobal
.DeviceList
;
90 if (cur
== (_EGLDevice
*) device
)
94 mtx_unlock(_eglGlobal
.Mutex
);
98 _EGLDevice _eglSoftwareDevice
= {
99 .extensions
= "EGL_MESA_device_software",
100 .MESA_device_software
= EGL_TRUE
,
105 * Negative value on error, zero if newly added, one if already in list.
108 _eglAddDRMDevice(drmDevicePtr device
, _EGLDevice
**out_dev
)
111 const int wanted_nodes
= 1 << DRM_NODE_RENDER
| 1 << DRM_NODE_PRIMARY
;
113 if ((device
->available_nodes
& wanted_nodes
) != wanted_nodes
)
116 dev
= _eglGlobal
.DeviceList
;
118 /* The first device is always software */
120 assert(_eglDeviceSupports(dev
, _EGL_DEVICE_SOFTWARE
));
125 assert(_eglDeviceSupports(dev
, _EGL_DEVICE_DRM
));
126 if (drmDevicesEqual(device
, dev
->device
) != 0) {
133 dev
->Next
= calloc(1, sizeof(_EGLDevice
));
141 dev
->extensions
= "EGL_EXT_device_drm";
142 dev
->EXT_device_drm
= EGL_TRUE
;
143 dev
->device
= device
;
152 /* Adds a device in DeviceList, if needed for the given fd.
154 * If a software device, the fd is ignored.
157 _eglAddDevice(int fd
, bool software
)
161 mtx_lock(_eglGlobal
.Mutex
);
162 dev
= _eglGlobal
.DeviceList
;
164 /* The first device is always software */
166 assert(_eglDeviceSupports(dev
, _EGL_DEVICE_SOFTWARE
));
173 if (drmGetDevice2(fd
, 0, &device
) != 0) {
178 /* Device is not added - error or already present */
179 if (_eglAddDRMDevice(device
, &dev
) != 0)
180 drmFreeDevice(&device
);
182 _eglLog(_EGL_FATAL
, "Driver bug: Built without libdrm, yet looking for HW device");
187 mtx_unlock(_eglGlobal
.Mutex
);
192 _eglDeviceSupports(_EGLDevice
*dev
, _EGLDeviceExtension ext
)
195 case _EGL_DEVICE_SOFTWARE
:
196 return dev
->MESA_device_software
;
197 case _EGL_DEVICE_DRM
:
198 return dev
->EXT_device_drm
;
205 /* Ideally we'll have an extension which passes the render node,
206 * instead of the card one + magic.
208 * Then we can move this in _eglQueryDeviceStringEXT below. Until then
212 _eglGetDRMDeviceRenderNode(_EGLDevice
*dev
)
215 return dev
->device
->nodes
[DRM_NODE_RENDER
];
222 _eglQueryDeviceAttribEXT(_EGLDevice
*dev
, EGLint attribute
,
227 _eglError(EGL_BAD_ATTRIBUTE
, "eglQueryDeviceStringEXT");
233 _eglQueryDeviceStringEXT(_EGLDevice
*dev
, EGLint name
)
237 return dev
->extensions
;
239 case EGL_DRM_DEVICE_FILE_EXT
:
240 if (_eglDeviceSupports(dev
, _EGL_DEVICE_DRM
))
241 return dev
->device
->nodes
[DRM_NODE_PRIMARY
];
245 _eglError(EGL_BAD_PARAMETER
, "eglQueryDeviceStringEXT");
250 /* Do a fresh lookup for devices.
252 * Walks through the DeviceList, discarding no longer available ones
253 * and adding new ones as applicable.
255 * Must be called with the global lock held.
258 _eglRefreshDeviceList(void)
260 ASSERTED _EGLDevice
*dev
;
263 dev
= _eglGlobal
.DeviceList
;
265 /* The first device is always software */
267 assert(_eglDeviceSupports(dev
, _EGL_DEVICE_SOFTWARE
));
271 drmDevicePtr devices
[64];
274 num_devs
= drmGetDevices2(0, devices
, ARRAY_SIZE(devices
));
275 for (int i
= 0; i
< num_devs
; i
++) {
276 ret
= _eglAddDRMDevice(devices
[i
], NULL
);
278 /* Device is not added - error or already present */
280 drmFreeDevice(&devices
[i
]);
291 _eglQueryDevicesEXT(EGLint max_devices
,
292 _EGLDevice
**devices
,
295 _EGLDevice
*dev
, *devs
;
298 if ((devices
&& max_devices
<= 0) || !num_devices
)
299 return _eglError(EGL_BAD_PARAMETER
, "eglQueryDevicesEXT");
301 mtx_lock(_eglGlobal
.Mutex
);
303 num_devs
= _eglRefreshDeviceList();
304 devs
= _eglGlobal
.DeviceList
;
306 /* bail early if we only care about the count */
308 *num_devices
= num_devs
;
312 /* Push the first device (the software one) to the end of the list.
313 * Sending it to the user only if they've requested the full list.
315 * By default, the user is likely to pick the first device so having the
316 * software (aka least performant) one is not a good idea.
318 *num_devices
= MIN2(num_devs
, max_devices
);
320 for (i
= 0, dev
= devs
->Next
; dev
&& i
< max_devices
; i
++) {
325 /* User requested the full device list, add the sofware device. */
326 if (max_devices
>= num_devs
) {
327 assert(_eglDeviceSupports(devs
, _EGL_DEVICE_SOFTWARE
));
328 devices
[num_devs
- 1] = devs
;
332 mtx_unlock(_eglGlobal
.Mutex
);