// // Copyright(c) 2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // entry_points_egl.cpp : Implements the EGL entry points. #include "libGLESv2/entry_points_egl.h" #include "common/debug.h" #include "common/utilities.h" #include "common/version.h" #include "libANGLE/Context.h" #include "libANGLE/Display.h" #include "libANGLE/EGLSync.h" #include "libANGLE/Surface.h" #include "libANGLE/Texture.h" #include "libANGLE/Thread.h" #include "libANGLE/queryutils.h" #include "libANGLE/validationEGL.h" #include "libGLESv2/global_state.h" #include "libGLESv2/proc_table_egl.h" using namespace egl; namespace { bool CompareProc(const ProcEntry &a, const char *b) { return strcmp(a.first, b) < 0; } void ClipConfigs(const std::vector &filteredConfigs, EGLConfig *output_configs, EGLint config_size, EGLint *num_config) { EGLint result_size = static_cast(filteredConfigs.size()); if (output_configs) { result_size = std::max(std::min(result_size, config_size), 0); for (EGLint i = 0; i < result_size; i++) { output_configs[i] = const_cast(filteredConfigs[i]); } } *num_config = result_size; } } // anonymous namespace extern "C" { // EGL 1.0 EGLint EGLAPIENTRY EGL_GetError(void) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("()"); Thread *thread = egl::GetCurrentThread(); EGLint error = thread->getError(); thread->setSuccess(); return error; } EGLDisplay EGLAPIENTRY EGL_GetDisplay(EGLNativeDisplayType display_id) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLNativeDisplayType display_id = 0x%016" PRIxPTR ")", (uintptr_t)display_id); return egl::Display::GetDisplayFromNativeDisplay(display_id, AttributeMap()); } EGLBoolean EGLAPIENTRY EGL_Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLint *major = 0x%016" PRIxPTR ", EGLint *minor = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)major, (uintptr_t)minor); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); ANGLE_EGL_TRY_RETURN(thread, ValidateInitialize(display), "eglInitialize", GetDisplayIfValid(display), EGL_FALSE); ANGLE_EGL_TRY_RETURN(thread, display->initialize(), "eglInitialize", GetDisplayIfValid(display), EGL_FALSE); if (major) *major = 1; if (minor) *minor = 4; thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_Terminate(EGLDisplay dpy) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ")", (uintptr_t)dpy); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); ANGLE_EGL_TRY_RETURN(thread, ValidateTerminate(display), "eglTerminate", GetDisplayIfValid(display), EGL_FALSE); ANGLE_EGL_TRY_RETURN(thread, display->makeCurrent(thread, nullptr, nullptr, nullptr), "eglTerminate", GetDisplayIfValid(display), EGL_FALSE); SetContextCurrent(thread, nullptr); ANGLE_EGL_TRY_RETURN(thread, display->terminate(thread), "eglTerminate", GetDisplayIfValid(display), EGL_FALSE); thread->setSuccess(); return EGL_TRUE; } const char *EGLAPIENTRY EGL_QueryString(EGLDisplay dpy, EGLint name) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLint name = %d)", (uintptr_t)dpy, name); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); if (!(display == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)) { ANGLE_EGL_TRY_RETURN(thread, ValidateDisplay(display), "eglQueryString", GetDisplayIfValid(display), nullptr); } const char *result; switch (name) { case EGL_CLIENT_APIS: result = "OpenGL_ES"; break; case EGL_EXTENSIONS: if (display == EGL_NO_DISPLAY) { result = egl::Display::GetClientExtensionString().c_str(); } else { result = display->getExtensionString().c_str(); } break; case EGL_VENDOR: result = display->getVendorString().c_str(); break; case EGL_VERSION: result = "1.4 (ANGLE " ANGLE_VERSION_STRING ")"; break; default: thread->setError(EglBadParameter(), GetDebug(), "eglQueryString", GetDisplayIfValid(display)); return nullptr; } thread->setSuccess(); return result; } EGLBoolean EGLAPIENTRY EGL_GetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLConfig *configs = 0x%016" PRIxPTR ", " "EGLint config_size = %d, EGLint *num_config = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)configs, config_size, (uintptr_t)num_config); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); ANGLE_EGL_TRY_RETURN(thread, ValidateGetConfigs(display, config_size, num_config), "eglGetConfigs", GetDisplayIfValid(display), EGL_FALSE); ClipConfigs(display->getConfigs(AttributeMap()), configs, config_size, num_config); thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_ChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", const EGLint *attrib_list = 0x%016" PRIxPTR ", " "EGLConfig *configs = 0x%016" PRIxPTR ", EGLint config_size = %d, EGLint *num_config = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)attrib_list, (uintptr_t)configs, config_size, (uintptr_t)num_config); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); AttributeMap attribMap = AttributeMap::CreateFromIntArray(attrib_list); ANGLE_EGL_TRY_RETURN(thread, ValidateChooseConfig(display, attribMap, config_size, num_config), "eglChooseConfig", GetDisplayIfValid(display), EGL_FALSE); ClipConfigs(display->chooseConfig(attribMap), configs, config_size, num_config); thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLConfig config = 0x%016" PRIxPTR ", EGLint attribute = %d, EGLint " "*value = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)config, attribute, (uintptr_t)value); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Config *configuration = static_cast(config); ANGLE_EGL_TRY_RETURN(thread, ValidateGetConfigAttrib(display, configuration, attribute), "eglGetConfigAttrib", GetDisplayIfValid(display), EGL_FALSE); QueryConfigAttrib(configuration, attribute, value); thread->setSuccess(); return EGL_TRUE; } EGLSurface EGLAPIENTRY EGL_CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLConfig config = 0x%016" PRIxPTR ", EGLNativeWindowType win = 0x%016" PRIxPTR ", " "const EGLint *attrib_list = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)config, (uintptr_t)win, (uintptr_t)attrib_list); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Config *configuration = static_cast(config); AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list); ANGLE_EGL_TRY_RETURN(thread, ValidateCreateWindowSurface(display, configuration, win, attributes), "eglCreateWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE); egl::Surface *surface = nullptr; ANGLE_EGL_TRY_RETURN(thread, display->createWindowSurface(configuration, win, attributes, &surface), "eglCreateWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE); return static_cast(surface); } EGLSurface EGLAPIENTRY EGL_CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLConfig config = 0x%016" PRIxPTR ", const EGLint *attrib_list = " "0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)config, (uintptr_t)attrib_list); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Config *configuration = static_cast(config); AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list); ANGLE_EGL_TRY_RETURN(thread, ValidateCreatePbufferSurface(display, configuration, attributes), "eglCreatePbufferSurface", GetDisplayIfValid(display), EGL_NO_SURFACE); egl::Surface *surface = nullptr; ANGLE_EGL_TRY_RETURN(thread, display->createPbufferSurface(configuration, attributes, &surface), "eglCreatePbufferSurface", GetDisplayIfValid(display), EGL_NO_SURFACE); return static_cast(surface); } EGLSurface EGLAPIENTRY EGL_CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLConfig config = 0x%016" PRIxPTR ", EGLNativePixmapType pixmap = " "0x%016" PRIxPTR ", " "const EGLint *attrib_list = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)config, (uintptr_t)pixmap, (uintptr_t)attrib_list); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Config *configuration = static_cast(config); ANGLE_EGL_TRY_RETURN(thread, ValidateConfig(display, configuration), "eglCreatePixmapSurface", GetDisplayIfValid(display), EGL_NO_SURFACE); UNIMPLEMENTED(); // FIXME thread->setSuccess(); return EGL_NO_SURFACE; } EGLBoolean EGLAPIENTRY EGL_DestroySurface(EGLDisplay dpy, EGLSurface surface) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSurface surface = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)surface); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Surface *eglSurface = static_cast(surface); ANGLE_EGL_TRY_RETURN(thread, ValidateDestroySurface(display, eglSurface, surface), "eglDestroySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); ANGLE_EGL_TRY_RETURN(thread, display->destroySurface(eglSurface), "eglDestroySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_QuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSurface surface = 0x%016" PRIxPTR ", EGLint attribute = %d, EGLint " "*value = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)surface, attribute, (uintptr_t)value); Thread *thread = egl::GetCurrentThread(); const egl::Display *display = static_cast(dpy); const Surface *eglSurface = static_cast(surface); ANGLE_EGL_TRY_RETURN(thread, ValidateQuerySurface(display, eglSurface, attribute, value), "eglQuerySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); QuerySurfaceAttrib(eglSurface, attribute, value); thread->setSuccess(); return EGL_TRUE; } EGLContext EGLAPIENTRY EGL_CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLConfig config = 0x%016" PRIxPTR ", EGLContext share_context = " "0x%016" PRIxPTR ", " "const EGLint *attrib_list = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)config, (uintptr_t)share_context, (uintptr_t)attrib_list); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Config *configuration = static_cast(config); gl::Context *sharedGLContext = static_cast(share_context); AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list); ANGLE_EGL_TRY_RETURN(thread, ValidateCreateContext(display, configuration, sharedGLContext, attributes), "eglCreateContext", GetDisplayIfValid(display), EGL_NO_CONTEXT); gl::Context *context = nullptr; ANGLE_EGL_TRY_RETURN(thread, display->createContext(configuration, sharedGLContext, thread->getAPI(), attributes, &context), "eglCreateContext", GetDisplayIfValid(display), EGL_NO_CONTEXT); thread->setSuccess(); return static_cast(context); } EGLBoolean EGLAPIENTRY EGL_DestroyContext(EGLDisplay dpy, EGLContext ctx) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLContext ctx = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)ctx); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); gl::Context *context = static_cast(ctx); ANGLE_EGL_TRY_RETURN(thread, ValidateDestroyContext(display, context, ctx), "eglDestroyContext", GetContextIfValid(display, context), EGL_FALSE); bool contextWasCurrent = context == thread->getContext(); ANGLE_EGL_TRY_RETURN(thread, display->destroyContext(thread, context), "eglDestroyContext", GetContextIfValid(display, context), EGL_FALSE); if (contextWasCurrent) { SetContextCurrent(thread, nullptr); } thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSurface draw = 0x%016" PRIxPTR ", EGLSurface read = 0x%016" PRIxPTR ", " "EGLContext ctx = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)draw, (uintptr_t)read, (uintptr_t)ctx); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Surface *drawSurface = static_cast(draw); Surface *readSurface = static_cast(read); gl::Context *context = static_cast(ctx); ANGLE_EGL_TRY_RETURN(thread, ValidateMakeCurrent(display, drawSurface, readSurface, context), "eglMakeCurrent", GetContextIfValid(display, context), EGL_FALSE); Surface *previousDraw = thread->getCurrentDrawSurface(); Surface *previousRead = thread->getCurrentReadSurface(); gl::Context *previousContext = thread->getContext(); // Only call makeCurrent if the context or surfaces have changed. if (previousDraw != drawSurface || previousRead != readSurface || previousContext != context) { ANGLE_EGL_TRY_RETURN(thread, display->makeCurrent(thread, drawSurface, readSurface, context), "eglMakeCurrent", GetContextIfValid(display, context), EGL_FALSE); SetContextCurrent(thread, context); } thread->setSuccess(); return EGL_TRUE; } EGLSurface EGLAPIENTRY EGL_GetCurrentSurface(EGLint readdraw) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLint readdraw = %d)", readdraw); Thread *thread = egl::GetCurrentThread(); if (readdraw == EGL_READ) { thread->setSuccess(); return thread->getCurrentReadSurface(); } else if (readdraw == EGL_DRAW) { thread->setSuccess(); return thread->getCurrentDrawSurface(); } else { thread->setError(EglBadParameter(), GetDebug(), "eglGetCurrentSurface", nullptr); return EGL_NO_SURFACE; } } EGLDisplay EGLAPIENTRY EGL_GetCurrentDisplay(void) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("()"); Thread *thread = egl::GetCurrentThread(); thread->setSuccess(); if (thread->getContext() != nullptr) { return thread->getContext()->getDisplay(); } return EGL_NO_DISPLAY; } EGLBoolean EGLAPIENTRY EGL_QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLContext ctx = 0x%016" PRIxPTR ", EGLint attribute = %d, EGLint *value " "= 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)ctx, attribute, (uintptr_t)value); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); gl::Context *context = static_cast(ctx); ANGLE_EGL_TRY_RETURN(thread, ValidateQueryContext(display, context, attribute, value), "eglQueryContext", GetContextIfValid(display, context), EGL_FALSE); QueryContextAttrib(context, attribute, value); thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_WaitGL(void) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("()"); Thread *thread = egl::GetCurrentThread(); egl::Display *display = thread->getDisplay(); ANGLE_EGL_TRY_RETURN(thread, ValidateDisplay(display), "eglWaitGL", GetDisplayIfValid(display), EGL_FALSE); // eglWaitGL like calling eglWaitClient with the OpenGL ES API bound. Since we only implement // OpenGL ES we can do the call directly. ANGLE_EGL_TRY_RETURN(thread, display->waitClient(thread->getContext()), "eglWaitGL", GetDisplayIfValid(display), EGL_FALSE); thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_WaitNative(EGLint engine) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLint engine = %d)", engine); Thread *thread = egl::GetCurrentThread(); egl::Display *display = thread->getDisplay(); ANGLE_EGL_TRY_RETURN(thread, ValidateWaitNative(display, engine), "eglWaitNative", GetThreadIfValid(thread), EGL_FALSE); ANGLE_EGL_TRY_RETURN(thread, display->waitNative(thread->getContext(), engine), "eglWaitNative", GetThreadIfValid(thread), EGL_FALSE); thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_SwapBuffers(EGLDisplay dpy, EGLSurface surface) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSurface surface = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)surface); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Surface *eglSurface = (Surface *)surface; ANGLE_EGL_TRY_RETURN(thread, ValidateSwapBuffers(thread, display, eglSurface), "eglSwapBuffers", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); ANGLE_EGL_TRY_RETURN(thread, eglSurface->swap(thread->getContext()), "eglSwapBuffers", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSurface surface = 0x%016" PRIxPTR ", EGLNativePixmapType target = " "0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)surface, (uintptr_t)target); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Surface *eglSurface = static_cast(surface); ANGLE_EGL_TRY_RETURN(thread, ValidateCopyBuffers(display, eglSurface), "eglCopyBuffers", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); UNIMPLEMENTED(); // FIXME thread->setSuccess(); return 0; } // EGL 1.1 EGLBoolean EGLAPIENTRY EGL_BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSurface surface = 0x%016" PRIxPTR ", EGLint buffer = %d)", (uintptr_t)dpy, (uintptr_t)surface, buffer); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Surface *eglSurface = static_cast(surface); gl::Context *context = thread->getContext(); gl::Texture *textureObject = nullptr; ANGLE_EGL_TRY_RETURN( thread, ValidateBindTexImage(display, eglSurface, surface, buffer, context, &textureObject), "eglBindTexImage", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); if (context) { ANGLE_EGL_TRY_RETURN(thread, eglSurface->bindTexImage(context, textureObject, buffer), "eglBindTexImage", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); } thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSurface surface = 0x%016" PRIxPTR ", EGLint attribute = %d, EGLint " "value = %d)", (uintptr_t)dpy, (uintptr_t)surface, attribute, value); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Surface *eglSurface = static_cast(surface); ANGLE_EGL_TRY_RETURN(thread, ValidateSurfaceAttrib(display, eglSurface, attribute, value), "eglSurfaceAttrib", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); SetSurfaceAttrib(eglSurface, attribute, value); thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSurface surface = 0x%016" PRIxPTR ", EGLint buffer = %d)", (uintptr_t)dpy, (uintptr_t)surface, buffer); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Surface *eglSurface = static_cast(surface); ANGLE_EGL_TRY_RETURN(thread, ValidateReleaseTexImage(display, eglSurface, surface, buffer), "eglReleaseTexImage", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); gl::Texture *texture = eglSurface->getBoundTexture(); if (texture) { ANGLE_EGL_TRY_RETURN(thread, eglSurface->releaseTexImage(thread->getContext(), buffer), "eglReleaseTexImage", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); } thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_SwapInterval(EGLDisplay dpy, EGLint interval) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLint interval = %d)", (uintptr_t)dpy, interval); Thread *thread = egl::GetCurrentThread(); gl::Context *context = thread->getContext(); egl::Display *display = static_cast(dpy); Surface *draw_surface = static_cast(thread->getCurrentDrawSurface()); ANGLE_EGL_TRY_RETURN(thread, ValidateSwapInterval(display, draw_surface, context), "eglSwapInterval", GetDisplayIfValid(display), EGL_FALSE); const egl::Config *surfaceConfig = draw_surface->getConfig(); EGLint clampedInterval = std::min(std::max(interval, surfaceConfig->minSwapInterval), surfaceConfig->maxSwapInterval); draw_surface->setSwapInterval(clampedInterval); thread->setSuccess(); return EGL_TRUE; } // EGL 1.2 EGLBoolean EGLAPIENTRY EGL_BindAPI(EGLenum api) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLenum api = 0x%X)", api); Thread *thread = egl::GetCurrentThread(); ANGLE_EGL_TRY_RETURN(thread, ValidateBindAPI(api), "eglBindAPI", GetThreadIfValid(thread), EGL_FALSE); thread->setAPI(api); thread->setSuccess(); return EGL_TRUE; } EGLenum EGLAPIENTRY EGL_QueryAPI(void) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("()"); Thread *thread = egl::GetCurrentThread(); EGLenum API = thread->getAPI(); thread->setSuccess(); return API; } EGLSurface EGLAPIENTRY EGL_CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%016" PRIxPTR ", " "EGLConfig config = 0x%016" PRIxPTR ", const EGLint *attrib_list = 0x%016" PRIxPTR ")", (uintptr_t)dpy, buftype, (uintptr_t)buffer, (uintptr_t)config, (uintptr_t)attrib_list); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Config *configuration = static_cast(config); AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list); ANGLE_EGL_TRY_RETURN( thread, ValidateCreatePbufferFromClientBuffer(display, buftype, buffer, configuration, attributes), "eglCreatePbufferFromClientBuffer", GetDisplayIfValid(display), EGL_NO_SURFACE); egl::Surface *surface = nullptr; ANGLE_EGL_TRY_RETURN(thread, display->createPbufferFromClientBuffer(configuration, buftype, buffer, attributes, &surface), "eglCreatePbufferFromClientBuffer", GetDisplayIfValid(display), EGL_NO_SURFACE); return static_cast(surface); } EGLBoolean EGLAPIENTRY EGL_ReleaseThread(void) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("()"); Thread *thread = egl::GetCurrentThread(); Surface *previousDraw = thread->getCurrentDrawSurface(); Surface *previousRead = thread->getCurrentReadSurface(); gl::Context *previousContext = thread->getContext(); egl::Display *previousDisplay = thread->getDisplay(); // Only call makeCurrent if the context or surfaces have changed. if (previousDraw != EGL_NO_SURFACE || previousRead != EGL_NO_SURFACE || previousContext != EGL_NO_CONTEXT) { if (previousDisplay != EGL_NO_DISPLAY) { ANGLE_EGL_TRY_RETURN(thread, previousDisplay->makeCurrent(thread, nullptr, nullptr, nullptr), "eglReleaseThread", nullptr, EGL_FALSE); } SetContextCurrent(thread, nullptr); } thread->setSuccess(); return EGL_TRUE; } EGLBoolean EGLAPIENTRY EGL_WaitClient(void) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("()"); Thread *thread = egl::GetCurrentThread(); egl::Display *display = thread->getDisplay(); gl::Context *context = thread->getContext(); ANGLE_EGL_TRY_RETURN(thread, ValidateDisplay(display), "eglWaitClient", GetContextIfValid(display, context), EGL_FALSE); ANGLE_EGL_TRY_RETURN(thread, display->waitClient(context), "eglWaitClient", GetContextIfValid(display, context), EGL_FALSE); thread->setSuccess(); return EGL_TRUE; } // EGL 1.4 EGLContext EGLAPIENTRY EGL_GetCurrentContext(void) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("()"); Thread *thread = egl::GetCurrentThread(); gl::Context *context = thread->getContext(); thread->setSuccess(); return static_cast(context); } // EGL 1.5 EGLSync EGLAPIENTRY EGL_CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLenum type = 0x%X, const EGLint* attrib_list = 0x%016" PRIxPTR ")", (uintptr_t)dpy, type, (uintptr_t)attrib_list); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); AttributeMap attributes = AttributeMap::CreateFromAttribArray(attrib_list); gl::Context *currentContext = thread->getContext(); egl::Display *currentDisplay = currentContext ? currentContext->getDisplay() : nullptr; ANGLE_EGL_TRY_RETURN( thread, ValidateCreateSyncKHR(display, type, attributes, currentDisplay, currentContext), "eglCreateSync", GetDisplayIfValid(display), EGL_NO_SYNC); egl::Sync *syncObject = nullptr; ANGLE_EGL_TRY_RETURN(thread, display->createSync(currentContext, type, attributes, &syncObject), "eglCreateSync", GetDisplayIfValid(display), EGL_NO_SYNC); thread->setSuccess(); return static_cast(syncObject); } EGLBoolean EGLAPIENTRY EGL_DestroySync(EGLDisplay dpy, EGLSync sync) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSync sync = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)sync); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); egl::Sync *syncObject = static_cast(sync); ANGLE_EGL_TRY_RETURN(thread, ValidateDestroySync(display, syncObject), "eglDestroySync", GetDisplayIfValid(display), EGL_FALSE); display->destroySync(syncObject); thread->setSuccess(); return EGL_TRUE; } EGLint EGLAPIENTRY EGL_ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSync sync = 0x%016" PRIxPTR ", EGLint flags = 0x%X, EGLTime timeout = " "%llu)", (uintptr_t)dpy, (uintptr_t)sync, flags, static_cast(timeout)); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); egl::Sync *syncObject = static_cast(sync); ANGLE_EGL_TRY_RETURN(thread, ValidateClientWaitSync(display, syncObject, flags, timeout), "eglClientWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE); gl::Context *currentContext = thread->getContext(); EGLint syncStatus = EGL_FALSE; ANGLE_EGL_TRY_RETURN( thread, syncObject->clientWait(display, currentContext, flags, timeout, &syncStatus), "eglClientWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE); thread->setSuccess(); return syncStatus; } EGLBoolean EGLAPIENTRY EGL_GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSync sync = 0x%016" PRIxPTR ", EGLint attribute = 0x%X, EGLAttrib " "*value = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)sync, attribute, (uintptr_t)value); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); egl::Sync *syncObject = static_cast(sync); ANGLE_EGL_TRY_RETURN(thread, ValidateGetSyncAttrib(display, syncObject, attribute, value), "eglGetSyncAttrib", GetSyncIfValid(display, syncObject), EGL_FALSE); EGLint valueExt; ANGLE_EGL_TRY_RETURN(thread, GetSyncAttrib(display, syncObject, attribute, &valueExt), "eglGetSyncAttrib", GetSyncIfValid(display, syncObject), EGL_FALSE); *value = valueExt; thread->setSuccess(); return EGL_TRUE; } EGLImage EGLAPIENTRY EGL_CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLContext ctx = 0x%016" PRIxPTR ", EGLenum target = 0x%X, " "EGLClientBuffer buffer = 0x%016" PRIxPTR ", const EGLAttrib *attrib_list = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)ctx, target, (uintptr_t)buffer, (uintptr_t)attrib_list); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); gl::Context *context = static_cast(ctx); AttributeMap attributes = AttributeMap::CreateFromIntArray((const EGLint *)attrib_list); Error error = ValidateCreateImage(display, context, target, buffer, attributes); if (error.isError()) { thread->setError(error, GetDebug(), "eglCreateImage", GetDisplayIfValid(display)); return EGL_NO_IMAGE; } Image *image = nullptr; error = display->createImage(context, target, buffer, attributes, &image); if (error.isError()) { thread->setError(error, GetDebug(), "eglCreateImage", GetDisplayIfValid(display)); return EGL_NO_IMAGE; } thread->setSuccess(); return static_cast(image); } EGLBoolean EGLAPIENTRY EGL_DestroyImage(EGLDisplay dpy, EGLImage image) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLImage image = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)image); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); Image *img = static_cast(image); Error error = ValidateDestroyImage(display, img); if (error.isError()) { thread->setError(error, GetDebug(), "eglDestroyImage", GetImageIfValid(display, img)); return EGL_FALSE; } display->destroyImage(img); thread->setSuccess(); return EGL_TRUE; } EGLDisplay EGLAPIENTRY EGL_GetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLenum platform = %d, void* native_display = 0x%016" PRIxPTR ", const EGLint* attrib_list = " "0x%016" PRIxPTR ")", platform, (uintptr_t)native_display, (uintptr_t)attrib_list); Thread *thread = egl::GetCurrentThread(); ANGLE_EGL_TRY_RETURN(thread, ValidateGetPlatformDisplay(platform, native_display, attrib_list), "eglGetPlatformDisplay", GetThreadIfValid(thread), EGL_NO_DISPLAY); const auto &attribMap = AttributeMap::CreateFromAttribArray(attrib_list); if (platform == EGL_PLATFORM_ANGLE_ANGLE) { return egl::Display::GetDisplayFromNativeDisplay( gl::bitCast(native_display), attribMap); } else if (platform == EGL_PLATFORM_DEVICE_EXT) { Device *eglDevice = static_cast(native_display); return egl::Display::GetDisplayFromDevice(eglDevice, attribMap); } else { UNREACHABLE(); return EGL_NO_DISPLAY; } } EGLSurface EGLAPIENTRY EGL_CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLConfig config = 0x%016" PRIxPTR ", void* native_window = 0x%016" PRIxPTR ", " "const EGLint* attrib_list = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)config, (uintptr_t)native_window, (uintptr_t)attrib_list); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); UNIMPLEMENTED(); thread->setError(EglBadDisplay() << "eglCreatePlatformWindowSurface unimplemented.", GetDebug(), "eglCreatePlatformWindowSurface", GetDisplayIfValid(display)); return EGL_NO_SURFACE; } EGLSurface EGLAPIENTRY EGL_CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy = 0x%016" PRIxPTR ", EGLConfig config = 0x%016" PRIxPTR ", void* native_pixmap = 0x%016" PRIxPTR ", " "const EGLint* attrib_list = 0x%016" PRIxPTR ")", (uintptr_t)dpy, (uintptr_t)config, (uintptr_t)native_pixmap, (uintptr_t)attrib_list); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); UNIMPLEMENTED(); thread->setError(EglBadDisplay() << "eglCreatePlatformPixmapSurface unimplemented.", GetDebug(), "eglCreatePlatformPixmapSurface", GetDisplayIfValid(display)); return EGL_NO_SURFACE; } EGLBoolean EGLAPIENTRY EGL_WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(EGLDisplay dpy =0x%016" PRIxPTR "p, EGLSync sync = 0x%016" PRIxPTR ", EGLint flags = 0x%X)", (uintptr_t)dpy, (uintptr_t)sync, flags); Thread *thread = egl::GetCurrentThread(); egl::Display *display = static_cast(dpy); gl::Context *context = thread->getContext(); egl::Sync *syncObject = static_cast(sync); ANGLE_EGL_TRY_RETURN(thread, ValidateWaitSync(display, context, syncObject, flags), "eglWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE); gl::Context *currentContext = thread->getContext(); ANGLE_EGL_TRY_RETURN(thread, syncObject->serverWait(display, currentContext, flags), "eglWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE); thread->setSuccess(); return EGL_TRUE; } __eglMustCastToProperFunctionPointerType EGLAPIENTRY EGL_GetProcAddress(const char *procname) { ANGLE_SCOPED_GLOBAL_LOCK(); EVENT("(const char *procname = \"%s\")", procname); Thread *thread = egl::GetCurrentThread(); ProcEntry *entry = std::lower_bound(&g_procTable[0], &g_procTable[g_numProcs], procname, CompareProc); thread->setSuccess(); if (entry == &g_procTable[g_numProcs] || strcmp(entry->first, procname) != 0) { return nullptr; } return entry->second; } } // extern "C"