From 2747fcd3fce8ad062e329e765d44db23c850588d Mon Sep 17 00:00:00 2001 From: Kyle Brenneman Date: Wed, 10 Feb 2021 15:39:17 -0700 Subject: [PATCH] EGL: Allow adding EGLDeviceEXT handles It's possible for new devices to become available while a program is running, so eglQueryDevicesEXT might need to return a different list. Change the EGLDeviceEXT hashtable so that each entry is allocated and added separately, rathat than allocating every entry in a single malloc. Added a new __eglAddDevice function, which adds an entry to the device hashtable. When the application calls eglQueryDevicesEXT, always call through to each vendor library, and add (or update) each EGLDeviceEXT to the hashtable. There's still no provision for removing an entry from the device hashtable. The semantics of hot-unplugging a device aren't defined yet, and there's no way to ensure that libglvnd's mapping will get updated if a device disappears asynchonously, so it's up to the vendor library to deal with the old handle. --- src/EGL/libegl.c | 79 +++++++++++++++++++++++--- src/EGL/libeglmapping.c | 121 +++++++++++----------------------------- src/EGL/libeglmapping.h | 25 ++------- 3 files changed, 107 insertions(+), 118 deletions(-) diff --git a/src/EGL/libegl.c b/src/EGL/libegl.c index 4e9f615..30468b1 100644 --- a/src/EGL/libegl.c +++ b/src/EGL/libegl.c @@ -955,9 +955,73 @@ PUBLIC const char *EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name) } } +static EGLBoolean QueryVendorDevices(__EGLvendorInfo *vendor, EGLint max_devices, + EGLDeviceEXT *devices, EGLint *num_devices) +{ + EGLDeviceEXT *vendorDevices = NULL; + EGLint vendorCount = 0; + EGLint i; + + if (!vendor->supportsDevice) { + return EGL_TRUE; + } + + if (!vendor->staticDispatch.queryDevicesEXT(0, NULL, &vendorCount)) { + // Even if this vendor fails, we can still return the devices from any + // other vendors + return EGL_TRUE; + } + if (vendorCount <= 0) { + return EGL_TRUE; + } + + if (devices == NULL) { + // We're only getting the number of devices. + *num_devices += vendorCount; + return EGL_TRUE; + } + + vendorDevices = malloc(sizeof(EGLDeviceEXT) * vendorCount); + if (vendorDevices == NULL) + { + __eglReportCritical(EGL_BAD_ALLOC, "eglQueryDevicesEXT", + __eglGetThreadLabel(), "Out of memory allocating device list"); + return EGL_FALSE; + } + + if (!vendor->staticDispatch.queryDevicesEXT(vendorCount, vendorDevices, &vendorCount)) { + free(vendorDevices); + return EGL_TRUE; + } + + // Add or update our mapping for all of the devices, and fill in the + // caller's array. + for (i=0; isupportsDevice) { + if (dev == EGL_NO_DEVICE_EXT) { + // If the handle is NULL, then just silently ignore it. return EGL_TRUE; } - if (!vendor->staticDispatch.queryDevicesEXT(0, NULL, &count)) { - // Even if this vendor fails, we can still return the devices from any - // other vendors - return EGL_TRUE; - } - if (count <= 0) { - return EGL_TRUE; - } - - devices = (EGLDeviceEXT *) malloc(count * sizeof(EGLDeviceEXT)); - if (devices == NULL) { - return EGL_FALSE; - } - - if (!vendor->staticDispatch.queryDevicesEXT(count, devices, &count)) { - free(devices); - return EGL_FALSE; - } - - newDevList = (__EGLdeviceInfo *) realloc(__eglDeviceList, - (__eglDeviceCount + count) * sizeof(__EGLdeviceInfo)); - if (newDevList == NULL) { - free(devices); - return EGL_FALSE; - } - __eglDeviceList = newDevList; - - for (i=0; ihandle = dev; + HASH_ADD_PTR(_LH(__eglDeviceHash), handle, devInfo); } - free(devices); - + devInfo->vendor = vendor; + LKDHASH_UNLOCK(__eglDeviceHash); return EGL_TRUE; } -void InitDeviceListInternal(void) -{ - struct glvnd_list *vendorList = __eglLoadVendors(); - __EGLvendorInfo *vendor; - EGLint i; - - __eglDeviceList = NULL; - __eglDeviceHash = NULL; - __eglDeviceCount = 0; - - glvnd_list_for_each_entry(vendor, vendorList, entry) { - if (!AddVendorDevices(vendor)) { - free(__eglDeviceList); - __eglDeviceList = NULL; - __eglDeviceCount = 0; - return; - } - } - - // Build a hashtable for the devices. - for (i=0; i<__eglDeviceCount; i++) { - __EGLdeviceInfo *dev = &__eglDeviceList[i]; - HASH_ADD_PTR(__eglDeviceHash, handle, dev); - } -} - -void __eglInitDeviceList(void) -{ - __glvndPthreadFuncs.once(&deviceListInitOnce, InitDeviceListInternal); -} - __EGLvendorInfo *__eglGetVendorFromDevice(EGLDeviceEXT dev) { __EGLdeviceInfo *devInfo; + __EGLvendorInfo *vendor = NULL; - __eglInitDeviceList(); - - HASH_FIND_PTR(__eglDeviceHash, &dev, devInfo); + LKDHASH_RDLOCK(__eglDeviceHash); + HASH_FIND_PTR(_LH(__eglDeviceHash), &dev, devInfo); if (devInfo != NULL) { - return devInfo->vendor; + vendor = devInfo->vendor; } else { - return NULL; + vendor = NULL; } + LKDHASH_UNLOCK(__eglDeviceHash); + + return vendor; } diff --git a/src/EGL/libeglmapping.h b/src/EGL/libeglmapping.h index 26747e4..d1018d9 100644 --- a/src/EGL/libeglmapping.h +++ b/src/EGL/libeglmapping.h @@ -44,16 +44,6 @@ typedef struct __EGLdisplayInfoRec { __EGLvendorInfo *vendor; } __EGLdisplayInfo; -typedef struct __EGLdeviceInfoRec { - EGLDeviceEXT handle; - __EGLvendorInfo *vendor; - UT_hash_handle hh; -} __EGLdeviceInfo; - -extern __EGLdeviceInfo *__eglDeviceList; -extern __EGLdeviceInfo *__eglDeviceHash; -extern int __eglDeviceCount; - void __eglThreadInitialize(void); /*! @@ -61,22 +51,12 @@ void __eglThreadInitialize(void); */ void __eglMappingInit(void); -/*! - * Initializes the EGLDeviceEXT list and hashtable. - * - * This function must be called before trying to access the \c __eglDeviceList - * array. - */ -void __eglInitDeviceList(void); - /*! * This handles freeing all mapping state during library teardown * or resetting locks on fork recovery. */ void __eglMappingTeardown(EGLBoolean doReset); -const __EGLdeviceInfo *__eglGetDeviceList(EGLint *deviceCount); - /*! * Looks up the __EGLdisplayInfo structure for a display. If the display does * not exist, then this returns NULL. @@ -110,6 +90,11 @@ __eglMustCastToProperFunctionPointerType __eglGetEGLDispatchAddress(const char * __eglMustCastToProperFunctionPointerType __eglFetchDispatchEntry(__EGLvendorInfo *vendor, int index); +/** + * Adds an EGLDeviceEXT handle to libglvnd's mapping. + */ +EGLBoolean __eglAddDevice(EGLDeviceEXT dev, __EGLvendorInfo *vendor); + __EGLvendorInfo *__eglGetVendorFromDevice(EGLDeviceEXT dev); void __eglSetError(EGLint errorCode);