diff options
Diffstat (limited to 'src/egl/main')
-rw-r--r-- | src/egl/main/50_mesa.json | 6 | ||||
-rw-r--r-- | src/egl/main/eglapi.c | 6 | ||||
-rw-r--r-- | src/egl/main/egldispatchstubs.c | 110 | ||||
-rw-r--r-- | src/egl/main/egldispatchstubs.h | 26 | ||||
-rw-r--r-- | src/egl/main/eglglobals.c | 47 | ||||
-rw-r--r-- | src/egl/main/eglglobals.h | 13 | ||||
-rw-r--r-- | src/egl/main/eglglvnd.c | 82 |
7 files changed, 285 insertions, 5 deletions
diff --git a/src/egl/main/50_mesa.json b/src/egl/main/50_mesa.json new file mode 100644 index 00000000000..8aaaa100ffa --- /dev/null +++ b/src/egl/main/50_mesa.json @@ -0,0 +1,6 @@ +{ + "file_format_version" : "1.0.0", + "ICD" : { + "library_path" : "libEGL_mesa.so.0" + } +} diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 5694b5a4ca3..fc243a58e8c 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -657,7 +657,11 @@ eglQueryString(EGLDisplay dpy, EGLint name) _EGLDriver *drv; if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) { - RETURN_EGL_SUCCESS(NULL, _eglGlobal.ClientExtensionString); + const char *ret = _eglGetClientExtensionString(); + if (ret != NULL) + RETURN_EGL_SUCCESS(NULL, ret); + else + RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, NULL); } disp = _eglLockDisplay(dpy); diff --git a/src/egl/main/egldispatchstubs.c b/src/egl/main/egldispatchstubs.c new file mode 100644 index 00000000000..e02abd7a9e0 --- /dev/null +++ b/src/egl/main/egldispatchstubs.c @@ -0,0 +1,110 @@ +#include "egldispatchstubs.h" +#include "g_egldispatchstubs.h" + +#include <string.h> + +#include "eglcurrent.h" + +static const __EGLapiExports *exports; + +const int __EGL_DISPATCH_FUNC_COUNT = __EGL_DISPATCH_COUNT; +int __EGL_DISPATCH_FUNC_INDICES[__EGL_DISPATCH_COUNT + 1]; + +static int FindProcIndex(const char *name) +{ + unsigned first = 0; + unsigned last = __EGL_DISPATCH_COUNT - 1; + + while (first <= last) { + unsigned middle = (first + last) / 2; + int comp = strcmp(name, + __EGL_DISPATCH_FUNC_NAMES[middle]); + + if (comp > 0) + first = middle + 1; + else if (comp < 0) + last = middle - 1; + else + return middle; + } + + /* Just point to the dummy entry at the end of the respective table */ + return __EGL_DISPATCH_COUNT; +} + +void __eglInitDispatchStubs(const __EGLapiExports *exportsTable) +{ + int i; + exports = exportsTable; + for (i=0; i<__EGL_DISPATCH_FUNC_COUNT; i++) { + __EGL_DISPATCH_FUNC_INDICES[i] = -1; + } +} + +void __eglSetDispatchIndex(const char *name, int dispatchIndex) +{ + int index = FindProcIndex(name); + __EGL_DISPATCH_FUNC_INDICES[index] = dispatchIndex; +} + +void *__eglDispatchFindDispatchFunction(const char *name) +{ + int index = FindProcIndex(name); + return (void *) __EGL_DISPATCH_FUNCS[index]; +} + +static __eglMustCastToProperFunctionPointerType FetchVendorFunc(__EGLvendorInfo *vendor, + int index, EGLint errorCode) +{ + __eglMustCastToProperFunctionPointerType func = NULL; + + if (vendor != NULL) { + func = exports->fetchDispatchEntry(vendor, __EGL_DISPATCH_FUNC_INDICES[index]); + } + if (func == NULL) { + if (errorCode != EGL_SUCCESS) { + _eglError(errorCode, __EGL_DISPATCH_FUNC_NAMES[index]); + } + return NULL; + } + + if (!exports->setLastVendor(vendor)) { + // Don't bother trying to set an error code in libglvnd. If + // setLastVendor failed, then setEGLError would also fail. + _eglError(errorCode, __EGL_DISPATCH_FUNC_NAMES[index]); + return NULL; + } + + return func; +} + +__eglMustCastToProperFunctionPointerType __eglDispatchFetchByCurrent(int index) +{ + __EGLvendorInfo *vendor; + + // Note: This is only used for the eglWait* functions. For those, if + // there's no current context, then they're supposed to do nothing but + // return success. + exports->threadInit(); + vendor = exports->getCurrentVendor(); + return FetchVendorFunc(vendor, index, EGL_SUCCESS); +} + +__eglMustCastToProperFunctionPointerType __eglDispatchFetchByDisplay(EGLDisplay dpy, int index) +{ + __EGLvendorInfo *vendor; + + exports->threadInit(); + vendor = exports->getVendorFromDisplay(dpy); + return FetchVendorFunc(vendor, index, EGL_BAD_DISPLAY); +} + +__eglMustCastToProperFunctionPointerType __eglDispatchFetchByDevice(EGLDeviceEXT dev, int index) +{ + __EGLvendorInfo *vendor; + + exports->threadInit(); + vendor = exports->getVendorFromDevice(dev); + return FetchVendorFunc(vendor, index, EGL_BAD_DEVICE_EXT); +} + diff --git a/src/egl/main/egldispatchstubs.h b/src/egl/main/egldispatchstubs.h new file mode 100644 index 00000000000..7861ea5e61a --- /dev/null +++ b/src/egl/main/egldispatchstubs.h @@ -0,0 +1,26 @@ +#ifndef EGLDISPATCHSTUBS_H +#define EGLDISPATCHSTUBS_H + +#include "glvnd/libeglabi.h" + +// These variables are all generated along with the dispatch stubs. +extern const int __EGL_DISPATCH_FUNC_COUNT; +extern const char * const __EGL_DISPATCH_FUNC_NAMES[]; +extern int __EGL_DISPATCH_FUNC_INDICES[]; +extern const __eglMustCastToProperFunctionPointerType __EGL_DISPATCH_FUNCS[]; + +void __eglInitDispatchStubs(const __EGLapiExports *exportsTable); +void __eglSetDispatchIndex(const char *name, int index); + +/** + * Returns the dispatch function for the given name, or \c NULL if the function + * isn't supported. + */ +void *__eglDispatchFindDispatchFunction(const char *name); + +// Helper functions used by the generated stubs. +__eglMustCastToProperFunctionPointerType __eglDispatchFetchByDisplay(EGLDisplay dpy, int index); +__eglMustCastToProperFunctionPointerType __eglDispatchFetchByDevice(EGLDeviceEXT dpy, int index); +__eglMustCastToProperFunctionPointerType __eglDispatchFetchByCurrent(int index); + +#endif // EGLDISPATCHSTUBS_H diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c index cb41063e321..baf96bb1ec5 100644 --- a/src/egl/main/eglglobals.c +++ b/src/egl/main/eglglobals.c @@ -29,6 +29,8 @@ #include <stdlib.h> +#include <stdio.h> +#include <string.h> #include <assert.h> #include "c11/threads.h" @@ -50,9 +52,13 @@ struct _egl_global _eglGlobal = _eglFiniDisplay }, - /* ClientExtensionString */ + /* ClientOnlyExtensionString */ "EGL_EXT_client_extensions" " EGL_EXT_platform_base" + " EGL_KHR_client_get_all_proc_addresses" + " EGL_KHR_debug", + + /* PlatformExtensionString */ #ifdef HAVE_WAYLAND_PLATFORM " EGL_EXT_platform_wayland" #endif @@ -65,8 +71,9 @@ struct _egl_global _eglGlobal = #ifdef HAVE_SURFACELESS_PLATFORM " EGL_MESA_platform_surfaceless" #endif - " EGL_KHR_client_get_all_proc_addresses" - " EGL_KHR_debug", + "", + + NULL, /* ClientExtensionsString */ NULL, /* debugCallback */ _EGL_DEBUG_BIT_CRITICAL | _EGL_DEBUG_BIT_ERROR, /* debugTypesEnabled */ @@ -101,3 +108,37 @@ _eglAddAtExitCall(void (*func)(void)) mtx_unlock(_eglGlobal.Mutex); } } + +const char * +_eglGetClientExtensionString(void) +{ + const char *ret; + + mtx_lock(_eglGlobal.Mutex); + + if (_eglGlobal.ClientExtensionString == NULL) { + size_t clientLen = strlen(_eglGlobal.ClientOnlyExtensionString); + size_t platformLen = strlen(_eglGlobal.PlatformExtensionString); + + _eglGlobal.ClientExtensionString = (char *) malloc(clientLen + platformLen + 1); + if (_eglGlobal.ClientExtensionString != NULL) { + char *ptr = _eglGlobal.ClientExtensionString; + + memcpy(ptr, _eglGlobal.ClientOnlyExtensionString, clientLen); + ptr += clientLen; + + if (platformLen > 0) { + // Note that if PlatformExtensionString is not empty, then it will + // already have a leading space. + assert(_eglGlobal.PlatformExtensionString[0] == ' '); + memcpy(ptr, _eglGlobal.PlatformExtensionString, platformLen); + ptr += platformLen; + } + *ptr = '\0'; + } + } + ret = _eglGlobal.ClientExtensionString; + + mtx_unlock(_eglGlobal.Mutex); + return ret; +} diff --git a/src/egl/main/eglglobals.h b/src/egl/main/eglglobals.h index ec4f3d04a36..c6ef59d4820 100644 --- a/src/egl/main/eglglobals.h +++ b/src/egl/main/eglglobals.h @@ -57,7 +57,15 @@ struct _egl_global EGLint NumAtExitCalls; void (*AtExitCalls[10])(void); - const char *ClientExtensionString; + /* + * Under libglvnd, the client extension string has to be split into two + * strings, one for platform extensions, and one for everything else. So, + * define separate strings for them. _eglGetClientExtensionString will + * concatenate them together for a non-libglvnd build. + */ + const char *ClientOnlyExtensionString; + const char *PlatformExtensionString; + char *ClientExtensionString; EGLDEBUGPROCKHR debugCallback; unsigned int debugTypesEnabled; @@ -76,4 +84,7 @@ static inline unsigned int DebugBitFromType(EGLenum type) return (1 << (type - EGL_DEBUG_MSG_CRITICAL_KHR)); } +extern const char * +_eglGetClientExtensionString(void); + #endif /* EGLGLOBALS_INCLUDED */ diff --git a/src/egl/main/eglglvnd.c b/src/egl/main/eglglvnd.c new file mode 100644 index 00000000000..6b984ed6c28 --- /dev/null +++ b/src/egl/main/eglglvnd.c @@ -0,0 +1,82 @@ +#include <string.h> +#include <assert.h> + +#include <glvnd/libeglabi.h> + +#include "eglcurrent.h" +#include "egldispatchstubs.h" +#include "eglglobals.h" + +static const __EGLapiExports *__eglGLVNDApiExports = NULL; + +static const char * EGLAPIENTRY +__eglGLVNDQueryString(EGLDisplay dpy, EGLenum name) +{ + // For client extensions, return the list of non-platform extensions. The + // platform extensions are returned by __eglGLVNDGetVendorString. + if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) + return _eglGlobal.ClientOnlyExtensionString; + + // For everything else, forward to the normal eglQueryString function. + return eglQueryString(dpy, name); +} + +static const char * +__eglGLVNDGetVendorString(int name) +{ + if (name == __EGL_VENDOR_STRING_PLATFORM_EXTENSIONS) { + const char *str = _eglGlobal.PlatformExtensionString; + // The platform extension string may have a leading space. If it does, + // then skip over it. + while (*str == ' ') { + str++; + } + return str; + } + + return NULL; +} + +static EGLDisplay +__eglGLVNDGetPlatformDisplay(EGLenum platform, void *native_display, + const EGLAttrib *attrib_list) +{ + if (platform == EGL_NONE) { + assert(native_display == (void *) EGL_DEFAULT_DISPLAY); + assert(attrib_list == NULL); + return eglGetDisplay((EGLNativeDisplayType) native_display); + } else { + return eglGetPlatformDisplay(platform, native_display, attrib_list); + } +} + +static void * +__eglGLVNDGetProcAddress(const char *procName) +{ + if (strcmp(procName, "eglQueryString") == 0) + return (void *) __eglGLVNDQueryString; + + return (void *) eglGetProcAddress(procName); +} + +EGLAPI EGLBoolean +__egl_Main(uint32_t version, const __EGLapiExports *exports, + __EGLvendorInfo *vendor, __EGLapiImports *imports) +{ + if (EGL_VENDOR_ABI_GET_MAJOR_VERSION(version) != + EGL_VENDOR_ABI_MAJOR_VERSION) + return EGL_FALSE; + + __eglGLVNDApiExports = exports; + __eglInitDispatchStubs(exports); + + imports->getPlatformDisplay = __eglGLVNDGetPlatformDisplay; + imports->getSupportsAPI = _eglIsApiValid; + imports->getVendorString = __eglGLVNDGetVendorString; + imports->getProcAddress = __eglGLVNDGetProcAddress; + imports->getDispatchAddress = __eglDispatchFindDispatchFunction; + imports->setDispatchIndex = __eglSetDispatchIndex; + + return EGL_TRUE; +} + |