egldevice.c revision 01e04c3f
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 3101e04c3fSmrg#include "util/macros.h" 3201e04c3fSmrg 3301e04c3fSmrg#include "eglcurrent.h" 3401e04c3fSmrg#include "egldevice.h" 3501e04c3fSmrg#include "egllog.h" 3601e04c3fSmrg#include "eglglobals.h" 3701e04c3fSmrg#include "egltypedefs.h" 3801e04c3fSmrg 3901e04c3fSmrg 4001e04c3fSmrgstruct _egl_device { 4101e04c3fSmrg _EGLDevice *Next; 4201e04c3fSmrg 4301e04c3fSmrg const char *extensions; 4401e04c3fSmrg 4501e04c3fSmrg EGLBoolean MESA_device_software; 4601e04c3fSmrg EGLBoolean EXT_device_drm; 4701e04c3fSmrg 4801e04c3fSmrg#ifdef HAVE_LIBDRM 4901e04c3fSmrg drmDevicePtr device; 5001e04c3fSmrg#endif 5101e04c3fSmrg}; 5201e04c3fSmrg 5301e04c3fSmrgvoid 5401e04c3fSmrg_eglFiniDevice(void) 5501e04c3fSmrg{ 5601e04c3fSmrg _EGLDevice *dev_list, *dev; 5701e04c3fSmrg 5801e04c3fSmrg /* atexit function is called with global mutex locked */ 5901e04c3fSmrg 6001e04c3fSmrg dev_list = _eglGlobal.DeviceList; 6101e04c3fSmrg 6201e04c3fSmrg /* The first device is static allocated SW device */ 6301e04c3fSmrg assert(dev_list); 6401e04c3fSmrg assert(_eglDeviceSupports(dev_list, _EGL_DEVICE_SOFTWARE)); 6501e04c3fSmrg dev_list = dev_list->Next; 6601e04c3fSmrg 6701e04c3fSmrg while (dev_list) { 6801e04c3fSmrg /* pop list head */ 6901e04c3fSmrg dev = dev_list; 7001e04c3fSmrg dev_list = dev_list->Next; 7101e04c3fSmrg 7201e04c3fSmrg#ifdef HAVE_LIBDRM 7301e04c3fSmrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM)); 7401e04c3fSmrg drmFreeDevice(&dev->device); 7501e04c3fSmrg#endif 7601e04c3fSmrg free(dev); 7701e04c3fSmrg } 7801e04c3fSmrg 7901e04c3fSmrg _eglGlobal.DeviceList = NULL; 8001e04c3fSmrg} 8101e04c3fSmrg 8201e04c3fSmrgEGLBoolean 8301e04c3fSmrg_eglCheckDeviceHandle(EGLDeviceEXT device) 8401e04c3fSmrg{ 8501e04c3fSmrg _EGLDevice *cur; 8601e04c3fSmrg 8701e04c3fSmrg mtx_lock(_eglGlobal.Mutex); 8801e04c3fSmrg cur = _eglGlobal.DeviceList; 8901e04c3fSmrg while (cur) { 9001e04c3fSmrg if (cur == (_EGLDevice *) device) 9101e04c3fSmrg break; 9201e04c3fSmrg cur = cur->Next; 9301e04c3fSmrg } 9401e04c3fSmrg mtx_unlock(_eglGlobal.Mutex); 9501e04c3fSmrg return (cur != NULL); 9601e04c3fSmrg} 9701e04c3fSmrg 9801e04c3fSmrg_EGLDevice _eglSoftwareDevice = { 9901e04c3fSmrg .extensions = "EGL_MESA_device_software", 10001e04c3fSmrg .MESA_device_software = EGL_TRUE, 10101e04c3fSmrg}; 10201e04c3fSmrg 10301e04c3fSmrg#ifdef HAVE_LIBDRM 10401e04c3fSmrg/* 10501e04c3fSmrg * Negative value on error, zero if newly added, one if already in list. 10601e04c3fSmrg */ 10701e04c3fSmrgstatic int 10801e04c3fSmrg_eglAddDRMDevice(drmDevicePtr device, _EGLDevice **out_dev) 10901e04c3fSmrg{ 11001e04c3fSmrg _EGLDevice *dev; 11101e04c3fSmrg 11201e04c3fSmrg if ((device->available_nodes & (1 << DRM_NODE_PRIMARY | 11301e04c3fSmrg 1 << DRM_NODE_RENDER)) == 0) 11401e04c3fSmrg return -1; 11501e04c3fSmrg 11601e04c3fSmrg dev = _eglGlobal.DeviceList; 11701e04c3fSmrg 11801e04c3fSmrg /* The first device is always software */ 11901e04c3fSmrg assert(dev); 12001e04c3fSmrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); 12101e04c3fSmrg 12201e04c3fSmrg while (dev->Next) { 12301e04c3fSmrg dev = dev->Next; 12401e04c3fSmrg 12501e04c3fSmrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM)); 12601e04c3fSmrg if (drmDevicesEqual(device, dev->device) != 0) { 12701e04c3fSmrg if (out_dev) 12801e04c3fSmrg *out_dev = dev; 12901e04c3fSmrg return 1; 13001e04c3fSmrg } 13101e04c3fSmrg } 13201e04c3fSmrg 13301e04c3fSmrg dev->Next = calloc(1, sizeof(_EGLDevice)); 13401e04c3fSmrg if (!dev->Next) { 13501e04c3fSmrg if (out_dev) 13601e04c3fSmrg *out_dev = NULL; 13701e04c3fSmrg return -1; 13801e04c3fSmrg } 13901e04c3fSmrg 14001e04c3fSmrg dev = dev->Next; 14101e04c3fSmrg dev->extensions = "EGL_EXT_device_drm"; 14201e04c3fSmrg dev->EXT_device_drm = EGL_TRUE; 14301e04c3fSmrg dev->device = device; 14401e04c3fSmrg 14501e04c3fSmrg if (out_dev) 14601e04c3fSmrg *out_dev = dev; 14701e04c3fSmrg 14801e04c3fSmrg return 0; 14901e04c3fSmrg} 15001e04c3fSmrg#endif 15101e04c3fSmrg 15201e04c3fSmrg/* Adds a device in DeviceList, if needed for the given fd. 15301e04c3fSmrg * 15401e04c3fSmrg * If a software device, the fd is ignored. 15501e04c3fSmrg */ 15601e04c3fSmrg_EGLDevice * 15701e04c3fSmrg_eglAddDevice(int fd, bool software) 15801e04c3fSmrg{ 15901e04c3fSmrg _EGLDevice *dev; 16001e04c3fSmrg 16101e04c3fSmrg mtx_lock(_eglGlobal.Mutex); 16201e04c3fSmrg dev = _eglGlobal.DeviceList; 16301e04c3fSmrg 16401e04c3fSmrg /* The first device is always software */ 16501e04c3fSmrg assert(dev); 16601e04c3fSmrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); 16701e04c3fSmrg if (software) 16801e04c3fSmrg goto out; 16901e04c3fSmrg 17001e04c3fSmrg#ifdef HAVE_LIBDRM 17101e04c3fSmrg drmDevicePtr device; 17201e04c3fSmrg 17301e04c3fSmrg if (drmGetDevice2(fd, 0, &device) != 0) { 17401e04c3fSmrg dev = NULL; 17501e04c3fSmrg goto out; 17601e04c3fSmrg } 17701e04c3fSmrg 17801e04c3fSmrg /* Device is not added - error or already present */ 17901e04c3fSmrg if (_eglAddDRMDevice(device, &dev) != 0) 18001e04c3fSmrg drmFreeDevice(&device); 18101e04c3fSmrg#else 18201e04c3fSmrg _eglLog(_EGL_FATAL, "Driver bug: Built without libdrm, yet looking for HW device"); 18301e04c3fSmrg dev = NULL; 18401e04c3fSmrg#endif 18501e04c3fSmrg 18601e04c3fSmrgout: 18701e04c3fSmrg mtx_unlock(_eglGlobal.Mutex); 18801e04c3fSmrg return dev; 18901e04c3fSmrg} 19001e04c3fSmrg 19101e04c3fSmrgEGLBoolean 19201e04c3fSmrg_eglDeviceSupports(_EGLDevice *dev, _EGLDeviceExtension ext) 19301e04c3fSmrg{ 19401e04c3fSmrg switch (ext) { 19501e04c3fSmrg case _EGL_DEVICE_SOFTWARE: 19601e04c3fSmrg return dev->MESA_device_software; 19701e04c3fSmrg case _EGL_DEVICE_DRM: 19801e04c3fSmrg return dev->EXT_device_drm; 19901e04c3fSmrg default: 20001e04c3fSmrg assert(0); 20101e04c3fSmrg return EGL_FALSE; 20201e04c3fSmrg }; 20301e04c3fSmrg} 20401e04c3fSmrg 20501e04c3fSmrg/* Ideally we'll have an extension which passes the render node, 20601e04c3fSmrg * instead of the card one + magic. 20701e04c3fSmrg * 20801e04c3fSmrg * Then we can move this in _eglQueryDeviceStringEXT below. Until then 20901e04c3fSmrg * keep it separate. 21001e04c3fSmrg */ 21101e04c3fSmrgconst char * 21201e04c3fSmrg_eglGetDRMDeviceRenderNode(_EGLDevice *dev) 21301e04c3fSmrg{ 21401e04c3fSmrg return dev->device->nodes[DRM_NODE_RENDER]; 21501e04c3fSmrg} 21601e04c3fSmrg 21701e04c3fSmrgEGLBoolean 21801e04c3fSmrg_eglQueryDeviceAttribEXT(_EGLDevice *dev, EGLint attribute, 21901e04c3fSmrg EGLAttrib *value) 22001e04c3fSmrg{ 22101e04c3fSmrg switch (attribute) { 22201e04c3fSmrg default: 22301e04c3fSmrg _eglError(EGL_BAD_ATTRIBUTE, "eglQueryDeviceStringEXT"); 22401e04c3fSmrg return EGL_FALSE; 22501e04c3fSmrg } 22601e04c3fSmrg} 22701e04c3fSmrg 22801e04c3fSmrgconst char * 22901e04c3fSmrg_eglQueryDeviceStringEXT(_EGLDevice *dev, EGLint name) 23001e04c3fSmrg{ 23101e04c3fSmrg switch (name) { 23201e04c3fSmrg case EGL_EXTENSIONS: 23301e04c3fSmrg return dev->extensions; 23401e04c3fSmrg#ifdef HAVE_LIBDRM 23501e04c3fSmrg case EGL_DRM_DEVICE_FILE_EXT: 23601e04c3fSmrg if (_eglDeviceSupports(dev, _EGL_DEVICE_DRM)) 23701e04c3fSmrg return dev->device->nodes[DRM_NODE_PRIMARY]; 23801e04c3fSmrg /* fall through */ 23901e04c3fSmrg#endif 24001e04c3fSmrg default: 24101e04c3fSmrg _eglError(EGL_BAD_PARAMETER, "eglQueryDeviceStringEXT"); 24201e04c3fSmrg return NULL; 24301e04c3fSmrg }; 24401e04c3fSmrg} 24501e04c3fSmrg 24601e04c3fSmrg/* Do a fresh lookup for devices. 24701e04c3fSmrg * 24801e04c3fSmrg * Walks through the DeviceList, discarding no longer available ones 24901e04c3fSmrg * and adding new ones as applicable. 25001e04c3fSmrg * 25101e04c3fSmrg * Must be called with the global lock held. 25201e04c3fSmrg */ 25301e04c3fSmrgstatic int 25401e04c3fSmrg_eglRefreshDeviceList(void) 25501e04c3fSmrg{ 25601e04c3fSmrg MAYBE_UNUSED _EGLDevice *dev; 25701e04c3fSmrg int count = 0; 25801e04c3fSmrg 25901e04c3fSmrg dev = _eglGlobal.DeviceList; 26001e04c3fSmrg 26101e04c3fSmrg /* The first device is always software */ 26201e04c3fSmrg assert(dev); 26301e04c3fSmrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); 26401e04c3fSmrg count++; 26501e04c3fSmrg 26601e04c3fSmrg#ifdef HAVE_LIBDRM 26701e04c3fSmrg drmDevicePtr devices[64]; 26801e04c3fSmrg int num_devs, ret; 26901e04c3fSmrg 27001e04c3fSmrg num_devs = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); 27101e04c3fSmrg for (int i = 0; i < num_devs; i++) { 27201e04c3fSmrg ret = _eglAddDRMDevice(devices[i], NULL); 27301e04c3fSmrg 27401e04c3fSmrg /* Device is not added - error or already present */ 27501e04c3fSmrg if (ret != 0) 27601e04c3fSmrg drmFreeDevice(&devices[i]); 27701e04c3fSmrg 27801e04c3fSmrg if (ret >= 0) 27901e04c3fSmrg count++; 28001e04c3fSmrg } 28101e04c3fSmrg#endif 28201e04c3fSmrg 28301e04c3fSmrg return count; 28401e04c3fSmrg} 28501e04c3fSmrg 28601e04c3fSmrgEGLBoolean 28701e04c3fSmrg_eglQueryDevicesEXT(EGLint max_devices, 28801e04c3fSmrg _EGLDevice **devices, 28901e04c3fSmrg EGLint *num_devices) 29001e04c3fSmrg{ 29101e04c3fSmrg _EGLDevice *dev, *devs; 29201e04c3fSmrg int i = 0, num_devs; 29301e04c3fSmrg 29401e04c3fSmrg if ((devices && max_devices <= 0) || !num_devices) 29501e04c3fSmrg return _eglError(EGL_BAD_PARAMETER, "eglQueryDevicesEXT"); 29601e04c3fSmrg 29701e04c3fSmrg mtx_lock(_eglGlobal.Mutex); 29801e04c3fSmrg 29901e04c3fSmrg num_devs = _eglRefreshDeviceList(); 30001e04c3fSmrg devs = _eglGlobal.DeviceList; 30101e04c3fSmrg 30201e04c3fSmrg /* bail early if we only care about the count */ 30301e04c3fSmrg if (!devices) { 30401e04c3fSmrg *num_devices = num_devs; 30501e04c3fSmrg goto out; 30601e04c3fSmrg } 30701e04c3fSmrg 30801e04c3fSmrg *num_devices = MIN2(num_devs, max_devices); 30901e04c3fSmrg 31001e04c3fSmrg for (i = 0, dev = devs; i < *num_devices; i++) { 31101e04c3fSmrg devices[i] = dev; 31201e04c3fSmrg dev = dev->Next; 31301e04c3fSmrg } 31401e04c3fSmrg 31501e04c3fSmrgout: 31601e04c3fSmrg mtx_unlock(_eglGlobal.Mutex); 31701e04c3fSmrg 31801e04c3fSmrg return EGL_TRUE; 31901e04c3fSmrg} 320