X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fmain%2Feglapi.c;h=9a59d9e0c3571f937f1311cb079f5a749a08e90d;hb=caf7fb627dae6b49830a11b85952815e0fd096db;hp=df355a50424a3b376a03d60b51bb0015d3c869b3;hpb=017946b7247ea7c36219b44dfc118ccad4da7d1d;p=mesa.git diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index df355a50424..9a59d9e0c35 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -88,8 +88,7 @@ #include #include "c99_compat.h" #include "c11/threads.h" -#include "GL/mesa_glinterop.h" -#include "eglcompiler.h" +#include "util/macros.h" #include "eglglobals.h" #include "eglcontext.h" @@ -102,6 +101,7 @@ #include "eglimage.h" #include "eglsync.h" +#include "GL/mesa_glinterop.h" /** * Macros to help return an API entrypoint. @@ -157,6 +157,12 @@ _EGL_CHECK_OBJECT(disp, Sync, s, ret, drv) +struct _egl_entrypoint { + const char *name; + _EGLProc function; +}; + + static inline _EGLDriver * _eglCheckDisplay(_EGLDisplay *disp, const char *msg) { @@ -250,6 +256,77 @@ _eglUnlockDisplay(_EGLDisplay *dpy) mtx_unlock(&dpy->Mutex); } +static EGLBoolean +_eglSetFuncName(const char *funcName, _EGLDisplay *disp, EGLenum objectType, _EGLResource *object) +{ + _EGLThreadInfo *thr = _eglGetCurrentThread(); + if (!_eglIsCurrentThreadDummy()) { + thr->CurrentFuncName = funcName; + thr->CurrentObjectLabel = NULL; + + if (objectType == EGL_OBJECT_THREAD_KHR) + thr->CurrentObjectLabel = thr->Label; + else if (objectType == EGL_OBJECT_DISPLAY_KHR && disp) + thr->CurrentObjectLabel = disp->Label; + else if (object) + thr->CurrentObjectLabel = object->Label; + + return EGL_TRUE; + } + + _eglDebugReport(EGL_BAD_ALLOC, funcName, EGL_DEBUG_MSG_CRITICAL_KHR, NULL); + return EGL_FALSE; +} + +#define _EGL_FUNC_START(disp, objectType, object, ret) \ + do { \ + if (!_eglSetFuncName(__func__, disp, objectType, (_EGLResource *) object)) { \ + if (disp) \ + _eglUnlockDisplay(disp); \ + return ret; \ + } \ + } while(0) + +/** + * Convert an attribute list from EGLint[] to EGLAttrib[]. + * + * Return an EGL error code. The output parameter out_attrib_list is modified + * only on success. + */ +static EGLint +_eglConvertIntsToAttribs(const EGLint *int_list, EGLAttrib **out_attrib_list) +{ + size_t len = 0; + EGLAttrib *attrib_list; + + if (int_list) { + while (int_list[2*len] != EGL_NONE) + ++len; + } + + if (len == 0) { + *out_attrib_list = NULL; + return EGL_SUCCESS; + } + + if (2*len + 1 > SIZE_MAX / sizeof(EGLAttrib)) + return EGL_BAD_ALLOC; + + attrib_list = malloc((2*len + 1) * sizeof(EGLAttrib)); + if (!attrib_list) + return EGL_BAD_ALLOC; + + for (size_t i = 0; i < len; ++i) { + attrib_list[2*i + 0] = int_list[2*i + 0]; + attrib_list[2*i + 1] = int_list[2*i + 1]; + } + + attrib_list[2*len] = EGL_NONE; + + *out_attrib_list = attrib_list; + return EGL_SUCCESS; +} + static EGLint * _eglConvertAttribsToInt(const EGLAttrib *attr_list) @@ -287,6 +364,8 @@ eglGetDisplay(EGLNativeDisplayType nativeDisplay) _EGLDisplay *dpy; void *native_display_ptr; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + STATIC_ASSERT(sizeof(void*) == sizeof(nativeDisplay)); native_display_ptr = (void*) nativeDisplay; @@ -297,7 +376,7 @@ eglGetDisplay(EGLNativeDisplayType nativeDisplay) static EGLDisplay _eglGetPlatformDisplayCommon(EGLenum platform, void *native_display, - const EGLint *attrib_list) + const EGLint *attrib_list) { _EGLDisplay *dpy; @@ -318,6 +397,11 @@ _eglGetPlatformDisplayCommon(EGLenum platform, void *native_display, dpy = _eglGetWaylandDisplay((struct wl_display*) native_display, attrib_list); break; +#endif +#ifdef HAVE_SURFACELESS_PLATFORM + case EGL_PLATFORM_SURFACELESS_MESA: + dpy = _eglGetSurfacelessDisplay(native_display, attrib_list); + break; #endif default: RETURN_EGL_ERROR(NULL, EGL_BAD_PARAMETER, NULL); @@ -330,6 +414,7 @@ static EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) { + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); return _eglGetPlatformDisplayCommon(platform, native_display, attrib_list); } @@ -340,6 +425,8 @@ eglGetPlatformDisplay(EGLenum platform, void *native_display, EGLDisplay display; EGLint *int_attribs; + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_NO_DISPLAY); + int_attribs = _eglConvertAttribsToInt(attrib_list); if (attrib_list && !int_attribs) RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, NULL); @@ -392,6 +479,7 @@ _eglCreateExtensionsString(_EGLDisplay *dpy) /* Please keep these sorted alphabetically. */ _EGL_CHECK_EXTENSION(ANDROID_framebuffer_target); _EGL_CHECK_EXTENSION(ANDROID_image_native_buffer); + _EGL_CHECK_EXTENSION(ANDROID_native_fence_sync); _EGL_CHECK_EXTENSION(ANDROID_recordable); _EGL_CHECK_EXTENSION(CHROMIUM_sync_control); @@ -399,10 +487,13 @@ _eglCreateExtensionsString(_EGLDisplay *dpy) _EGL_CHECK_EXTENSION(EXT_buffer_age); _EGL_CHECK_EXTENSION(EXT_create_context_robustness); _EGL_CHECK_EXTENSION(EXT_image_dma_buf_import); + _EGL_CHECK_EXTENSION(EXT_image_dma_buf_import_modifiers); _EGL_CHECK_EXTENSION(EXT_swap_buffers_with_damage); _EGL_CHECK_EXTENSION(KHR_cl_event2); + _EGL_CHECK_EXTENSION(KHR_config_attribs); _EGL_CHECK_EXTENSION(KHR_create_context); + _EGL_CHECK_EXTENSION(KHR_create_context_no_error); _EGL_CHECK_EXTENSION(KHR_fence_sync); _EGL_CHECK_EXTENSION(KHR_get_all_proc_addresses); _EGL_CHECK_EXTENSION(KHR_gl_colorspace); @@ -415,8 +506,11 @@ _eglCreateExtensionsString(_EGLDisplay *dpy) _EGL_CHECK_EXTENSION(KHR_image_base); _EGL_CHECK_EXTENSION(KHR_image_pixmap); _EGL_CHECK_EXTENSION(KHR_no_config_context); + _EGL_CHECK_EXTENSION(KHR_partial_update); _EGL_CHECK_EXTENSION(KHR_reusable_sync); _EGL_CHECK_EXTENSION(KHR_surfaceless_context); + if (dpy->Extensions.EXT_swap_buffers_with_damage) + _eglAppendExtension(&exts, "EGL_KHR_swap_buffers_with_damage"); _EGL_CHECK_EXTENSION(KHR_wait_sync); if (dpy->Extensions.KHR_no_config_context) @@ -483,6 +577,8 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -510,12 +606,17 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) */ disp->Extensions.KHR_get_all_proc_addresses = EGL_TRUE; + /* Extensions is used to provide EGL 1.3 functionality for 1.2 aware + * programs. It is driver agnostic and handled in the main EGL code. + */ + disp->Extensions.KHR_config_attribs = EGL_TRUE; + _eglComputeVersion(disp); _eglCreateExtensionsString(disp); _eglCreateAPIsString(disp); snprintf(disp->VersionString, sizeof(disp->VersionString), - "%d.%d (%s)", disp->Version / 10, disp->Version % 10, - disp->Driver->Name); + "%d.%d (%s)", disp->Version / 10, disp->Version % 10, + disp->Driver->Name); } /* Update applications version of major and minor if not NULL */ @@ -533,6 +634,8 @@ eglTerminate(EGLDisplay dpy) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(NULL, EGL_BAD_DISPLAY, EGL_FALSE); @@ -556,10 +659,15 @@ 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); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, NULL); _EGL_CHECK_DISPLAY(disp, NULL, drv); switch (name) { @@ -585,6 +693,8 @@ eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.GetConfigs(drv, disp, configs, config_size, num_config); @@ -600,9 +710,11 @@ eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); ret = drv->API.ChooseConfig(drv, disp, attrib_list, configs, - config_size, num_config); + config_size, num_config); RETURN_EGL_EVAL(disp, ret); } @@ -617,6 +729,8 @@ eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_CONFIG(disp, conf, EGL_FALSE, drv); ret = drv->API.GetConfigAttrib(drv, disp, conf, attribute, value); @@ -635,9 +749,13 @@ eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list, _EGLContext *context; EGLContext ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_CONTEXT); + _EGL_CHECK_DISPLAY(disp, EGL_NO_CONTEXT, drv); - if (!config && !disp->Extensions.KHR_no_config_context) + if (config != EGL_NO_CONFIG_KHR) + _EGL_CHECK_CONFIG(disp, conf, EGL_NO_CONTEXT, drv); + else if (!disp->Extensions.KHR_no_config_context) RETURN_EGL_ERROR(disp, EGL_BAD_CONFIG, EGL_NO_CONTEXT); if (!share && share_list != EGL_NO_CONTEXT) @@ -658,6 +776,8 @@ eglDestroyContext(EGLDisplay dpy, EGLContext ctx) _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_CONTEXT_KHR, context, EGL_FALSE); + _EGL_CHECK_CONTEXT(disp, context, EGL_FALSE, drv); _eglUnlinkContext(context); ret = drv->API.DestroyContext(drv, disp, context); @@ -677,6 +797,8 @@ eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_CONTEXT_KHR, context, EGL_FALSE); + if (!disp) RETURN_EGL_ERROR(disp, EGL_BAD_DISPLAY, EGL_FALSE); drv = disp->Driver; @@ -708,6 +830,14 @@ eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_FALSE); } + /* If a native window underlying either draw or read is no longer valid, + * an EGL_BAD_NATIVE_WINDOW error is generated. + */ + if (draw_surf && draw_surf->Lost) + RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_FALSE); + if (read_surf && read_surf->Lost) + RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_FALSE); + ret = drv->API.MakeCurrent(drv, disp, draw_surf, read_surf, context); RETURN_EGL_EVAL(disp, ret); @@ -723,6 +853,8 @@ eglQueryContext(EGLDisplay dpy, EGLContext ctx, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_CONTEXT_KHR, context, EGL_FALSE); + _EGL_CHECK_CONTEXT(disp, context, EGL_FALSE, drv); ret = drv->API.QueryContext(drv, disp, context, attribute, value); @@ -739,11 +871,33 @@ _eglCreateWindowSurfaceCommon(_EGLDisplay *disp, EGLConfig config, _EGLSurface *surf; EGLSurface ret; - _EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv); if (native_window == NULL) RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); +#ifdef HAVE_SURFACELESS_PLATFORM + if (disp && disp->Platform == _EGL_PLATFORM_SURFACELESS) { + /* From the EGL_MESA_platform_surfaceless spec (v1): + * + * eglCreatePlatformWindowSurface fails when called with a + * that belongs to the surfaceless platform. It returns + * EGL_NO_SURFACE and generates EGL_BAD_NATIVE_WINDOW. The + * justification for this unconditional failure is that the + * surfaceless platform has no native windows, and therefore the + * parameter is always invalid. + * + * This check must occur before checking the EGLConfig, which emits + * EGL_BAD_CONFIG. + */ + RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } +#endif + + _EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv); + + if ((conf->SurfaceType & EGL_WINDOW_BIT) == 0) + RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SURFACE); + surf = drv->API.CreateWindowSurface(drv, disp, conf, native_window, attrib_list); ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE; @@ -757,21 +911,18 @@ eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType window, const EGLint *attrib_list) { _EGLDisplay *disp = _eglLockDisplay(dpy); + + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_SURFACE); STATIC_ASSERT(sizeof(void*) == sizeof(window)); return _eglCreateWindowSurfaceCommon(disp, config, (void*) window, attrib_list); } - -static EGLSurface EGLAPIENTRY -eglCreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, - void *native_window, - const EGLint *attrib_list) +static void * +_fixupNativeWindow(_EGLDisplay *disp, void *native_window) { - _EGLDisplay *disp = _eglLockDisplay(dpy); - #ifdef HAVE_X11_PLATFORM - if (disp->Platform == _EGL_PLATFORM_X11 && native_window != NULL) { + if (disp && disp->Platform == _EGL_PLATFORM_X11 && native_window != NULL) { /* The `native_window` parameter for the X11 platform differs between * eglCreateWindowSurface() and eglCreatePlatformPixmapSurfaceEXT(). In * eglCreateWindowSurface(), the type of `native_window` is an Xlib @@ -779,10 +930,22 @@ eglCreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, * `Window*`. Convert `Window*` to `Window` because that's what * dri2_x11_create_window_surface() expects. */ - native_window = (void*) (* (Window*) native_window); + return (void *)(* (Window*) native_window); } #endif + return native_window; +} + +static EGLSurface EGLAPIENTRY +eglCreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, + void *native_window, + const EGLint *attrib_list) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + + native_window = _fixupNativeWindow(disp, native_window); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_SURFACE); return _eglCreateWindowSurfaceCommon(disp, config, native_window, attrib_list); } @@ -793,18 +956,39 @@ eglCreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list) { + _EGLDisplay *disp = _eglLockDisplay(dpy); EGLSurface surface; - EGLint *int_attribs = _eglConvertAttribsToInt(attrib_list); + EGLint *int_attribs; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_SURFACE); + + int_attribs = _eglConvertAttribsToInt(attrib_list); if (attrib_list && !int_attribs) - RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, EGL_NO_SURFACE); + RETURN_EGL_ERROR(disp, EGL_BAD_ALLOC, EGL_NO_SURFACE); - surface = eglCreatePlatformWindowSurfaceEXT(dpy, config, native_window, - int_attribs); + native_window = _fixupNativeWindow(disp, native_window); + surface = _eglCreateWindowSurfaceCommon(disp, config, native_window, + int_attribs); free(int_attribs); return surface; } +static void * +_fixupNativePixmap(_EGLDisplay *disp, void *native_pixmap) +{ +#ifdef HAVE_X11_PLATFORM + /* The `native_pixmap` parameter for the X11 platform differs between + * eglCreatePixmapSurface() and eglCreatePlatformPixmapSurfaceEXT(). In + * eglCreatePixmapSurface(), the type of `native_pixmap` is an Xlib + * `Pixmap`. In eglCreatePlatformPixmapSurfaceEXT(), the type is + * `Pixmap*`. Convert `Pixmap*` to `Pixmap` because that's what + * dri2_x11_create_pixmap_surface() expects. + */ + if (disp && disp->Platform == _EGL_PLATFORM_X11 && native_pixmap != NULL) + return (void *)(* (Pixmap*) native_pixmap); +#endif + return native_pixmap; +} static EGLSurface _eglCreatePixmapSurfaceCommon(_EGLDisplay *disp, EGLConfig config, @@ -815,7 +999,30 @@ _eglCreatePixmapSurfaceCommon(_EGLDisplay *disp, EGLConfig config, _EGLSurface *surf; EGLSurface ret; +#if HAVE_SURFACELESS_PLATFORM + if (disp && disp->Platform == _EGL_PLATFORM_SURFACELESS) { + /* From the EGL_MESA_platform_surfaceless spec (v1): + * + * [Like eglCreatePlatformWindowSurface,] eglCreatePlatformPixmapSurface + * also fails when called with a that belongs to the + * surfaceless platform. It returns EGL_NO_SURFACE and generates + * EGL_BAD_NATIVE_PIXMAP. + * + * This check must occur before checking the EGLConfig, which emits + * EGL_BAD_CONFIG. + */ + RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE); + } +#endif + _EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv); + + if ((conf->SurfaceType & EGL_PIXMAP_BIT) == 0) + RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SURFACE); + + if (native_pixmap == NULL) + RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE); + surf = drv->API.CreatePixmapSurface(drv, disp, conf, native_pixmap, attrib_list); ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE; @@ -829,31 +1036,22 @@ eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) { _EGLDisplay *disp = _eglLockDisplay(dpy); + + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_SURFACE); STATIC_ASSERT(sizeof(void*) == sizeof(pixmap)); return _eglCreatePixmapSurfaceCommon(disp, config, (void*) pixmap, - attrib_list); + attrib_list); } static EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, - void *native_pixmap, - const EGLint *attrib_list) + void *native_pixmap, + const EGLint *attrib_list) { _EGLDisplay *disp = _eglLockDisplay(dpy); -#ifdef HAVE_X11_PLATFORM - /* The `native_pixmap` parameter for the X11 platform differs between - * eglCreatePixmapSurface() and eglCreatePlatformPixmapSurfaceEXT(). In - * eglCreatePixmapSurface(), the type of `native_pixmap` is an Xlib - * `Pixmap`. In eglCreatePlatformPixmapSurfaceEXT(), the type is - * `Pixmap*`. Convert `Pixmap*` to `Pixmap` because that's what - * dri2_x11_create_pixmap_surface() expects. - */ - if (disp->Platform == _EGL_PLATFORM_X11 && native_pixmap != NULL) { - native_pixmap = (void*) (* (Pixmap*) native_pixmap); - } -#endif - + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_SURFACE); + native_pixmap = _fixupNativePixmap(disp, native_pixmap); return _eglCreatePixmapSurfaceCommon(disp, config, native_pixmap, attrib_list); } @@ -864,14 +1062,19 @@ eglCreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list) { + _EGLDisplay *disp = _eglLockDisplay(dpy); EGLSurface surface; - EGLint *int_attribs = _eglConvertAttribsToInt(attrib_list); + EGLint *int_attribs; + + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_SURFACE); + int_attribs = _eglConvertAttribsToInt(attrib_list); if (attrib_list && !int_attribs) - RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, EGL_NO_SURFACE); + RETURN_EGL_ERROR(disp, EGL_BAD_ALLOC, EGL_NO_SURFACE); - surface = eglCreatePlatformPixmapSurfaceEXT(dpy, config, native_pixmap, - int_attribs); + native_pixmap = _fixupNativePixmap(disp, native_pixmap); + surface = _eglCreatePixmapSurfaceCommon(disp, config, native_pixmap, + int_attribs); free(int_attribs); return surface; } @@ -887,8 +1090,12 @@ eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, _EGLSurface *surf; EGLSurface ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_SURFACE); _EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv); + if ((conf->SurfaceType & EGL_PBUFFER_BIT) == 0) + RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SURFACE); + surf = drv->API.CreatePbufferSurface(drv, disp, conf, attrib_list); ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE; @@ -904,6 +1111,7 @@ eglDestroySurface(EGLDisplay dpy, EGLSurface surface) _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); _eglUnlinkSurface(surf); ret = drv->API.DestroySurface(drv, disp, surf); @@ -920,6 +1128,7 @@ eglQuerySurface(EGLDisplay dpy, EGLSurface surface, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); ret = drv->API.QuerySurface(drv, disp, surf, attribute, value); @@ -935,6 +1144,7 @@ eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); ret = drv->API.SurfaceAttrib(drv, disp, surf, attribute, value); @@ -950,6 +1160,7 @@ eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); ret = drv->API.BindTexImage(drv, disp, surf, buffer); @@ -965,6 +1176,7 @@ eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); ret = drv->API.ReleaseTexImage(drv, disp, surf, buffer); @@ -977,21 +1189,31 @@ eglSwapInterval(EGLDisplay dpy, EGLint interval) { _EGLDisplay *disp = _eglLockDisplay(dpy); _EGLContext *ctx = _eglGetCurrentContext(); - _EGLSurface *surf; + _EGLSurface *surf = ctx ? ctx->DrawSurface : NULL; _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT || ctx->Resource.Display != disp) RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_FALSE); - surf = ctx->DrawSurface; if (_eglGetSurfaceHandle(surf) == EGL_NO_SURFACE) RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE); - ret = drv->API.SwapInterval(drv, disp, surf, interval); + interval = CLAMP(interval, + surf->Config->MinSwapInterval, + surf->Config->MaxSwapInterval); + + if (surf->SwapInterval != interval) + ret = drv->API.SwapInterval(drv, disp, surf, interval); + else + ret = EGL_TRUE; + + if (ret) + surf->SwapInterval = interval; RETURN_EGL_EVAL(disp, ret); } @@ -1006,6 +1228,7 @@ eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); /* surface must be bound to current context in EGL 1.4 */ @@ -1015,19 +1238,35 @@ eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE); #endif + /* From the EGL 1.5 spec: + * + * If eglSwapBuffers is called and the native window associated with + * surface is no longer valid, an EGL_BAD_NATIVE_WINDOW error is + * generated. + */ + if (surf->Lost) + RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_FALSE); + ret = drv->API.SwapBuffers(drv, disp, surf); + /* EGL_KHR_partial_update + * Frame boundary successfully reached, + * reset damage region and reset BufferAgeRead + */ + if (ret) { + surf->SetDamageRegionCalled = EGL_FALSE; + surf->BufferAgeRead = EGL_FALSE; + } + RETURN_EGL_EVAL(disp, ret); } -static EGLBoolean EGLAPIENTRY -eglSwapBuffersWithDamageEXT(EGLDisplay dpy, EGLSurface surface, - EGLint *rects, EGLint n_rects) +static EGLBoolean +_eglSwapBuffersWithDamageCommon(_EGLDisplay *disp, _EGLSurface *surf, + EGLint *rects, EGLint n_rects) { _EGLContext *ctx = _eglGetCurrentContext(); - _EGLDisplay *disp = _eglLockDisplay(dpy); - _EGLSurface *surf = _eglLookupSurface(surface, disp); _EGLDriver *drv; EGLBoolean ret; @@ -1043,6 +1282,99 @@ eglSwapBuffersWithDamageEXT(EGLDisplay dpy, EGLSurface surface, ret = drv->API.SwapBuffersWithDamageEXT(drv, disp, surf, rects, n_rects); + /* EGL_KHR_partial_update + * Frame boundary successfully reached, + * reset damage region and reset BufferAgeRead + */ + if (ret) { + surf->SetDamageRegionCalled = EGL_FALSE; + surf->BufferAgeRead = EGL_FALSE; + } + + RETURN_EGL_EVAL(disp, ret); +} + +static EGLBoolean EGLAPIENTRY +eglSwapBuffersWithDamageEXT(EGLDisplay dpy, EGLSurface surface, + EGLint *rects, EGLint n_rects) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSurface *surf = _eglLookupSurface(surface, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); + return _eglSwapBuffersWithDamageCommon(disp, surf, rects, n_rects); +} + +static EGLBoolean EGLAPIENTRY +eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface surface, + EGLint *rects, EGLint n_rects) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSurface *surf = _eglLookupSurface(surface, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); + return _eglSwapBuffersWithDamageCommon(disp, surf, rects, n_rects); +} + +/** + * If the width of the passed rect is greater than the surface's + * width then it is clamped to the width of the surface. Same with + * height. + */ + +static void +_eglSetDamageRegionKHRClampRects(_EGLDisplay* disp, _EGLSurface* surf, + EGLint *rects, EGLint n_rects) +{ + EGLint i; + EGLint surf_height = surf->Height; + EGLint surf_width = surf->Width; + + for (i = 0; i < (4 * n_rects); i += 4) { + EGLint x, y, rect_width, rect_height; + x = rects[i]; + y = rects[i + 1]; + rect_width = rects[i + 2]; + rect_height = rects[i + 3]; + + if (rect_width > surf_width - x) + rects[i + 2] = surf_width - x; + + if (rect_height > surf_height - y) + rects[i + 3] = surf_height - y; + } +} + +static EGLBoolean EGLAPIENTRY +eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, + EGLint *rects, EGLint n_rects) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSurface *surf = _eglLookupSurface(surface, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); + _EGLContext *ctx = _eglGetCurrentContext(); + _EGLDriver *drv; + EGLBoolean ret; + _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); + + if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT || + surf->Type != EGL_WINDOW_BIT || + ctx->DrawSurface != surf || + surf->SwapBehavior != EGL_BUFFER_DESTROYED) + RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_FALSE); + + /* If the damage region is already set or + * buffer age is not queried between + * frame boundaries, throw bad access error + */ + + if (surf->SetDamageRegionCalled || !surf->BufferAgeRead) + RETURN_EGL_ERROR(disp, EGL_BAD_ACCESS, EGL_FALSE); + + _eglSetDamageRegionKHRClampRects(disp, surf, rects, n_rects); + ret = drv->API.SetDamageRegion(drv, disp, surf, rects, n_rects); + + if (ret) + surf->SetDamageRegionCalled = EGL_TRUE; + RETURN_EGL_EVAL(disp, ret); } @@ -1055,6 +1387,7 @@ eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) EGLBoolean ret; void *native_pixmap_ptr; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); STATIC_ASSERT(sizeof(void*) == sizeof(target)); native_pixmap_ptr = (void*) target; @@ -1067,8 +1400,8 @@ eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) } -EGLBoolean EGLAPIENTRY -eglWaitClient(void) +static EGLBoolean +_eglWaitClientCommon(void) { _EGLContext *ctx = _eglGetCurrentContext(); _EGLDisplay *disp; @@ -1094,12 +1427,19 @@ eglWaitClient(void) RETURN_EGL_EVAL(disp, ret); } +EGLBoolean EGLAPIENTRY +eglWaitClient(void) +{ + _EGL_FUNC_START(NULL, EGL_OBJECT_CONTEXT_KHR, _eglGetCurrentContext(), EGL_FALSE); + return _eglWaitClientCommon(); +} EGLBoolean EGLAPIENTRY eglWaitGL(void) { /* Since we only support OpenGL and GLES, eglWaitGL is equivalent to eglWaitClient. */ - return eglWaitClient(); + _EGL_FUNC_START(NULL, EGL_OBJECT_CONTEXT_KHR, _eglGetCurrentContext(), EGL_FALSE); + return _eglWaitClientCommon(); } @@ -1114,6 +1454,8 @@ eglWaitNative(EGLint engine) if (!ctx) RETURN_EGL_SUCCESS(NULL, EGL_TRUE); + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_FALSE); + disp = ctx->Resource.Display; mtx_lock(&disp->Mutex); @@ -1163,6 +1505,8 @@ eglGetCurrentSurface(EGLint readdraw) _EGLSurface *surf; EGLSurface ret; + _EGL_FUNC_START(NULL, EGL_NONE, NULL, EGL_NO_SURFACE); + if (!ctx) RETURN_EGL_SUCCESS(NULL, EGL_NO_SURFACE); @@ -1214,8 +1558,11 @@ eglGetError(void) EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api) { - _EGLThreadInfo *t = _eglGetCurrentThread(); + _EGLThreadInfo *t; + + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_FALSE); + t = _eglGetCurrentThread(); if (_eglIsCurrentThreadDummy()) RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, EGL_FALSE); @@ -1255,6 +1602,8 @@ eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, _EGLSurface *surf; EGLSurface ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_SURFACE); + _EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv); surf = drv->API.CreatePbufferFromClientBuffer(drv, disp, buftype, buffer, @@ -1271,8 +1620,10 @@ eglReleaseThread(void) /* unbind current contexts */ if (!_eglIsCurrentThreadDummy()) { _EGLThreadInfo *t = _eglGetCurrentThread(); - _EGLContext *ctx = t->CurrentContext; + + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_FALSE); + if (ctx) { _EGLDisplay *disp = ctx->Resource.Display; _EGLDriver *drv; @@ -1290,11 +1641,10 @@ eglReleaseThread(void) } -static EGLImage EGLAPIENTRY -eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, - EGLClientBuffer buffer, const EGLint *attr_list) +static EGLImage +_eglCreateImageCommon(_EGLDisplay *disp, EGLContext ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint *attr_list) { - _EGLDisplay *disp = _eglLockDisplay(dpy); _EGLContext *context = _eglLookupContext(ctx, disp); _EGLDriver *drv; _EGLImage *img; @@ -1311,35 +1661,46 @@ eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, if (ctx != EGL_NO_CONTEXT && target == EGL_LINUX_DMA_BUF_EXT) RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); - img = drv->API.CreateImageKHR(drv, - disp, context, target, buffer, attr_list); + img = drv->API.CreateImageKHR(drv, disp, context, target, + buffer, attr_list); ret = (img) ? _eglLinkImage(img) : EGL_NO_IMAGE_KHR; RETURN_EGL_EVAL(disp, ret); } +static EGLImage EGLAPIENTRY +eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint *attr_list) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_IMAGE_KHR); + return _eglCreateImageCommon(disp, ctx, target, buffer, attr_list); +} + EGLImage EGLAPIENTRY eglCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attr_list) { + _EGLDisplay *disp = _eglLockDisplay(dpy); EGLImage image; - EGLint *int_attribs = _eglConvertAttribsToInt(attr_list); + EGLint *int_attribs; + + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_NO_IMAGE_KHR); + int_attribs = _eglConvertAttribsToInt(attr_list); if (attr_list && !int_attribs) - RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, EGL_NO_IMAGE); + RETURN_EGL_ERROR(disp, EGL_BAD_ALLOC, EGL_NO_IMAGE); - image = eglCreateImageKHR(dpy, ctx, target, buffer, int_attribs); + image = _eglCreateImageCommon(disp, ctx, target, buffer, int_attribs); free(int_attribs); return image; } -EGLBoolean EGLAPIENTRY -eglDestroyImage(EGLDisplay dpy, EGLImage image) +static EGLBoolean +_eglDestroyImageCommon(_EGLDisplay *disp, _EGLImage *img) { - _EGLDisplay *disp = _eglLockDisplay(dpy); - _EGLImage *img = _eglLookupImage(image, disp); _EGLDriver *drv; EGLBoolean ret; @@ -1355,13 +1716,30 @@ eglDestroyImage(EGLDisplay dpy, EGLImage image) RETURN_EGL_EVAL(disp, ret); } +EGLBoolean EGLAPIENTRY +eglDestroyImage(EGLDisplay dpy, EGLImage image) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLImage *img = _eglLookupImage(image, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_IMAGE_KHR, img, EGL_FALSE); + return _eglDestroyImageCommon(disp, img); +} + +static EGLBoolean EGLAPIENTRY +eglDestroyImageKHR(EGLDisplay dpy, EGLImage image) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLImage *img = _eglLookupImage(image, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_IMAGE_KHR, img, EGL_FALSE); + return _eglDestroyImageCommon(disp, img); +} + static EGLSync -_eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list, - const EGLAttrib *attrib_list64, EGLBoolean is64, +_eglCreateSync(_EGLDisplay *disp, EGLenum type, const EGLAttrib *attrib_list, + EGLBoolean orig_is_EGLAttrib, EGLenum invalid_type_error) { - _EGLDisplay *disp = _eglLockDisplay(dpy); _EGLContext *ctx = _eglGetCurrentContext(); _EGLDriver *drv; _EGLSync *sync; @@ -1369,12 +1747,30 @@ _eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list, _EGL_CHECK_DISPLAY(disp, EGL_NO_SYNC_KHR, drv); - if (!disp->Extensions.KHR_cl_event2 && is64) - RETURN_EGL_EVAL(disp, EGL_NO_SYNC_KHR); + if (!disp->Extensions.KHR_cl_event2 && orig_is_EGLAttrib) { + /* There exist two EGLAttrib variants of eglCreateSync*: + * eglCreateSync64KHR which requires EGL_KHR_cl_event2, and eglCreateSync + * which requires EGL 1.5. Here we use the presence of EGL_KHR_cl_event2 + * support as a proxy for EGL 1.5 support, even though that's not + * entirely correct (though _eglComputeVersion does the same). + * + * The EGL spec provides no guidance on how to handle unsupported + * functions. EGL_BAD_MATCH seems reasonable. + */ + RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SYNC_KHR); + } + + /* If type is EGL_SYNC_FENCE and no context is current for the bound API + * (i.e., eglGetCurrentContext returns EGL_NO_CONTEXT ), an EGL_BAD_MATCH + * error is generated. + */ + if (!ctx && + (type == EGL_SYNC_FENCE_KHR || type == EGL_SYNC_NATIVE_FENCE_ANDROID)) + RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SYNC_KHR); /* return an error if the client API doesn't support GL_OES_EGL_sync */ - if (!ctx || ctx->Resource.Display != dpy || - ctx->ClientAPI != EGL_OPENGL_ES_API) + if (ctx && (ctx->Resource.Display != disp || + ctx->ClientAPI != EGL_OPENGL_ES_API)) RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SYNC_KHR); switch (type) { @@ -1390,11 +1786,15 @@ _eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list, if (!disp->Extensions.KHR_cl_event2) RETURN_EGL_ERROR(disp, invalid_type_error, EGL_NO_SYNC_KHR); break; + case EGL_SYNC_NATIVE_FENCE_ANDROID: + if (!disp->Extensions.ANDROID_native_fence_sync) + RETURN_EGL_ERROR(disp, invalid_type_error, EGL_NO_SYNC_KHR); + break; default: RETURN_EGL_ERROR(disp, invalid_type_error, EGL_NO_SYNC_KHR); } - sync = drv->API.CreateSyncKHR(drv, disp, type, attrib_list, attrib_list64); + sync = drv->API.CreateSyncKHR(drv, disp, type, attrib_list); ret = (sync) ? _eglLinkSync(sync) : EGL_NO_SYNC_KHR; RETURN_EGL_EVAL(disp, ret); @@ -1402,17 +1802,40 @@ _eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list, static EGLSync EGLAPIENTRY -eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) +eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *int_list) { - return _eglCreateSync(dpy, type, attrib_list, NULL, EGL_FALSE, + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + + EGLSync sync; + EGLAttrib *attrib_list; + EGLint err; + + if (sizeof(int_list[0]) == sizeof(attrib_list[0])) { + attrib_list = (EGLAttrib *) int_list; + } else { + err = _eglConvertIntsToAttribs(int_list, &attrib_list); + if (err != EGL_SUCCESS) + RETURN_EGL_ERROR(disp, err, EGL_NO_SYNC); + } + + sync = _eglCreateSync(disp, type, attrib_list, EGL_FALSE, EGL_BAD_ATTRIBUTE); + + if (sizeof(int_list[0]) != sizeof(attrib_list[0])) + free(attrib_list); + + /* Don't double-unlock the display. _eglCreateSync already unlocked it. */ + return sync; } static EGLSync EGLAPIENTRY eglCreateSync64KHR(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list) { - return _eglCreateSync(dpy, type, NULL, attrib_list, EGL_TRUE, + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + return _eglCreateSync(disp, type, attrib_list, EGL_TRUE, EGL_BAD_ATTRIBUTE); } @@ -1420,22 +1843,23 @@ eglCreateSync64KHR(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list) EGLSync EGLAPIENTRY eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list) { - return _eglCreateSync(dpy, type, NULL, attrib_list, EGL_TRUE, + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + return _eglCreateSync(disp, type, attrib_list, EGL_TRUE, EGL_BAD_PARAMETER); } -EGLBoolean EGLAPIENTRY -eglDestroySync(EGLDisplay dpy, EGLSync sync) +static EGLBoolean +_eglDestroySync(_EGLDisplay *disp, _EGLSync *s) { - _EGLDisplay *disp = _eglLockDisplay(dpy); - _EGLSync *s = _eglLookupSync(sync, disp); _EGLDriver *drv; EGLBoolean ret; _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv); assert(disp->Extensions.KHR_reusable_sync || - disp->Extensions.KHR_fence_sync); + disp->Extensions.KHR_fence_sync || + disp->Extensions.ANDROID_native_fence_sync); _eglUnlinkSync(s); ret = drv->API.DestroySyncKHR(drv, disp, s); @@ -1443,18 +1867,36 @@ eglDestroySync(EGLDisplay dpy, EGLSync sync) RETURN_EGL_EVAL(disp, ret); } +EGLBoolean EGLAPIENTRY +eglDestroySync(EGLDisplay dpy, EGLSync sync) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE); + return _eglDestroySync(disp, s); +} -EGLint EGLAPIENTRY -eglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) +static EGLBoolean EGLAPIENTRY +eglDestroySyncKHR(EGLDisplay dpy, EGLSync sync) { _EGLDisplay *disp = _eglLockDisplay(dpy); _EGLSync *s = _eglLookupSync(sync, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE); + return _eglDestroySync(disp, s); +} + + +static EGLint +_eglClientWaitSyncCommon(_EGLDisplay *disp, EGLDisplay dpy, + _EGLSync *s, EGLint flags, EGLTime timeout) +{ _EGLDriver *drv; EGLint ret; _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv); assert(disp->Extensions.KHR_reusable_sync || - disp->Extensions.KHR_fence_sync); + disp->Extensions.KHR_fence_sync || + disp->Extensions.ANDROID_native_fence_sync); if (s->SyncStatus == EGL_SIGNALED_KHR) RETURN_EGL_EVAL(disp, EGL_CONDITION_SATISFIED_KHR); @@ -1479,12 +1921,30 @@ eglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) RETURN_EGL_EVAL(disp, ret); } +EGLint EGLAPIENTRY +eglClientWaitSync(EGLDisplay dpy, EGLSync sync, + EGLint flags, EGLTime timeout) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE); + return _eglClientWaitSyncCommon(disp, dpy, s, flags, timeout); +} static EGLint EGLAPIENTRY -eglWaitSyncKHR(EGLDisplay dpy, EGLSync sync, EGLint flags) +eglClientWaitSyncKHR(EGLDisplay dpy, EGLSync sync, + EGLint flags, EGLTime timeout) { _EGLDisplay *disp = _eglLockDisplay(dpy); _EGLSync *s = _eglLookupSync(sync, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE); + return _eglClientWaitSyncCommon(disp, dpy, s, flags, timeout); +} + + +static EGLint +_eglWaitSyncCommon(_EGLDisplay *disp, _EGLSync *s, EGLint flags) +{ _EGLContext *ctx = _eglGetCurrentContext(); _EGLDriver *drv; EGLint ret; @@ -1505,6 +1965,15 @@ eglWaitSyncKHR(EGLDisplay dpy, EGLSync sync, EGLint flags) RETURN_EGL_EVAL(disp, ret); } +static EGLint EGLAPIENTRY +eglWaitSyncKHR(EGLDisplay dpy, EGLSync sync, EGLint flags) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE); + return _eglWaitSyncCommon(disp, s, flags); +} + EGLBoolean EGLAPIENTRY eglWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) @@ -1513,7 +1982,10 @@ eglWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) * EGLBoolean. In both cases, the return values can only be EGL_FALSE and * EGL_TRUE. */ - return eglWaitSyncKHR(dpy, sync, flags); + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE); + return _eglWaitSyncCommon(disp, s, flags); } @@ -1525,6 +1997,8 @@ eglSignalSyncKHR(EGLDisplay dpy, EGLSync sync, EGLenum mode) _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE); + _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv); assert(disp->Extensions.KHR_reusable_sync); ret = drv->API.SignalSyncKHR(drv, disp, s, mode); @@ -1533,34 +2007,46 @@ eglSignalSyncKHR(EGLDisplay dpy, EGLSync sync, EGLenum mode) } -EGLBoolean EGLAPIENTRY -eglGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value) +static EGLBoolean +_eglGetSyncAttribCommon(_EGLDisplay *disp, _EGLSync *s, EGLint attribute, EGLAttrib *value) { - _EGLDisplay *disp = _eglLockDisplay(dpy); - _EGLSync *s = _eglLookupSync(sync, disp); _EGLDriver *drv; EGLBoolean ret; _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv); assert(disp->Extensions.KHR_reusable_sync || - disp->Extensions.KHR_fence_sync); + disp->Extensions.KHR_fence_sync || + disp->Extensions.ANDROID_native_fence_sync); ret = drv->API.GetSyncAttrib(drv, disp, s, attribute, value); RETURN_EGL_EVAL(disp, ret); } +EGLBoolean EGLAPIENTRY +eglGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); + _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE); + return _eglGetSyncAttribCommon(disp, s, attribute, value); +} + static EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLint *value) { + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); EGLAttrib attrib; EGLBoolean result; + _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE); + if (!value) - RETURN_EGL_ERROR(NULL, EGL_BAD_PARAMETER, EGL_FALSE); + RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE); attrib = *value; - result = eglGetSyncAttrib(dpy, sync, attribute, &attrib); + result = _eglGetSyncAttribCommon(disp, s, attribute, &attrib); /* The EGL_KHR_fence_sync spec says this about eglGetSyncAttribKHR: * @@ -1573,10 +2059,33 @@ eglGetSyncAttribKHR(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLint *valu return result; } +static EGLint EGLAPIENTRY +eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSync sync) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); + _EGLDriver *drv; + EGLBoolean ret; + + _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE); + + /* the spec doesn't seem to specify what happens if the fence + * type is not EGL_SYNC_NATIVE_FENCE_ANDROID, but this seems + * sensible: + */ + if (!(s && (s->Type == EGL_SYNC_NATIVE_FENCE_ANDROID))) + RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_NO_NATIVE_FENCE_FD_ANDROID); + + _EGL_CHECK_SYNC(disp, s, EGL_NO_NATIVE_FENCE_FD_ANDROID, drv); + assert(disp->Extensions.ANDROID_native_fence_sync); + ret = drv->API.DupNativeFenceFDANDROID(drv, disp, s); + + RETURN_EGL_EVAL(disp, ret); +} static EGLBoolean EGLAPIENTRY eglSwapBuffersRegionNOK(EGLDisplay dpy, EGLSurface surface, - EGLint numRects, const EGLint *rects) + EGLint numRects, const EGLint *rects) { _EGLContext *ctx = _eglGetCurrentContext(); _EGLDisplay *disp = _eglLockDisplay(dpy); @@ -1584,6 +2093,8 @@ eglSwapBuffersRegionNOK(EGLDisplay dpy, EGLSurface surface, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); + _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); if (!disp->Extensions.NOK_swap_region) @@ -1608,6 +2119,8 @@ eglCreateDRMImageMESA(EGLDisplay dpy, const EGLint *attr_list) _EGLImage *img; EGLImage ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_NO_IMAGE_KHR, drv); if (!disp->Extensions.MESA_drm_image) RETURN_EGL_EVAL(disp, EGL_NO_IMAGE_KHR); @@ -1620,13 +2133,15 @@ eglCreateDRMImageMESA(EGLDisplay dpy, const EGLint *attr_list) static EGLBoolean EGLAPIENTRY eglExportDRMImageMESA(EGLDisplay dpy, EGLImage image, - EGLint *name, EGLint *handle, EGLint *stride) + EGLint *name, EGLint *handle, EGLint *stride) { _EGLDisplay *disp = _eglLockDisplay(dpy); _EGLImage *img = _eglLookupImage(image, disp); _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_IMAGE_KHR, img, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); assert(disp->Extensions.MESA_drm_image); @@ -1648,6 +2163,8 @@ eglBindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display) _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); assert(disp->Extensions.WL_bind_wayland_display); @@ -1666,6 +2183,8 @@ eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display) _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); assert(disp->Extensions.WL_bind_wayland_display); @@ -1685,6 +2204,8 @@ eglQueryWaylandBufferWL(EGLDisplay dpy, struct wl_resource *buffer, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); assert(disp->Extensions.WL_bind_wayland_display); @@ -1705,8 +2226,11 @@ eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImage image) _EGLDriver *drv; struct wl_buffer *ret; + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, NULL, drv); - assert(disp->Extensions.WL_create_wayland_buffer_from_image); + if (!disp->Extensions.WL_create_wayland_buffer_from_image) + RETURN_EGL_EVAL(disp, NULL); img = _eglLookupImage(image, disp); @@ -1727,6 +2251,8 @@ eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); + _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); if (!disp->Extensions.NV_post_sub_buffer) @@ -1747,6 +2273,8 @@ eglGetSyncValuesCHROMIUM(EGLDisplay display, EGLSurface surface, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE); + _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); if (!disp->Extensions.CHROMIUM_sync_control) RETURN_EGL_EVAL(disp, EGL_FALSE); @@ -1769,6 +2297,8 @@ eglExportDMABUFImageQueryMESA(EGLDisplay dpy, EGLImage image, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_IMAGE_KHR, img, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); assert(disp->Extensions.MESA_image_dma_buf_export); @@ -1790,6 +2320,8 @@ eglExportDMABUFImageMESA(EGLDisplay dpy, EGLImage image, _EGLDriver *drv; EGLBoolean ret; + _EGL_FUNC_START(disp, EGL_OBJECT_IMAGE_KHR, img, EGL_FALSE); + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); assert(disp->Extensions.MESA_image_dma_buf_export); @@ -1801,102 +2333,219 @@ eglExportDMABUFImageMESA(EGLDisplay dpy, EGLImage image, RETURN_EGL_EVAL(disp, ret); } +static EGLint EGLAPIENTRY +eglLabelObjectKHR(EGLDisplay dpy, EGLenum objectType, EGLObjectKHR object, + EGLLabelKHR label) +{ + _EGLDisplay *disp = NULL; + _EGLResourceType type; + + _EGL_FUNC_START(NULL, EGL_NONE, NULL, EGL_BAD_ALLOC); + + if (objectType == EGL_OBJECT_THREAD_KHR) { + _EGLThreadInfo *t = _eglGetCurrentThread(); + + if (!_eglIsCurrentThreadDummy()) { + t->Label = label; + return EGL_SUCCESS; + } + + RETURN_EGL_ERROR(NULL, EGL_BAD_ALLOC, EGL_BAD_ALLOC); + } + + disp = _eglLockDisplay(dpy); + if (disp == NULL) + RETURN_EGL_ERROR(disp, EGL_BAD_DISPLAY, EGL_BAD_DISPLAY); + + if (objectType == EGL_OBJECT_DISPLAY_KHR) { + if (dpy != (EGLDisplay) object) + RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_BAD_PARAMETER); + + disp->Label = label; + RETURN_EGL_EVAL(disp, EGL_SUCCESS); + } + + switch (objectType) { + case EGL_OBJECT_CONTEXT_KHR: + type = _EGL_RESOURCE_CONTEXT; + break; + case EGL_OBJECT_SURFACE_KHR: + type = _EGL_RESOURCE_SURFACE; + break; + case EGL_OBJECT_IMAGE_KHR: + type = _EGL_RESOURCE_IMAGE; + break; + case EGL_OBJECT_SYNC_KHR: + type = _EGL_RESOURCE_SYNC; + break; + case EGL_OBJECT_STREAM_KHR: + default: + RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_BAD_PARAMETER); + } + + if (_eglCheckResource(object, type, disp)) { + _EGLResource *res = (_EGLResource *) object; + + res->Label = label; + RETURN_EGL_EVAL(disp, EGL_SUCCESS); + } + + RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_BAD_PARAMETER); +} + +static EGLBoolean +_validDebugMessageLevel(EGLAttrib level) +{ + return (level >= EGL_DEBUG_MSG_CRITICAL_KHR && + level <= EGL_DEBUG_MSG_INFO_KHR); +} + +static EGLint EGLAPIENTRY +eglDebugMessageControlKHR(EGLDEBUGPROCKHR callback, + const EGLAttrib *attrib_list) +{ + unsigned int newEnabled; + + _EGL_FUNC_START(NULL, EGL_NONE, NULL, EGL_BAD_ALLOC); + + mtx_lock(_eglGlobal.Mutex); + + newEnabled = _eglGlobal.debugTypesEnabled; + if (attrib_list != NULL) { + int i; + + for (i = 0; attrib_list[i] != EGL_NONE; i += 2) { + if (_validDebugMessageLevel(attrib_list[i])) { + if (attrib_list[i + 1]) + newEnabled |= DebugBitFromType(attrib_list[i]); + else + newEnabled &= ~DebugBitFromType(attrib_list[i]); + continue; + } + + // On error, set the last error code, call the current + // debug callback, and return the error code. + mtx_unlock(_eglGlobal.Mutex); + _eglReportError(EGL_BAD_ATTRIBUTE, NULL, + "Invalid attribute 0x%04lx", (unsigned long) attrib_list[i]); + return EGL_BAD_ATTRIBUTE; + } + } + + if (callback != NULL) { + _eglGlobal.debugCallback = callback; + _eglGlobal.debugTypesEnabled = newEnabled; + } else { + _eglGlobal.debugCallback = NULL; + _eglGlobal.debugTypesEnabled = _EGL_DEBUG_BIT_CRITICAL | _EGL_DEBUG_BIT_ERROR; + } + + mtx_unlock(_eglGlobal.Mutex); + return EGL_SUCCESS; +} + +static EGLBoolean EGLAPIENTRY +eglQueryDebugKHR(EGLint attribute, EGLAttrib *value) +{ + _EGL_FUNC_START(NULL, EGL_NONE, NULL, EGL_BAD_ALLOC); + + mtx_lock(_eglGlobal.Mutex); + + do { + if (_validDebugMessageLevel(attribute)) { + if (_eglGlobal.debugTypesEnabled & DebugBitFromType(attribute)) + *value = EGL_TRUE; + else + *value = EGL_FALSE; + break; + } + + if (attribute == EGL_DEBUG_CALLBACK_KHR) { + *value = (EGLAttrib) _eglGlobal.debugCallback; + break; + } + + mtx_unlock(_eglGlobal.Mutex); + _eglReportError(EGL_BAD_ATTRIBUTE, NULL, + "Invalid attribute 0x%04lx", (unsigned long) attribute); + return EGL_FALSE; + } while (0); + + mtx_unlock(_eglGlobal.Mutex); + return EGL_TRUE; +} + +static int +_eglFunctionCompare(const void *key, const void *elem) +{ + const char *procname = key; + const struct _egl_entrypoint *entrypoint = elem; + return strcmp(procname, entrypoint->name); +} + +static EGLBoolean EGLAPIENTRY +eglQueryDmaBufFormatsEXT(EGLDisplay dpy, EGLint max_formats, + EGLint *formats, EGLint *num_formats) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLDriver *drv; + EGLBoolean ret; + + _EGL_FUNC_START(NULL, EGL_NONE, NULL, EGL_FALSE); + + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); + + ret = drv->API.QueryDmaBufFormatsEXT(drv, disp, max_formats, formats, + num_formats); + + RETURN_EGL_EVAL(disp, ret); +} + +static EGLBoolean EGLAPIENTRY +eglQueryDmaBufModifiersEXT(EGLDisplay dpy, EGLint format, EGLint max_modifiers, + EGLuint64KHR *modifiers, EGLBoolean *external_only, + EGLint *num_modifiers) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLDriver *drv; + EGLBoolean ret; + + _EGL_FUNC_START(NULL, EGL_NONE, NULL, EGL_FALSE); + + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); + + ret = drv->API.QueryDmaBufModifiersEXT(drv, disp, format, max_modifiers, + modifiers, external_only, + num_modifiers); + + RETURN_EGL_EVAL(disp, ret); +} + __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const char *procname) { - static const struct { - const char *name; - _EGLProc function; - } egl_functions[] = { - /* core functions queryable in the presence of - * EGL_KHR_get_all_proc_addresses or EGL 1.5 - */ - /* alphabetical order */ - { "eglBindAPI", (_EGLProc) eglBindAPI }, - { "eglBindTexImage", (_EGLProc) eglBindTexImage }, - { "eglChooseConfig", (_EGLProc) eglChooseConfig }, - { "eglCopyBuffers", (_EGLProc) eglCopyBuffers }, - { "eglCreateContext", (_EGLProc) eglCreateContext }, - { "eglCreatePbufferFromClientBuffer", (_EGLProc) eglCreatePbufferFromClientBuffer }, - { "eglCreatePbufferSurface", (_EGLProc) eglCreatePbufferSurface }, - { "eglCreatePixmapSurface", (_EGLProc) eglCreatePixmapSurface }, - { "eglCreateWindowSurface", (_EGLProc) eglCreateWindowSurface }, - { "eglDestroyContext", (_EGLProc) eglDestroyContext }, - { "eglDestroySurface", (_EGLProc) eglDestroySurface }, - { "eglGetConfigAttrib", (_EGLProc) eglGetConfigAttrib }, - { "eglGetConfigs", (_EGLProc) eglGetConfigs }, - { "eglGetCurrentContext", (_EGLProc) eglGetCurrentContext }, - { "eglGetCurrentDisplay", (_EGLProc) eglGetCurrentDisplay }, - { "eglGetCurrentSurface", (_EGLProc) eglGetCurrentSurface }, - { "eglGetDisplay", (_EGLProc) eglGetDisplay }, - { "eglGetError", (_EGLProc) eglGetError }, - { "eglGetProcAddress", (_EGLProc) eglGetProcAddress }, - { "eglInitialize", (_EGLProc) eglInitialize }, - { "eglMakeCurrent", (_EGLProc) eglMakeCurrent }, - { "eglQueryAPI", (_EGLProc) eglQueryAPI }, - { "eglQueryContext", (_EGLProc) eglQueryContext }, - { "eglQueryString", (_EGLProc) eglQueryString }, - { "eglQuerySurface", (_EGLProc) eglQuerySurface }, - { "eglReleaseTexImage", (_EGLProc) eglReleaseTexImage }, - { "eglReleaseThread", (_EGLProc) eglReleaseThread }, - { "eglSurfaceAttrib", (_EGLProc) eglSurfaceAttrib }, - { "eglSwapBuffers", (_EGLProc) eglSwapBuffers }, - { "eglSwapInterval", (_EGLProc) eglSwapInterval }, - { "eglTerminate", (_EGLProc) eglTerminate }, - { "eglWaitClient", (_EGLProc) eglWaitClient }, - { "eglWaitGL", (_EGLProc) eglWaitGL }, - { "eglWaitNative", (_EGLProc) eglWaitNative }, - { "eglCreateSync", (_EGLProc) eglCreateSync }, - { "eglDestroySync", (_EGLProc) eglDestroySync }, - { "eglClientWaitSync", (_EGLProc) eglClientWaitSync }, - { "eglGetSyncAttrib", (_EGLProc) eglGetSyncAttrib }, - { "eglWaitSync", (_EGLProc) eglWaitSync }, - { "eglCreateImage", (_EGLProc) eglCreateImage }, - { "eglDestroyImage", (_EGLProc) eglDestroyImage }, - { "eglGetPlatformDisplay", (_EGLProc) eglGetPlatformDisplay }, - { "eglCreatePlatformWindowSurface", (_EGLProc) eglCreatePlatformWindowSurface }, - { "eglCreatePlatformPixmapSurface", (_EGLProc) eglCreatePlatformPixmapSurface }, - { "eglCreateImageKHR", (_EGLProc) eglCreateImageKHR }, - { "eglDestroyImageKHR", (_EGLProc) eglDestroyImage }, - { "eglCreateSyncKHR", (_EGLProc) eglCreateSyncKHR }, - { "eglCreateSync64KHR", (_EGLProc) eglCreateSync64KHR }, - { "eglDestroySyncKHR", (_EGLProc) eglDestroySync }, - { "eglClientWaitSyncKHR", (_EGLProc) eglClientWaitSync }, - { "eglWaitSyncKHR", (_EGLProc) eglWaitSyncKHR }, - { "eglSignalSyncKHR", (_EGLProc) eglSignalSyncKHR }, - { "eglGetSyncAttribKHR", (_EGLProc) eglGetSyncAttribKHR }, - { "eglSwapBuffersRegionNOK", (_EGLProc) eglSwapBuffersRegionNOK }, - { "eglCreateDRMImageMESA", (_EGLProc) eglCreateDRMImageMESA }, - { "eglExportDRMImageMESA", (_EGLProc) eglExportDRMImageMESA }, - { "eglBindWaylandDisplayWL", (_EGLProc) eglBindWaylandDisplayWL }, - { "eglUnbindWaylandDisplayWL", (_EGLProc) eglUnbindWaylandDisplayWL }, - { "eglQueryWaylandBufferWL", (_EGLProc) eglQueryWaylandBufferWL }, - { "eglCreateWaylandBufferFromImageWL", (_EGLProc) eglCreateWaylandBufferFromImageWL }, - { "eglPostSubBufferNV", (_EGLProc) eglPostSubBufferNV }, - { "eglSwapBuffersWithDamageEXT", (_EGLProc) eglSwapBuffersWithDamageEXT }, - { "eglGetPlatformDisplayEXT", (_EGLProc) eglGetPlatformDisplayEXT }, - { "eglCreatePlatformWindowSurfaceEXT", (_EGLProc) eglCreatePlatformWindowSurfaceEXT }, - { "eglCreatePlatformPixmapSurfaceEXT", (_EGLProc) eglCreatePlatformPixmapSurfaceEXT }, - { "eglGetSyncValuesCHROMIUM", (_EGLProc) eglGetSyncValuesCHROMIUM }, - { "eglExportDMABUFImageQueryMESA", (_EGLProc) eglExportDMABUFImageQueryMESA }, - { "eglExportDMABUFImageMESA", (_EGLProc) eglExportDMABUFImageMESA }, - { NULL, NULL } + static const struct _egl_entrypoint egl_functions[] = { +#define EGL_ENTRYPOINT(f) { .name = #f, .function = (_EGLProc) f }, +#include "eglentrypoint.h" +#undef EGL_ENTRYPOINT }; - EGLint i; - _EGLProc ret; + _EGLProc ret = NULL; if (!procname) RETURN_EGL_SUCCESS(NULL, NULL); - ret = NULL; + _EGL_FUNC_START(NULL, EGL_NONE, NULL, NULL); + if (strncmp(procname, "egl", 3) == 0) { - for (i = 0; egl_functions[i].name; i++) { - if (strcmp(egl_functions[i].name, procname) == 0) { - ret = egl_functions[i].function; - break; - } - } + const struct _egl_entrypoint *entrypoint = + bsearch(procname, + egl_functions, ARRAY_SIZE(egl_functions), + sizeof(egl_functions[0]), + _eglFunctionCompare); + if (entrypoint) + ret = entrypoint->function; } + if (!ret) ret = _eglGetDriverProc(procname); @@ -1929,7 +2578,7 @@ _eglLockDisplayInterop(EGLDisplay dpy, EGLContext context, return MESA_GLINTEROP_SUCCESS; } -int +PUBLIC int MesaGLInteropEGLQueryDeviceInfo(EGLDisplay dpy, EGLContext context, struct mesa_glinterop_device_info *out) { @@ -1951,7 +2600,7 @@ MesaGLInteropEGLQueryDeviceInfo(EGLDisplay dpy, EGLContext context, return ret; } -int +PUBLIC int MesaGLInteropEGLExportObject(EGLDisplay dpy, EGLContext context, struct mesa_glinterop_export_in *in, struct mesa_glinterop_export_out *out)