1b8e80941Smrg/************************************************************************** 2b8e80941Smrg * 3b8e80941Smrg * Copyright 2015, 2018 Collabora 4b8e80941Smrg * All Rights Reserved. 5b8e80941Smrg * 6b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7b8e80941Smrg * copy of this software and associated documentation files (the 8b8e80941Smrg * "Software"), to deal in the Software without restriction, including 9b8e80941Smrg * without limitation the rights to use, copy, modify, merge, publish, 10b8e80941Smrg * distribute, sub license, and/or sell copies of the Software, and to 11b8e80941Smrg * permit persons to whom the Software is furnished to do so, subject to 12b8e80941Smrg * the following conditions: 13b8e80941Smrg * 14b8e80941Smrg * The above copyright notice and this permission notice (including the 15b8e80941Smrg * next paragraph) shall be included in all copies or substantial portions 16b8e80941Smrg * of the Software. 17b8e80941Smrg * 18b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24b8e80941Smrg * DEALINGS IN THE SOFTWARE. 25b8e80941Smrg * 26b8e80941Smrg **************************************************************************/ 27b8e80941Smrg 28b8e80941Smrg#ifdef HAVE_LIBDRM 29b8e80941Smrg#include <xf86drm.h> 30b8e80941Smrg#endif 31b8e80941Smrg#include "util/macros.h" 32b8e80941Smrg 33b8e80941Smrg#include "eglcurrent.h" 34b8e80941Smrg#include "egldevice.h" 35b8e80941Smrg#include "egllog.h" 36b8e80941Smrg#include "eglglobals.h" 37b8e80941Smrg#include "egltypedefs.h" 38b8e80941Smrg 39b8e80941Smrg 40b8e80941Smrgstruct _egl_device { 41b8e80941Smrg _EGLDevice *Next; 42b8e80941Smrg 43b8e80941Smrg const char *extensions; 44b8e80941Smrg 45b8e80941Smrg EGLBoolean MESA_device_software; 46b8e80941Smrg EGLBoolean EXT_device_drm; 47b8e80941Smrg 48b8e80941Smrg#ifdef HAVE_LIBDRM 49b8e80941Smrg drmDevicePtr device; 50b8e80941Smrg#endif 51b8e80941Smrg}; 52b8e80941Smrg 53b8e80941Smrgvoid 54b8e80941Smrg_eglFiniDevice(void) 55b8e80941Smrg{ 56b8e80941Smrg _EGLDevice *dev_list, *dev; 57b8e80941Smrg 58b8e80941Smrg /* atexit function is called with global mutex locked */ 59b8e80941Smrg 60b8e80941Smrg dev_list = _eglGlobal.DeviceList; 61b8e80941Smrg 62b8e80941Smrg /* The first device is static allocated SW device */ 63b8e80941Smrg assert(dev_list); 64b8e80941Smrg assert(_eglDeviceSupports(dev_list, _EGL_DEVICE_SOFTWARE)); 65b8e80941Smrg dev_list = dev_list->Next; 66b8e80941Smrg 67b8e80941Smrg while (dev_list) { 68b8e80941Smrg /* pop list head */ 69b8e80941Smrg dev = dev_list; 70b8e80941Smrg dev_list = dev_list->Next; 71b8e80941Smrg 72b8e80941Smrg#ifdef HAVE_LIBDRM 73b8e80941Smrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM)); 74b8e80941Smrg drmFreeDevice(&dev->device); 75b8e80941Smrg#endif 76b8e80941Smrg free(dev); 77b8e80941Smrg } 78b8e80941Smrg 79b8e80941Smrg _eglGlobal.DeviceList = NULL; 80b8e80941Smrg} 81b8e80941Smrg 82b8e80941SmrgEGLBoolean 83b8e80941Smrg_eglCheckDeviceHandle(EGLDeviceEXT device) 84b8e80941Smrg{ 85b8e80941Smrg _EGLDevice *cur; 86b8e80941Smrg 87b8e80941Smrg mtx_lock(_eglGlobal.Mutex); 88b8e80941Smrg cur = _eglGlobal.DeviceList; 89b8e80941Smrg while (cur) { 90b8e80941Smrg if (cur == (_EGLDevice *) device) 91b8e80941Smrg break; 92b8e80941Smrg cur = cur->Next; 93b8e80941Smrg } 94b8e80941Smrg mtx_unlock(_eglGlobal.Mutex); 95b8e80941Smrg return (cur != NULL); 96b8e80941Smrg} 97b8e80941Smrg 98b8e80941Smrg_EGLDevice _eglSoftwareDevice = { 99b8e80941Smrg .extensions = "EGL_MESA_device_software", 100b8e80941Smrg .MESA_device_software = EGL_TRUE, 101b8e80941Smrg}; 102b8e80941Smrg 103b8e80941Smrg#ifdef HAVE_LIBDRM 104b8e80941Smrg/* 105b8e80941Smrg * Negative value on error, zero if newly added, one if already in list. 106b8e80941Smrg */ 107b8e80941Smrgstatic int 108b8e80941Smrg_eglAddDRMDevice(drmDevicePtr device, _EGLDevice **out_dev) 109b8e80941Smrg{ 110b8e80941Smrg _EGLDevice *dev; 111b8e80941Smrg const int wanted_nodes = 1 << DRM_NODE_RENDER | 1 << DRM_NODE_PRIMARY; 112b8e80941Smrg 113b8e80941Smrg if ((device->available_nodes & wanted_nodes) != wanted_nodes) 114b8e80941Smrg return -1; 115b8e80941Smrg 116b8e80941Smrg dev = _eglGlobal.DeviceList; 117b8e80941Smrg 118b8e80941Smrg /* The first device is always software */ 119b8e80941Smrg assert(dev); 120b8e80941Smrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); 121b8e80941Smrg 122b8e80941Smrg while (dev->Next) { 123b8e80941Smrg dev = dev->Next; 124b8e80941Smrg 125b8e80941Smrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_DRM)); 126b8e80941Smrg if (drmDevicesEqual(device, dev->device) != 0) { 127b8e80941Smrg if (out_dev) 128b8e80941Smrg *out_dev = dev; 129b8e80941Smrg return 1; 130b8e80941Smrg } 131b8e80941Smrg } 132b8e80941Smrg 133b8e80941Smrg dev->Next = calloc(1, sizeof(_EGLDevice)); 134b8e80941Smrg if (!dev->Next) { 135b8e80941Smrg if (out_dev) 136b8e80941Smrg *out_dev = NULL; 137b8e80941Smrg return -1; 138b8e80941Smrg } 139b8e80941Smrg 140b8e80941Smrg dev = dev->Next; 141b8e80941Smrg dev->extensions = "EGL_EXT_device_drm"; 142b8e80941Smrg dev->EXT_device_drm = EGL_TRUE; 143b8e80941Smrg dev->device = device; 144b8e80941Smrg 145b8e80941Smrg if (out_dev) 146b8e80941Smrg *out_dev = dev; 147b8e80941Smrg 148b8e80941Smrg return 0; 149b8e80941Smrg} 150b8e80941Smrg#endif 151b8e80941Smrg 152b8e80941Smrg/* Adds a device in DeviceList, if needed for the given fd. 153b8e80941Smrg * 154b8e80941Smrg * If a software device, the fd is ignored. 155b8e80941Smrg */ 156b8e80941Smrg_EGLDevice * 157b8e80941Smrg_eglAddDevice(int fd, bool software) 158b8e80941Smrg{ 159b8e80941Smrg _EGLDevice *dev; 160b8e80941Smrg 161b8e80941Smrg mtx_lock(_eglGlobal.Mutex); 162b8e80941Smrg dev = _eglGlobal.DeviceList; 163b8e80941Smrg 164b8e80941Smrg /* The first device is always software */ 165b8e80941Smrg assert(dev); 166b8e80941Smrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); 167b8e80941Smrg if (software) 168b8e80941Smrg goto out; 169b8e80941Smrg 170b8e80941Smrg#ifdef HAVE_LIBDRM 171b8e80941Smrg drmDevicePtr device; 172b8e80941Smrg 173b8e80941Smrg if (drmGetDevice2(fd, 0, &device) != 0) { 174b8e80941Smrg dev = NULL; 175b8e80941Smrg goto out; 176b8e80941Smrg } 177b8e80941Smrg 178b8e80941Smrg /* Device is not added - error or already present */ 179b8e80941Smrg if (_eglAddDRMDevice(device, &dev) != 0) 180b8e80941Smrg drmFreeDevice(&device); 181b8e80941Smrg#else 182b8e80941Smrg _eglLog(_EGL_FATAL, "Driver bug: Built without libdrm, yet looking for HW device"); 183b8e80941Smrg dev = NULL; 184b8e80941Smrg#endif 185b8e80941Smrg 186b8e80941Smrgout: 187b8e80941Smrg mtx_unlock(_eglGlobal.Mutex); 188b8e80941Smrg return dev; 189b8e80941Smrg} 190b8e80941Smrg 191b8e80941SmrgEGLBoolean 192b8e80941Smrg_eglDeviceSupports(_EGLDevice *dev, _EGLDeviceExtension ext) 193b8e80941Smrg{ 194b8e80941Smrg switch (ext) { 195b8e80941Smrg case _EGL_DEVICE_SOFTWARE: 196b8e80941Smrg return dev->MESA_device_software; 197b8e80941Smrg case _EGL_DEVICE_DRM: 198b8e80941Smrg return dev->EXT_device_drm; 199b8e80941Smrg default: 200b8e80941Smrg assert(0); 201b8e80941Smrg return EGL_FALSE; 202b8e80941Smrg }; 203b8e80941Smrg} 204b8e80941Smrg 205b8e80941SmrgEGLBoolean 206b8e80941Smrg_eglQueryDeviceAttribEXT(_EGLDevice *dev, EGLint attribute, 207b8e80941Smrg EGLAttrib *value) 208b8e80941Smrg{ 209b8e80941Smrg switch (attribute) { 210b8e80941Smrg default: 211b8e80941Smrg _eglError(EGL_BAD_ATTRIBUTE, "eglQueryDeviceStringEXT"); 212b8e80941Smrg return EGL_FALSE; 213b8e80941Smrg } 214b8e80941Smrg} 215b8e80941Smrg 216b8e80941Smrgconst char * 217b8e80941Smrg_eglQueryDeviceStringEXT(_EGLDevice *dev, EGLint name) 218b8e80941Smrg{ 219b8e80941Smrg switch (name) { 220b8e80941Smrg case EGL_EXTENSIONS: 221b8e80941Smrg return dev->extensions; 222b8e80941Smrg#ifdef HAVE_LIBDRM 223b8e80941Smrg case EGL_DRM_DEVICE_FILE_EXT: 224b8e80941Smrg if (_eglDeviceSupports(dev, _EGL_DEVICE_DRM)) 225b8e80941Smrg return dev->device->nodes[DRM_NODE_PRIMARY]; 226b8e80941Smrg /* fall through */ 227b8e80941Smrg#endif 228b8e80941Smrg default: 229b8e80941Smrg _eglError(EGL_BAD_PARAMETER, "eglQueryDeviceStringEXT"); 230b8e80941Smrg return NULL; 231b8e80941Smrg }; 232b8e80941Smrg} 233b8e80941Smrg 234b8e80941Smrg/* Do a fresh lookup for devices. 235b8e80941Smrg * 236b8e80941Smrg * Walks through the DeviceList, discarding no longer available ones 237b8e80941Smrg * and adding new ones as applicable. 238b8e80941Smrg * 239b8e80941Smrg * Must be called with the global lock held. 240b8e80941Smrg */ 241b8e80941Smrgstatic int 242b8e80941Smrg_eglRefreshDeviceList(void) 243b8e80941Smrg{ 244b8e80941Smrg MAYBE_UNUSED _EGLDevice *dev; 245b8e80941Smrg int count = 0; 246b8e80941Smrg 247b8e80941Smrg dev = _eglGlobal.DeviceList; 248b8e80941Smrg 249b8e80941Smrg /* The first device is always software */ 250b8e80941Smrg assert(dev); 251b8e80941Smrg assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE)); 252b8e80941Smrg count++; 253b8e80941Smrg 254b8e80941Smrg#ifdef HAVE_LIBDRM 255b8e80941Smrg drmDevicePtr devices[64]; 256b8e80941Smrg int num_devs, ret; 257b8e80941Smrg 258b8e80941Smrg num_devs = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); 259b8e80941Smrg for (int i = 0; i < num_devs; i++) { 260b8e80941Smrg ret = _eglAddDRMDevice(devices[i], NULL); 261b8e80941Smrg 262b8e80941Smrg /* Device is not added - error or already present */ 263b8e80941Smrg if (ret != 0) 264b8e80941Smrg drmFreeDevice(&devices[i]); 265b8e80941Smrg 266b8e80941Smrg if (ret >= 0) 267b8e80941Smrg count++; 268b8e80941Smrg } 269b8e80941Smrg#endif 270b8e80941Smrg 271b8e80941Smrg return count; 272b8e80941Smrg} 273b8e80941Smrg 274b8e80941SmrgEGLBoolean 275b8e80941Smrg_eglQueryDevicesEXT(EGLint max_devices, 276b8e80941Smrg _EGLDevice **devices, 277b8e80941Smrg EGLint *num_devices) 278b8e80941Smrg{ 279b8e80941Smrg _EGLDevice *dev, *devs; 280b8e80941Smrg int i = 0, num_devs; 281b8e80941Smrg 282b8e80941Smrg if ((devices && max_devices <= 0) || !num_devices) 283b8e80941Smrg return _eglError(EGL_BAD_PARAMETER, "eglQueryDevicesEXT"); 284b8e80941Smrg 285b8e80941Smrg mtx_lock(_eglGlobal.Mutex); 286b8e80941Smrg 287b8e80941Smrg num_devs = _eglRefreshDeviceList(); 288b8e80941Smrg devs = _eglGlobal.DeviceList; 289b8e80941Smrg 290b8e80941Smrg /* bail early if we only care about the count */ 291b8e80941Smrg if (!devices) { 292b8e80941Smrg *num_devices = num_devs; 293b8e80941Smrg goto out; 294b8e80941Smrg } 295b8e80941Smrg 296b8e80941Smrg *num_devices = MIN2(num_devs, max_devices); 297b8e80941Smrg 298b8e80941Smrg for (i = 0, dev = devs; i < *num_devices; i++) { 299b8e80941Smrg devices[i] = dev; 300b8e80941Smrg dev = dev->Next; 301b8e80941Smrg } 302b8e80941Smrg 303b8e80941Smrgout: 304b8e80941Smrg mtx_unlock(_eglGlobal.Mutex); 305b8e80941Smrg 306b8e80941Smrg return EGL_TRUE; 307b8e80941Smrg} 308