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/compiler.h"
32 #include "util/macros.h"
34 #include "eglcurrent.h"
35 #include "egldevice.h"
37 #include "eglglobals.h"
38 #include "egltypedefs.h"
44 const char *extensions;
46 EGLBoolean MESA_device_software;
47 EGLBoolean EXT_device_drm;
48 EGLBoolean EXT_device_drm_render_node;
58 _EGLDevice *dev_list, *dev;
60 /* atexit function is called with global mutex locked */
62 dev_list = _eglGlobal.DeviceList;
64 /* The first device is static allocated SW device */
66 assert(_eglDeviceSupports(dev_list, _EGL_DEVICE_SOFTWARE));
67 dev_list = dev_list->Next;
72 dev_list = dev_list->Next;
75 assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM));
76 drmFreeDevice(&dev->device);
81 _eglGlobal.DeviceList = NULL;
85 _eglCheckDeviceHandle(EGLDeviceEXT device)
89 simple_mtx_lock(_eglGlobal.Mutex);
90 cur = _eglGlobal.DeviceList;
92 if (cur == (_EGLDevice *) device)
96 simple_mtx_unlock(_eglGlobal.Mutex);
100 _EGLDevice _eglSoftwareDevice = {
101 /* TODO: EGL_EXT_device_drm support for KMS + llvmpipe */
102 .extensions = "EGL_MESA_device_software EGL_EXT_device_drm_render_node",
103 .MESA_device_software = EGL_TRUE,
104 .EXT_device_drm_render_node = EGL_TRUE,
109 * Negative value on error, zero if newly added, one if already in list.
112 _eglAddDRMDevice(drmDevicePtr device, _EGLDevice **out_dev)
116 if ((device->available_nodes & (1 << DRM_NODE_PRIMARY |
117 1 << DRM_NODE_RENDER)) == 0)
120 dev = _eglGlobal.DeviceList;
122 /* The first device is always software */
124 assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
129 assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM));
130 if (drmDevicesEqual(device, dev->device) != 0) {
137 dev->Next = calloc(1, sizeof(_EGLDevice));
145 dev->extensions = "EGL_EXT_device_drm";
146 dev->EXT_device_drm = EGL_TRUE;
147 dev->device = device;
149 /* TODO: EGL_EXT_device_drm_render_node support for kmsro + renderonly */
150 if (device->available_nodes & (1 << DRM_NODE_RENDER)) {
151 dev->extensions = "EGL_EXT_device_drm EGL_EXT_device_drm_render_node";
152 dev->EXT_device_drm_render_node = EGL_TRUE;
162 /* Adds a device in DeviceList, if needed for the given fd.
164 * If a software device, the fd is ignored.
167 _eglAddDevice(int fd, bool software)
171 simple_mtx_lock(_eglGlobal.Mutex);
172 dev = _eglGlobal.DeviceList;
174 /*This exception only happen in multithread case, when _eglAtExit is *
175 *called and _eglFiniDevice(where _eglGlobal.DeviceList is set to null)*
176 *is called in main thread. */
178 _eglLog(_EGL_FATAL, "_eglGlobal.DeviceList is freed");
182 /* The first device is always software */
184 assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
191 if (drmGetDevice2(fd, 0, &device) != 0) {
196 /* Device is not added - error or already present */
197 if (_eglAddDRMDevice(device, &dev) != 0)
198 drmFreeDevice(&device);
200 _eglLog(_EGL_FATAL, "Driver bug: Built without libdrm, yet looking for HW device");
205 simple_mtx_unlock(_eglGlobal.Mutex);
210 _eglDeviceSupports(_EGLDevice *dev, _EGLDeviceExtension ext)
213 case _EGL_DEVICE_SOFTWARE:
214 return dev->MESA_device_software;
215 case _EGL_DEVICE_DRM:
216 return dev->EXT_device_drm;
217 case _EGL_DEVICE_DRM_RENDER_NODE:
218 return dev->EXT_device_drm_render_node;
225 /* Ideally we'll have an extension which passes the render node,
226 * instead of the card one + magic.
228 * Then we can move this in _eglQueryDeviceStringEXT below. Until then
232 _eglGetDRMDeviceRenderNode(_EGLDevice *dev)
235 return dev->device->nodes[DRM_NODE_RENDER];
242 _eglQueryDeviceAttribEXT(_EGLDevice *dev, EGLint attribute,
247 _eglError(EGL_BAD_ATTRIBUTE, "eglQueryDeviceAttribEXT");
253 _eglQueryDeviceStringEXT(_EGLDevice *dev, EGLint name)
257 return dev->extensions;
258 case EGL_DRM_DEVICE_FILE_EXT:
259 if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM))
262 return dev->device->nodes[DRM_NODE_PRIMARY];
264 /* This should never happen: we don't yet support EGL_DEVICE_DRM for the
265 * software device, and physical devices are only exposed when libdrm is
270 case EGL_DRM_RENDER_NODE_FILE_EXT:
271 if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM_RENDER_NODE))
274 return dev->device ? dev->device->nodes[DRM_NODE_RENDER] : NULL;
276 /* Physical devices are only exposed when libdrm is available. */
277 assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
281 _eglError(EGL_BAD_PARAMETER, "eglQueryDeviceStringEXT");
285 /* Do a fresh lookup for devices.
287 * Walks through the DeviceList, discarding no longer available ones
288 * and adding new ones as applicable.
290 * Must be called with the global lock held.
293 _eglRefreshDeviceList(void)
295 ASSERTED _EGLDevice *dev;
298 dev = _eglGlobal.DeviceList;
300 /* The first device is always software */
302 assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
306 drmDevicePtr devices[64];
309 num_devs = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
310 for (int i = 0; i < num_devs; i++) {
311 if (!(devices[i]->available_nodes & (1 << DRM_NODE_RENDER)))
314 ret = _eglAddDRMDevice(devices[i], NULL);
316 /* Device is not added - error or already present */
318 drmFreeDevice(&devices[i]);
329 _eglQueryDevicesEXT(EGLint max_devices,
330 _EGLDevice **devices,
333 _EGLDevice *dev, *devs;
336 if ((devices && max_devices <= 0) || !num_devices)
337 return _eglError(EGL_BAD_PARAMETER, "eglQueryDevicesEXT");
339 simple_mtx_lock(_eglGlobal.Mutex);
341 num_devs = _eglRefreshDeviceList();
342 devs = _eglGlobal.DeviceList;
344 /* bail early if we only care about the count */
346 *num_devices = num_devs;
350 /* Push the first device (the software one) to the end of the list.
351 * Sending it to the user only if they've requested the full list.
353 * By default, the user is likely to pick the first device so having the
354 * software (aka least performant) one is not a good idea.
356 *num_devices = MIN2(num_devs, max_devices);
358 for (i = 0, dev = devs->Next; dev && i < max_devices; i++) {
363 /* User requested the full device list, add the sofware device. */
364 if (max_devices >= num_devs) {
365 assert(_eglDeviceSupports(devs, _EGL_DEVICE_SOFTWARE));
366 devices[num_devs - 1] = devs;
370 simple_mtx_unlock(_eglGlobal.Mutex);