egldevice.c revision 7ec681f3
101e04c3fSmrg/************************************************************************** 201e04c3fSmrg * 301e04c3fSmrg * Copyright 2015, 2018 Collabora 401e04c3fSmrg * All Rights Reserved. 501e04c3fSmrg * 601e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 701e04c3fSmrg * copy of this software and associated documentation files (the 801e04c3fSmrg * "Software"), to deal in the Software without restriction, including 901e04c3fSmrg * without limitation the rights to use, copy, modify, merge, publish, 1001e04c3fSmrg * distribute, sub license, and/or sell copies of the Software, and to 1101e04c3fSmrg * permit persons to whom the Software is furnished to do so, subject to 1201e04c3fSmrg * the following conditions: 1301e04c3fSmrg * 1401e04c3fSmrg * The above copyright notice and this permission notice (including the 1501e04c3fSmrg * next paragraph) shall be included in all copies or substantial portions 1601e04c3fSmrg * of the Software. 1701e04c3fSmrg * 1801e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1901e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2001e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2101e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2201e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2301e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2401e04c3fSmrg * DEALINGS IN THE SOFTWARE. 2501e04c3fSmrg * 2601e04c3fSmrg **************************************************************************/ 2701e04c3fSmrg 2801e04c3fSmrg#ifdef HAVE_LIBDRM 2901e04c3fSmrg#include <xf86drm.h> 3001e04c3fSmrg#endif 317ec681f3Smrg#include "util/compiler.h" 3201e04c3fSmrg#include "util/macros.h" 3301e04c3fSmrg 3401e04c3fSmrg#include "eglcurrent.h" 3501e04c3fSmrg#include "egldevice.h" 3601e04c3fSmrg#include "egllog.h" 3701e04c3fSmrg#include "eglglobals.h" 3801e04c3fSmrg#include "egltypedefs.h" 3901e04c3fSmrg 4001e04c3fSmrg 4101e04c3fSmrgstruct _egl_device { 4201e04c3fSmrg _EGLDevice *Next; 4301e04c3fSmrg 4401e04c3fSmrg const char *extensions; 4501e04c3fSmrg 4601e04c3fSmrg EGLBoolean MESA_device_software; 4701e04c3fSmrg EGLBoolean EXT_device_drm; 487ec681f3Smrg EGLBoolean EXT_device_drm_render_node; 4901e04c3fSmrg 5001e04c3fSmrg#ifdef HAVE_LIBDRM 5101e04c3fSmrg drmDevicePtr device; 5201e04c3fSmrg#endif 5301e04c3fSmrg}; 5401e04c3fSmrg 5501e04c3fSmrgvoid 5601e04c3fSmrg_eglFiniDevice(void) 5701e04c3fSmrg{ 5801e04c3fSmrg _EGLDevice *dev_list, *dev; 5901e04c3fSmrg 6001e04c3fSmrg /* atexit function is called with global mutex locked */ 6101e04c3fSmrg 6201e04c3fSmrg dev_list = _eglGlobal.DeviceList; 6301e04c3fSmrg 6401e04c3fSmrg /* The first device is static allocated SW device */ 6501e04c3fSmrg assert(dev_list); 6601e04c3fSmrg assert(_eglDeviceSupports(dev_list, _EGL_DEVICE_SOFTWARE)); 6701e04c3fSmrg dev_list = dev_list->Next; 6801e04c3fSmrg 6901e04c3fSmrg while (dev_list) { 7001e04c3fSmrg /* pop list head */ 7101e04c3fSmrg dev = dev_list; 7201e04c3fSmrg dev_list = dev_list->Next; 7301e04c3fSmrg 7401e04c3fSmrg#ifdef HAVE_LIBDRM 7501e04c3fSmrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM)); 7601e04c3fSmrg drmFreeDevice(&dev->device); 7701e04c3fSmrg#endif 7801e04c3fSmrg free(dev); 7901e04c3fSmrg } 8001e04c3fSmrg 8101e04c3fSmrg _eglGlobal.DeviceList = NULL; 8201e04c3fSmrg} 8301e04c3fSmrg 8401e04c3fSmrgEGLBoolean 8501e04c3fSmrg_eglCheckDeviceHandle(EGLDeviceEXT device) 8601e04c3fSmrg{ 8701e04c3fSmrg _EGLDevice *cur; 8801e04c3fSmrg 8901e04c3fSmrg mtx_lock(_eglGlobal.Mutex); 9001e04c3fSmrg cur = _eglGlobal.DeviceList; 9101e04c3fSmrg while (cur) { 9201e04c3fSmrg if (cur == (_EGLDevice *) device) 9301e04c3fSmrg break; 9401e04c3fSmrg cur = cur->Next; 9501e04c3fSmrg } 9601e04c3fSmrg mtx_unlock(_eglGlobal.Mutex); 9701e04c3fSmrg return (cur != NULL); 9801e04c3fSmrg} 9901e04c3fSmrg 10001e04c3fSmrg_EGLDevice _eglSoftwareDevice = { 1017ec681f3Smrg /* TODO: EGL_EXT_device_drm support for KMS + llvmpipe */ 1027ec681f3Smrg .extensions = "EGL_MESA_device_software EGL_EXT_device_drm_render_node", 10301e04c3fSmrg .MESA_device_software = EGL_TRUE, 1047ec681f3Smrg .EXT_device_drm_render_node = EGL_TRUE, 10501e04c3fSmrg}; 10601e04c3fSmrg 10701e04c3fSmrg#ifdef HAVE_LIBDRM 10801e04c3fSmrg/* 10901e04c3fSmrg * Negative value on error, zero if newly added, one if already in list. 11001e04c3fSmrg */ 11101e04c3fSmrgstatic int 11201e04c3fSmrg_eglAddDRMDevice(drmDevicePtr device, _EGLDevice **out_dev) 11301e04c3fSmrg{ 11401e04c3fSmrg _EGLDevice *dev; 11501e04c3fSmrg 1167ec681f3Smrg if ((device->available_nodes & (1 << DRM_NODE_PRIMARY | 1177ec681f3Smrg 1 << DRM_NODE_RENDER)) == 0) 11801e04c3fSmrg return -1; 11901e04c3fSmrg 12001e04c3fSmrg dev = _eglGlobal.DeviceList; 12101e04c3fSmrg 12201e04c3fSmrg /* The first device is always software */ 12301e04c3fSmrg assert(dev); 12401e04c3fSmrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); 12501e04c3fSmrg 12601e04c3fSmrg while (dev->Next) { 12701e04c3fSmrg dev = dev->Next; 12801e04c3fSmrg 12901e04c3fSmrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM)); 13001e04c3fSmrg if (drmDevicesEqual(device, dev->device) != 0) { 13101e04c3fSmrg if (out_dev) 13201e04c3fSmrg *out_dev = dev; 13301e04c3fSmrg return 1; 13401e04c3fSmrg } 13501e04c3fSmrg } 13601e04c3fSmrg 13701e04c3fSmrg dev->Next = calloc(1, sizeof(_EGLDevice)); 13801e04c3fSmrg if (!dev->Next) { 13901e04c3fSmrg if (out_dev) 14001e04c3fSmrg *out_dev = NULL; 14101e04c3fSmrg return -1; 14201e04c3fSmrg } 14301e04c3fSmrg 14401e04c3fSmrg dev = dev->Next; 14501e04c3fSmrg dev->extensions = "EGL_EXT_device_drm"; 14601e04c3fSmrg dev->EXT_device_drm = EGL_TRUE; 14701e04c3fSmrg dev->device = device; 14801e04c3fSmrg 1497ec681f3Smrg /* TODO: EGL_EXT_device_drm_render_node support for kmsro + renderonly */ 1507ec681f3Smrg if (device->available_nodes & (1 << DRM_NODE_RENDER)) { 1517ec681f3Smrg dev->extensions = "EGL_EXT_device_drm EGL_EXT_device_drm_render_node"; 1527ec681f3Smrg dev->EXT_device_drm_render_node = EGL_TRUE; 1537ec681f3Smrg } 1547ec681f3Smrg 15501e04c3fSmrg if (out_dev) 15601e04c3fSmrg *out_dev = dev; 15701e04c3fSmrg 15801e04c3fSmrg return 0; 15901e04c3fSmrg} 16001e04c3fSmrg#endif 16101e04c3fSmrg 16201e04c3fSmrg/* Adds a device in DeviceList, if needed for the given fd. 16301e04c3fSmrg * 16401e04c3fSmrg * If a software device, the fd is ignored. 16501e04c3fSmrg */ 16601e04c3fSmrg_EGLDevice * 16701e04c3fSmrg_eglAddDevice(int fd, bool software) 16801e04c3fSmrg{ 16901e04c3fSmrg _EGLDevice *dev; 17001e04c3fSmrg 17101e04c3fSmrg mtx_lock(_eglGlobal.Mutex); 17201e04c3fSmrg dev = _eglGlobal.DeviceList; 17301e04c3fSmrg 17401e04c3fSmrg /* The first device is always software */ 17501e04c3fSmrg assert(dev); 17601e04c3fSmrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); 17701e04c3fSmrg if (software) 17801e04c3fSmrg goto out; 17901e04c3fSmrg 18001e04c3fSmrg#ifdef HAVE_LIBDRM 18101e04c3fSmrg drmDevicePtr device; 18201e04c3fSmrg 18301e04c3fSmrg if (drmGetDevice2(fd, 0, &device) != 0) { 18401e04c3fSmrg dev = NULL; 18501e04c3fSmrg goto out; 18601e04c3fSmrg } 18701e04c3fSmrg 18801e04c3fSmrg /* Device is not added - error or already present */ 18901e04c3fSmrg if (_eglAddDRMDevice(device, &dev) != 0) 19001e04c3fSmrg drmFreeDevice(&device); 19101e04c3fSmrg#else 19201e04c3fSmrg _eglLog(_EGL_FATAL, "Driver bug: Built without libdrm, yet looking for HW device"); 19301e04c3fSmrg dev = NULL; 19401e04c3fSmrg#endif 19501e04c3fSmrg 19601e04c3fSmrgout: 19701e04c3fSmrg mtx_unlock(_eglGlobal.Mutex); 19801e04c3fSmrg return dev; 19901e04c3fSmrg} 20001e04c3fSmrg 20101e04c3fSmrgEGLBoolean 20201e04c3fSmrg_eglDeviceSupports(_EGLDevice *dev, _EGLDeviceExtension ext) 20301e04c3fSmrg{ 20401e04c3fSmrg switch (ext) { 20501e04c3fSmrg case _EGL_DEVICE_SOFTWARE: 20601e04c3fSmrg return dev->MESA_device_software; 20701e04c3fSmrg case _EGL_DEVICE_DRM: 20801e04c3fSmrg return dev->EXT_device_drm; 2097ec681f3Smrg case _EGL_DEVICE_DRM_RENDER_NODE: 2107ec681f3Smrg return dev->EXT_device_drm_render_node; 21101e04c3fSmrg default: 21201e04c3fSmrg assert(0); 21301e04c3fSmrg return EGL_FALSE; 21401e04c3fSmrg }; 21501e04c3fSmrg} 21601e04c3fSmrg 2177ec681f3Smrg/* Ideally we'll have an extension which passes the render node, 2187ec681f3Smrg * instead of the card one + magic. 2197ec681f3Smrg * 2207ec681f3Smrg * Then we can move this in _eglQueryDeviceStringEXT below. Until then 2217ec681f3Smrg * keep it separate. 2227ec681f3Smrg */ 2237ec681f3Smrgconst char * 2247ec681f3Smrg_eglGetDRMDeviceRenderNode(_EGLDevice *dev) 2257ec681f3Smrg{ 2267ec681f3Smrg#ifdef HAVE_LIBDRM 2277ec681f3Smrg return dev->device->nodes[DRM_NODE_RENDER]; 2287ec681f3Smrg#else 2297ec681f3Smrg return NULL; 2307ec681f3Smrg#endif 2317ec681f3Smrg} 2327ec681f3Smrg 23301e04c3fSmrgEGLBoolean 23401e04c3fSmrg_eglQueryDeviceAttribEXT(_EGLDevice *dev, EGLint attribute, 23501e04c3fSmrg EGLAttrib *value) 23601e04c3fSmrg{ 23701e04c3fSmrg switch (attribute) { 23801e04c3fSmrg default: 2397ec681f3Smrg _eglError(EGL_BAD_ATTRIBUTE, "eglQueryDeviceAttribEXT"); 24001e04c3fSmrg return EGL_FALSE; 24101e04c3fSmrg } 24201e04c3fSmrg} 24301e04c3fSmrg 24401e04c3fSmrgconst char * 24501e04c3fSmrg_eglQueryDeviceStringEXT(_EGLDevice *dev, EGLint name) 24601e04c3fSmrg{ 24701e04c3fSmrg switch (name) { 24801e04c3fSmrg case EGL_EXTENSIONS: 24901e04c3fSmrg return dev->extensions; 25001e04c3fSmrg case EGL_DRM_DEVICE_FILE_EXT: 2517ec681f3Smrg if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM)) 2527ec681f3Smrg break; 2537ec681f3Smrg#ifdef HAVE_LIBDRM 2547ec681f3Smrg return dev->device->nodes[DRM_NODE_PRIMARY]; 2557ec681f3Smrg#else 2567ec681f3Smrg /* This should never happen: we don't yet support EGL_DEVICE_DRM for the 2577ec681f3Smrg * software device, and physical devices are only exposed when libdrm is 2587ec681f3Smrg * available. */ 2597ec681f3Smrg assert(0); 2607ec681f3Smrg break; 26101e04c3fSmrg#endif 2627ec681f3Smrg case EGL_DRM_RENDER_NODE_FILE_EXT: 2637ec681f3Smrg if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM_RENDER_NODE)) 2647ec681f3Smrg break; 2657ec681f3Smrg#ifdef HAVE_LIBDRM 2667ec681f3Smrg return dev->device ? dev->device->nodes[DRM_NODE_RENDER] : NULL; 2677ec681f3Smrg#else 2687ec681f3Smrg /* Physical devices are only exposed when libdrm is available. */ 2697ec681f3Smrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); 27001e04c3fSmrg return NULL; 2717ec681f3Smrg#endif 2727ec681f3Smrg } 2737ec681f3Smrg _eglError(EGL_BAD_PARAMETER, "eglQueryDeviceStringEXT"); 2747ec681f3Smrg return NULL; 27501e04c3fSmrg} 27601e04c3fSmrg 27701e04c3fSmrg/* Do a fresh lookup for devices. 27801e04c3fSmrg * 27901e04c3fSmrg * Walks through the DeviceList, discarding no longer available ones 28001e04c3fSmrg * and adding new ones as applicable. 28101e04c3fSmrg * 28201e04c3fSmrg * Must be called with the global lock held. 28301e04c3fSmrg */ 28401e04c3fSmrgstatic int 28501e04c3fSmrg_eglRefreshDeviceList(void) 28601e04c3fSmrg{ 2877ec681f3Smrg ASSERTED _EGLDevice *dev; 28801e04c3fSmrg int count = 0; 28901e04c3fSmrg 29001e04c3fSmrg dev = _eglGlobal.DeviceList; 29101e04c3fSmrg 29201e04c3fSmrg /* The first device is always software */ 29301e04c3fSmrg assert(dev); 29401e04c3fSmrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); 29501e04c3fSmrg count++; 29601e04c3fSmrg 29701e04c3fSmrg#ifdef HAVE_LIBDRM 29801e04c3fSmrg drmDevicePtr devices[64]; 29901e04c3fSmrg int num_devs, ret; 30001e04c3fSmrg 30101e04c3fSmrg num_devs = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); 30201e04c3fSmrg for (int i = 0; i < num_devs; i++) { 3037ec681f3Smrg if (!(devices[i]->available_nodes & (1 << DRM_NODE_RENDER))) 3047ec681f3Smrg continue; 3057ec681f3Smrg 30601e04c3fSmrg ret = _eglAddDRMDevice(devices[i], NULL); 30701e04c3fSmrg 30801e04c3fSmrg /* Device is not added - error or already present */ 30901e04c3fSmrg if (ret != 0) 31001e04c3fSmrg drmFreeDevice(&devices[i]); 31101e04c3fSmrg 31201e04c3fSmrg if (ret >= 0) 31301e04c3fSmrg count++; 31401e04c3fSmrg } 31501e04c3fSmrg#endif 31601e04c3fSmrg 31701e04c3fSmrg return count; 31801e04c3fSmrg} 31901e04c3fSmrg 32001e04c3fSmrgEGLBoolean 32101e04c3fSmrg_eglQueryDevicesEXT(EGLint max_devices, 32201e04c3fSmrg _EGLDevice **devices, 32301e04c3fSmrg EGLint *num_devices) 32401e04c3fSmrg{ 32501e04c3fSmrg _EGLDevice *dev, *devs; 32601e04c3fSmrg int i = 0, num_devs; 32701e04c3fSmrg 32801e04c3fSmrg if ((devices && max_devices <= 0) || !num_devices) 32901e04c3fSmrg return _eglError(EGL_BAD_PARAMETER, "eglQueryDevicesEXT"); 33001e04c3fSmrg 33101e04c3fSmrg mtx_lock(_eglGlobal.Mutex); 33201e04c3fSmrg 33301e04c3fSmrg num_devs = _eglRefreshDeviceList(); 33401e04c3fSmrg devs = _eglGlobal.DeviceList; 33501e04c3fSmrg 33601e04c3fSmrg /* bail early if we only care about the count */ 33701e04c3fSmrg if (!devices) { 33801e04c3fSmrg *num_devices = num_devs; 33901e04c3fSmrg goto out; 34001e04c3fSmrg } 34101e04c3fSmrg 3427ec681f3Smrg /* Push the first device (the software one) to the end of the list. 3437ec681f3Smrg * Sending it to the user only if they've requested the full list. 3447ec681f3Smrg * 3457ec681f3Smrg * By default, the user is likely to pick the first device so having the 3467ec681f3Smrg * software (aka least performant) one is not a good idea. 3477ec681f3Smrg */ 34801e04c3fSmrg *num_devices = MIN2(num_devs, max_devices); 34901e04c3fSmrg 3507ec681f3Smrg for (i = 0, dev = devs->Next; dev && i < max_devices; i++) { 35101e04c3fSmrg devices[i] = dev; 35201e04c3fSmrg dev = dev->Next; 35301e04c3fSmrg } 35401e04c3fSmrg 3557ec681f3Smrg /* User requested the full device list, add the sofware device. */ 3567ec681f3Smrg if (max_devices >= num_devs) { 3577ec681f3Smrg assert(_eglDeviceSupports(devs, _EGL_DEVICE_SOFTWARE)); 3587ec681f3Smrg devices[num_devs - 1] = devs; 3597ec681f3Smrg } 3607ec681f3Smrg 36101e04c3fSmrgout: 36201e04c3fSmrg mtx_unlock(_eglGlobal.Mutex); 36301e04c3fSmrg 36401e04c3fSmrg return EGL_TRUE; 36501e04c3fSmrg} 366