From dbb4457d9858fa977246aa5e9cabe83455022dfe Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Wed, 4 Jul 2018 17:21:16 +0100 Subject: [PATCH] egl: add EGL_EXT_device_drm support MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add implementation based around the drmDevice API. As such it's only available only when building with libdrm. With the latter already a requirement when using !SW code paths in the platform code. Note: the current code will work if a device is hot-plugged. Yet hot-unplugged is not implemented, since I have no ways of testing it. v2: - ddd some _eglDeviceSupports checks - require DRM_NODE_RENDER - add _eglGetDRMDeviceRenderNode helper v3: - flip inverted asserts (Mathias) Signed-off-by: Emil Velikov Reviewed-by: Mathias Fröhlich --- src/egl/main/egldevice.c | 113 +++++++++++++++++++++++++++++++++++++++ src/egl/main/egldevice.h | 4 ++ 2 files changed, 117 insertions(+) diff --git a/src/egl/main/egldevice.c b/src/egl/main/egldevice.c index e285dd33fb7..4878039be0e 100644 --- a/src/egl/main/egldevice.c +++ b/src/egl/main/egldevice.c @@ -25,10 +25,14 @@ * **************************************************************************/ +#ifdef HAVE_LIBDRM +#include +#endif #include "util/macros.h" #include "eglcurrent.h" #include "egldevice.h" +#include "egllog.h" #include "eglglobals.h" #include "egltypedefs.h" @@ -39,6 +43,11 @@ struct _egl_device { const char *extensions; EGLBoolean MESA_device_software; + EGLBoolean EXT_device_drm; + +#ifdef HAVE_LIBDRM + drmDevicePtr device; +#endif }; void @@ -60,6 +69,10 @@ _eglFiniDevice(void) dev = dev_list; dev_list = dev_list->Next; +#ifdef HAVE_LIBDRM + assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM)); + drmFreeDevice(&dev->device); +#endif free(dev); } @@ -87,6 +100,55 @@ _EGLDevice _eglSoftwareDevice = { .MESA_device_software = EGL_TRUE, }; +#ifdef HAVE_LIBDRM +/* + * Negative value on error, zero if newly added, one if already in list. + */ +static int +_eglAddDRMDevice(drmDevicePtr device, _EGLDevice **out_dev) +{ + _EGLDevice *dev; + + if ((device->available_nodes & (1 << DRM_NODE_PRIMARY | + 1 << DRM_NODE_RENDER)) == 0) + return -1; + + dev = _eglGlobal.DeviceList; + + /* The first device is always software */ + assert(dev); + assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); + + while (dev->Next) { + dev = dev->Next; + + assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM)); + if (drmDevicesEqual(device, dev->device) != 0) { + if (out_dev) + *out_dev = dev; + return 1; + } + } + + dev->Next = calloc(1, sizeof(_EGLDevice)); + if (!dev->Next) { + if (out_dev) + *out_dev = NULL; + return -1; + } + + dev = dev->Next; + dev->extensions = "EGL_EXT_device_drm"; + dev->EXT_device_drm = EGL_TRUE; + dev->device = device; + + if (out_dev) + *out_dev = dev; + + return 0; +} +#endif + /* Adds a device in DeviceList, if needed for the given fd. * * If a software device, the fd is ignored. @@ -105,7 +167,21 @@ _eglAddDevice(int fd, bool software) if (software) goto out; +#ifdef HAVE_LIBDRM + drmDevicePtr device; + + if (drmGetDevice2(fd, 0, &device) != 0) { + dev = NULL; + goto out; + } + + /* Device is not added - error or already present */ + if (_eglAddDRMDevice(device, &dev) != 0) + drmFreeDevice(&device); +#else + _eglLog(_EGL_FATAL, "Driver bug: Built without libdrm, yet looking for HW device"); dev = NULL; +#endif out: mtx_unlock(_eglGlobal.Mutex); @@ -118,12 +194,26 @@ _eglDeviceSupports(_EGLDevice *dev, _EGLDeviceExtension ext) switch (ext) { case _EGL_DEVICE_SOFTWARE: return dev->MESA_device_software; + case _EGL_DEVICE_DRM: + return dev->EXT_device_drm; default: assert(0); return EGL_FALSE; }; } +/* Ideally we'll have an extension which passes the render node, + * instead of the card one + magic. + * + * Then we can move this in _eglQueryDeviceStringEXT below. Until then + * keep it separate. + */ +const char * +_eglGetDRMDeviceRenderNode(_EGLDevice *dev) +{ + return dev->device->nodes[DRM_NODE_RENDER]; +} + EGLBoolean _eglQueryDeviceAttribEXT(_EGLDevice *dev, EGLint attribute, EGLAttrib *value) @@ -141,6 +231,12 @@ _eglQueryDeviceStringEXT(_EGLDevice *dev, EGLint name) switch (name) { case EGL_EXTENSIONS: return dev->extensions; +#ifdef HAVE_LIBDRM + case EGL_DRM_DEVICE_FILE_EXT: + if (_eglDeviceSupports(dev, _EGL_DEVICE_DRM)) + return dev->device->nodes[DRM_NODE_PRIMARY]; + /* fall through */ +#endif default: _eglError(EGL_BAD_PARAMETER, "eglQueryDeviceStringEXT"); return NULL; @@ -167,6 +263,23 @@ _eglRefreshDeviceList(void) assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); count++; +#ifdef HAVE_LIBDRM + drmDevicePtr devices[64]; + int num_devs, ret; + + num_devs = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); + for (int i = 0; i < num_devs; i++) { + ret = _eglAddDRMDevice(devices[i], NULL); + + /* Device is not added - error or already present */ + if (ret != 0) + drmFreeDevice(&devices[i]); + + if (ret >= 0) + count++; + } +#endif + return count; } diff --git a/src/egl/main/egldevice.h b/src/egl/main/egldevice.h index 74b5ddeee5c..ddcdcd17f5a 100644 --- a/src/egl/main/egldevice.h +++ b/src/egl/main/egldevice.h @@ -60,6 +60,7 @@ _eglAddDevice(int fd, bool software); enum _egl_device_extension { _EGL_DEVICE_SOFTWARE, + _EGL_DEVICE_DRM, }; typedef enum _egl_device_extension _EGLDeviceExtension; @@ -67,6 +68,9 @@ typedef enum _egl_device_extension _EGLDeviceExtension; EGLBoolean _eglDeviceSupports(_EGLDevice *dev, _EGLDeviceExtension ext); +const char * +_eglGetDRMDeviceRenderNode(_EGLDevice *dev); + EGLBoolean _eglQueryDeviceAttribEXT(_EGLDevice *dev, EGLint attribute, EGLAttrib *value); -- 2.30.2