| // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // libEGL.cpp: Implements the exported EGL functions. |
| |
| #include "main.h" |
| #include "Display.h" |
| #include "Surface.hpp" |
| #include "Texture.hpp" |
| #include "Context.hpp" |
| #include "common/Image.hpp" |
| #include "common/debug.h" |
| #include "Common/Version.h" |
| |
| #if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD) |
| #include <vndk/window.h> |
| #elif defined(USE_X11) |
| #include "Main/libX11.hpp" |
| #endif |
| |
| #include <algorithm> |
| #include <vector> |
| #include <string.h> |
| |
| namespace egl |
| { |
| namespace |
| { |
| sw::RecursiveLock *getDisplayLock(egl::Display *display) { |
| if (!display) return nullptr; |
| return display->getLock(); |
| } |
| |
| bool validateDisplay(egl::Display *display) |
| { |
| if(display == EGL_NO_DISPLAY) |
| { |
| return error(EGL_BAD_DISPLAY, false); |
| } |
| |
| if(!display->isInitialized()) |
| { |
| return error(EGL_NOT_INITIALIZED, false); |
| } |
| |
| return true; |
| } |
| |
| bool validateConfig(egl::Display *display, EGLConfig config) |
| { |
| if(!validateDisplay(display)) |
| { |
| return false; |
| } |
| |
| if(!display->isValidConfig(config)) |
| { |
| return error(EGL_BAD_CONFIG, false); |
| } |
| |
| return true; |
| } |
| |
| bool validateContext(egl::Display *display, egl::Context *context) |
| { |
| if(!validateDisplay(display)) |
| { |
| return false; |
| } |
| |
| if(!display->isValidContext(context)) |
| { |
| return error(EGL_BAD_CONTEXT, false); |
| } |
| |
| return true; |
| } |
| |
| bool validateSurface(egl::Display *display, egl::Surface *surface) |
| { |
| if(!validateDisplay(display)) |
| { |
| return false; |
| } |
| |
| if(!display->isValidSurface(surface)) |
| { |
| return error(EGL_BAD_SURFACE, false); |
| } |
| |
| return true; |
| } |
| |
| // Class to facilitate conversion from EGLint to EGLAttrib lists. |
| class EGLAttribs |
| { |
| public: |
| explicit EGLAttribs(const EGLint *attrib_list) |
| { |
| if(attrib_list) |
| { |
| while(*attrib_list != EGL_NONE) |
| { |
| attrib.push_back(static_cast<EGLAttrib>(*attrib_list)); |
| attrib_list++; |
| } |
| } |
| |
| attrib.push_back(EGL_NONE); |
| } |
| |
| const EGLAttrib *operator&() const |
| { |
| return &attrib[0]; |
| } |
| |
| private: |
| std::vector<EGLAttrib> attrib; |
| }; |
| } |
| |
| EGLint EGLAPIENTRY GetError(void) |
| { |
| TRACE("()"); |
| |
| EGLint error = egl::getCurrentError(); |
| |
| if(error != EGL_SUCCESS) |
| { |
| egl::setCurrentError(EGL_SUCCESS); |
| } |
| |
| return error; |
| } |
| |
| EGLDisplay EGLAPIENTRY GetDisplay(EGLNativeDisplayType display_id) |
| { |
| TRACE("(EGLNativeDisplayType display_id = %p)", display_id); |
| |
| if(display_id != EGL_DEFAULT_DISPLAY) |
| { |
| // FIXME: Check if display_id is the default display |
| } |
| |
| #if defined(__linux__) && !defined(__ANDROID__) |
| #if defined(USE_X11) |
| if(!libX11) |
| #endif // Non X11 linux is headless only |
| { |
| return success(HEADLESS_DISPLAY); |
| } |
| #endif |
| |
| return success(PRIMARY_DISPLAY); // We only support the default display |
| } |
| |
| EGLBoolean EGLAPIENTRY Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLint *major = %p, EGLint *minor = %p)", |
| dpy, major, minor); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!display) |
| { |
| return error(EGL_BAD_DISPLAY, EGL_FALSE); |
| } |
| |
| if(!display->initialize()) |
| { |
| return error(EGL_NOT_INITIALIZED, EGL_FALSE); |
| } |
| |
| if(major) *major = 1; |
| if(minor) *minor = 4; |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY Terminate(EGLDisplay dpy) |
| { |
| TRACE("(EGLDisplay dpy = %p)", dpy); |
| |
| if(dpy == EGL_NO_DISPLAY) |
| { |
| return error(EGL_BAD_DISPLAY, EGL_FALSE); |
| } |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| display->terminate(); |
| |
| return success(EGL_TRUE); |
| } |
| |
| const char *EGLAPIENTRY QueryString(EGLDisplay dpy, EGLint name) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLint name = %d)", dpy, name); |
| |
| if(dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) |
| { |
| return success( |
| "EGL_KHR_client_get_all_proc_addresses " |
| #if defined(__linux__) && !defined(__ANDROID__) |
| "EGL_KHR_platform_gbm " |
| #endif |
| #if defined(USE_X11) |
| "EGL_KHR_platform_x11 " |
| #endif |
| "EGL_EXT_client_extensions " |
| "EGL_EXT_platform_base"); |
| } |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateDisplay(display)) |
| { |
| return nullptr; |
| } |
| |
| switch(name) |
| { |
| case EGL_CLIENT_APIS: |
| return success("OpenGL_ES"); |
| case EGL_EXTENSIONS: |
| return success("EGL_KHR_create_context " |
| "EGL_KHR_get_all_proc_addresses " |
| "EGL_KHR_gl_texture_2D_image " |
| "EGL_KHR_gl_texture_cubemap_image " |
| "EGL_KHR_gl_renderbuffer_image " |
| "EGL_KHR_fence_sync " |
| "EGL_KHR_image_base " |
| "EGL_KHR_surfaceless_context " |
| "EGL_ANGLE_iosurface_client_buffer " |
| "EGL_ANDROID_framebuffer_target " |
| "EGL_ANDROID_recordable"); |
| case EGL_VENDOR: |
| return success("Google Inc."); |
| case EGL_VERSION: |
| return success("1.4 SwiftShader " VERSION_STRING); |
| } |
| |
| return error(EGL_BAD_PARAMETER, (const char*)nullptr); |
| } |
| |
| EGLBoolean EGLAPIENTRY GetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLConfig *configs = %p, " |
| "EGLint config_size = %d, EGLint *num_config = %p)", |
| dpy, configs, config_size, num_config); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateDisplay(display)) |
| { |
| return EGL_FALSE; |
| } |
| |
| if(!num_config) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| const EGLint attribList[] = {EGL_NONE}; |
| |
| if(!display->getConfigs(configs, attribList, config_size, num_config)) |
| { |
| return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY ChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) |
| { |
| TRACE("(EGLDisplay dpy = %p, const EGLint *attrib_list = %p, " |
| "EGLConfig *configs = %p, EGLint config_size = %d, EGLint *num_config = %p)", |
| dpy, attrib_list, configs, config_size, num_config); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateDisplay(display)) |
| { |
| return EGL_FALSE; |
| } |
| |
| if(!num_config) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| const EGLint attribList[] = {EGL_NONE}; |
| |
| if(!attrib_list) |
| { |
| attrib_list = attribList; |
| } |
| |
| if(!display->getConfigs(configs, attrib_list, config_size, num_config)) |
| { |
| return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLint attribute = %d, EGLint *value = %p)", |
| dpy, config, attribute, value); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateConfig(display, config)) |
| { |
| return EGL_FALSE; |
| } |
| |
| if(!display->getConfigAttrib(config, attribute, value)) |
| { |
| return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLSurface EGLAPIENTRY CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_window = %p, " |
| "const EGLint *attrib_list = %p)", dpy, config, native_window, attrib_list); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateConfig(display, config)) |
| { |
| return EGL_NO_SURFACE; |
| } |
| |
| #if defined(USE_X11) |
| native_window = (void *)(*(::Window*)native_window); |
| #endif |
| |
| if(!display->isValidWindow((EGLNativeWindowType)native_window)) |
| { |
| return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); |
| } |
| |
| return display->createWindowSurface((EGLNativeWindowType)native_window, config, attrib_list); |
| } |
| |
| EGLSurface EGLAPIENTRY CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_window = %p, " |
| "const EGLint *attrib_list = %p)", dpy, config, native_window, attrib_list); |
| |
| EGLAttribs attribs(attrib_list); |
| return CreatePlatformWindowSurface(dpy, config, native_window, &attribs); |
| } |
| |
| EGLSurface EGLAPIENTRY CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType window, const EGLint *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativeWindowType window = %p, " |
| "const EGLint *attrib_list = %p)", dpy, config, window, attrib_list); |
| |
| EGLAttribs attribs(attrib_list); |
| |
| #if defined(USE_X11) |
| return CreatePlatformWindowSurface(dpy, config, (void*)&window, &attribs); |
| #else |
| return CreatePlatformWindowSurface(dpy, config, (void*)window, &attribs); |
| #endif |
| } |
| |
| EGLSurface EGLAPIENTRY CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, const EGLint *attrib_list = %p)", |
| dpy, config, attrib_list); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateConfig(display, config)) |
| { |
| return EGL_NO_SURFACE; |
| } |
| |
| return display->createPBufferSurface(config, attrib_list); |
| } |
| |
| EGLSurface EGLAPIENTRY CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_pixmap = %p, " |
| "const EGLint *attrib_list = %p)", dpy, config, native_pixmap, attrib_list); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateConfig(display, config)) |
| { |
| return EGL_NO_SURFACE; |
| } |
| |
| UNIMPLEMENTED(); // FIXME |
| |
| return success(EGL_NO_SURFACE); |
| } |
| |
| EGLSurface EGLAPIENTRY CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, void *native_pixmap = %p, " |
| "const EGLint *attrib_list = %p)", dpy, config, native_pixmap, attrib_list); |
| |
| EGLAttribs attribs(attrib_list); |
| return CreatePlatformPixmapSurface(dpy, config, native_pixmap, &attribs); |
| } |
| |
| EGLSurface EGLAPIENTRY CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativePixmapType pixmap = %p, " |
| "const EGLint *attrib_list = %p)", dpy, config, pixmap, attrib_list); |
| |
| EGLAttribs attribs(attrib_list); |
| return CreatePlatformPixmapSurface(dpy, config, (void*)pixmap, &attribs); |
| } |
| |
| EGLBoolean EGLAPIENTRY DestroySurface(EGLDisplay dpy, EGLSurface surface) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p)", dpy, surface); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateSurface(display, eglSurface)) |
| { |
| return EGL_FALSE; |
| } |
| |
| if(surface == EGL_NO_SURFACE) |
| { |
| return error(EGL_BAD_SURFACE, EGL_FALSE); |
| } |
| |
| display->destroySurface((egl::Surface*)surface); |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY QuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint attribute = %d, EGLint *value = %p)", |
| dpy, surface, attribute, value); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Surface *eglSurface = (egl::Surface*)surface; |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateSurface(display, eglSurface)) |
| { |
| return EGL_FALSE; |
| } |
| |
| if(surface == EGL_NO_SURFACE) |
| { |
| return error(EGL_BAD_SURFACE, EGL_FALSE); |
| } |
| |
| switch(attribute) |
| { |
| case EGL_VG_ALPHA_FORMAT: |
| *value = EGL_VG_ALPHA_FORMAT_NONPRE; // Default |
| break; |
| case EGL_VG_COLORSPACE: |
| *value = EGL_VG_COLORSPACE_sRGB; // Default |
| break; |
| case EGL_CONFIG_ID: |
| *value = eglSurface->getConfigID(); |
| break; |
| case EGL_HEIGHT: |
| *value = eglSurface->getHeight(); |
| break; |
| case EGL_HORIZONTAL_RESOLUTION: |
| *value = EGL_UNKNOWN; |
| break; |
| case EGL_LARGEST_PBUFFER: |
| if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified. |
| { |
| *value = eglSurface->getLargestPBuffer(); |
| } |
| break; |
| case EGL_MIPMAP_TEXTURE: |
| if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified. |
| { |
| *value = EGL_FALSE; // UNIMPLEMENTED |
| } |
| break; |
| case EGL_MIPMAP_LEVEL: |
| if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified. |
| { |
| *value = eglSurface->getMipmapLevel(); |
| } |
| break; |
| case EGL_MULTISAMPLE_RESOLVE: |
| *value = eglSurface->getMultisampleResolve(); |
| break; |
| case EGL_PIXEL_ASPECT_RATIO: |
| *value = eglSurface->getPixelAspectRatio(); |
| break; |
| case EGL_RENDER_BUFFER: |
| *value = eglSurface->getRenderBuffer(); |
| break; |
| case EGL_SWAP_BEHAVIOR: |
| *value = eglSurface->getSwapBehavior(); |
| break; |
| case EGL_TEXTURE_FORMAT: |
| if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified. |
| { |
| *value = eglSurface->getTextureFormat(); |
| } |
| break; |
| case EGL_TEXTURE_TARGET: |
| if(eglSurface->isPBufferSurface()) // For a window or pixmap surface, the contents of *value are not modified. |
| { |
| *value = eglSurface->getTextureTarget(); |
| } |
| break; |
| case EGL_VERTICAL_RESOLUTION: |
| *value = EGL_UNKNOWN; |
| break; |
| case EGL_WIDTH: |
| *value = eglSurface->getWidth(); |
| break; |
| default: |
| return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY BindAPI(EGLenum api) |
| { |
| TRACE("(EGLenum api = 0x%X)", api); |
| |
| switch(api) |
| { |
| case EGL_OPENGL_API: |
| case EGL_OPENVG_API: |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation |
| case EGL_OPENGL_ES_API: |
| break; |
| default: |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| egl::setCurrentAPI(api); |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLenum EGLAPIENTRY QueryAPI(void) |
| { |
| TRACE("()"); |
| |
| EGLenum API = egl::getCurrentAPI(); |
| |
| return success(API); |
| } |
| |
| EGLBoolean EGLAPIENTRY WaitClient(void) |
| { |
| TRACE("()"); |
| |
| // eglWaitClient is ignored if there is no current EGL rendering context for the current rendering API. |
| egl::Context *context = egl::getCurrentContext(); |
| |
| if(context) |
| { |
| context->finish(); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY ReleaseThread(void) |
| { |
| TRACE("()"); |
| |
| detachThread(); |
| |
| return EGL_TRUE; // success() is not called here because it would re-allocate thread-local storage. |
| } |
| |
| EGLSurface EGLAPIENTRY CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = %p, " |
| "EGLConfig config = %p, const EGLint *attrib_list = %p)", |
| dpy, buftype, buffer, config, attrib_list); |
| |
| switch(buftype) |
| { |
| case EGL_IOSURFACE_ANGLE: |
| { |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateConfig(display, config)) |
| { |
| return EGL_NO_SURFACE; |
| } |
| |
| return display->createPBufferSurface(config, attrib_list, buffer); |
| } |
| case EGL_OPENVG_IMAGE: |
| UNIMPLEMENTED(); |
| return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); |
| default: |
| return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); |
| }; |
| } |
| |
| EGLBoolean EGLAPIENTRY SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint attribute = %d, EGLint value = %d)", |
| dpy, surface, attribute, value); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateSurface(display, eglSurface)) |
| { |
| return EGL_FALSE; |
| } |
| |
| switch(attribute) |
| { |
| case EGL_MIPMAP_LEVEL: |
| eglSurface->setMipmapLevel(value); |
| break; |
| case EGL_MULTISAMPLE_RESOLVE: |
| switch(value) |
| { |
| case EGL_MULTISAMPLE_RESOLVE_DEFAULT: |
| break; |
| case EGL_MULTISAMPLE_RESOLVE_BOX: |
| if(!(eglSurface->getSurfaceType() & EGL_MULTISAMPLE_RESOLVE_BOX_BIT)) |
| { |
| return error(EGL_BAD_MATCH, EGL_FALSE); |
| } |
| break; |
| default: |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| eglSurface->setMultisampleResolve(value); |
| break; |
| case EGL_SWAP_BEHAVIOR: |
| switch(value) |
| { |
| case EGL_BUFFER_DESTROYED: |
| break; |
| case EGL_BUFFER_PRESERVED: |
| if(!(eglSurface->getSurfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)) |
| { |
| return error(EGL_BAD_MATCH, EGL_FALSE); |
| } |
| break; |
| default: |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| eglSurface->setSwapBehavior(value); |
| break; |
| default: |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint buffer = %d)", dpy, surface, buffer); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateSurface(display, eglSurface)) |
| { |
| return EGL_FALSE; |
| } |
| |
| if(buffer != EGL_BACK_BUFFER) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| if(surface == EGL_NO_SURFACE || eglSurface->isWindowSurface()) |
| { |
| return error(EGL_BAD_SURFACE, EGL_FALSE); |
| } |
| |
| if(eglSurface->getBoundTexture()) |
| { |
| return error(EGL_BAD_ACCESS, EGL_FALSE); |
| } |
| |
| if(eglSurface->getTextureFormat() == EGL_NO_TEXTURE) |
| { |
| return error(EGL_BAD_MATCH, EGL_FALSE); |
| } |
| |
| egl::Context *context = egl::getCurrentContext(); |
| |
| if(context) |
| { |
| context->bindTexImage(eglSurface); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLint buffer = %d)", dpy, surface, buffer); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateSurface(display, eglSurface)) |
| { |
| return EGL_FALSE; |
| } |
| |
| if(buffer != EGL_BACK_BUFFER) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| if(surface == EGL_NO_SURFACE || eglSurface->isWindowSurface()) |
| { |
| return error(EGL_BAD_SURFACE, EGL_FALSE); |
| } |
| |
| if(eglSurface->getTextureFormat() == EGL_NO_TEXTURE) |
| { |
| return error(EGL_BAD_MATCH, EGL_FALSE); |
| } |
| |
| egl::Texture *texture = eglSurface->getBoundTexture(); |
| |
| if(texture) |
| { |
| texture->releaseTexImage(); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY SwapInterval(EGLDisplay dpy, EGLint interval) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLint interval = %d)", dpy, interval); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Context *context = egl::getCurrentContext(); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateContext(display, context)) |
| { |
| return EGL_FALSE; |
| } |
| |
| egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface()); |
| |
| if(!draw_surface) |
| { |
| return error(EGL_BAD_SURFACE, EGL_FALSE); |
| } |
| |
| draw_surface->setSwapInterval(interval); |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLContext EGLAPIENTRY CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLContext share_context = %p, " |
| "const EGLint *attrib_list = %p)", dpy, config, share_context, attrib_list); |
| |
| EGLint majorVersion = 1; |
| EGLint minorVersion = 0; |
| |
| if(attrib_list) |
| { |
| for(const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) |
| { |
| switch(attribute[0]) |
| { |
| case EGL_CONTEXT_MAJOR_VERSION_KHR: // This token is an alias for EGL_CONTEXT_CLIENT_VERSION |
| majorVersion = attribute[1]; |
| break; |
| case EGL_CONTEXT_MINOR_VERSION_KHR: |
| minorVersion = attribute[1]; |
| break; |
| case EGL_CONTEXT_FLAGS_KHR: |
| switch(attribute[1]) |
| { |
| case EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR: |
| // According to the EGL_KHR_create_context spec: |
| // "Khronos is still defining the expected and required features of debug contexts, so |
| // implementations are currently free to implement "debug contexts" with little or no debug |
| // functionality. However, OpenGL and OpenGL ES implementations supporting the GL_KHR_debug |
| // extension should enable it when this bit is set." |
| break; |
| case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR: |
| case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR: |
| // These bits are for OpenGL contexts only, not OpenGL ES contexts |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
| default: |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
| } |
| break; |
| case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: |
| switch(attribute[1]) |
| { |
| case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR: |
| case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR: |
| // These bits are for OpenGL contexts only, not OpenGL ES contexts |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
| default: |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
| } |
| break; |
| case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR: |
| switch(attribute[1]) |
| { |
| case EGL_NO_RESET_NOTIFICATION_KHR: |
| case EGL_LOSE_CONTEXT_ON_RESET_KHR: |
| // These bits are for OpenGL contexts only, not OpenGL ES contexts |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
| default: |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
| } |
| break; |
| default: |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); |
| } |
| } |
| } |
| |
| switch(majorVersion) |
| { |
| case 1: |
| if(minorVersion != 0 && minorVersion != 1) |
| { |
| // 1.X: Only OpenGL ES 1.0 and 1.1 contexts are supported |
| return error(EGL_BAD_MATCH, EGL_NO_CONTEXT); |
| } |
| break; |
| case 2: |
| case 3: |
| if(minorVersion != 0) |
| { |
| // 2.X and 3.X: Only OpenGL ES 2.0 and 3.0 contexts are currently supported |
| return error(EGL_BAD_MATCH, EGL_NO_CONTEXT); |
| } |
| break; |
| default: |
| return error(EGL_BAD_MATCH, EGL_NO_CONTEXT); |
| } |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Context *shareContext = static_cast<egl::Context*>(share_context); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateConfig(display, config)) |
| { |
| return EGL_NO_CONTEXT; |
| } |
| |
| // Allow sharing between different context versions >= 2.0, but isolate 1.x |
| // contexts from 2.0+. Strict matching between context versions >= 2.0 is |
| // confusing for apps to navigate because of version promotion. |
| if(shareContext && ((shareContext->getClientVersion() >= 2) ^ (majorVersion >= 2))) |
| { |
| return error(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); |
| } |
| |
| return display->createContext(config, shareContext, majorVersion); |
| } |
| |
| EGLBoolean EGLAPIENTRY DestroyContext(EGLDisplay dpy, EGLContext ctx) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p)", dpy, ctx); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Context *context = static_cast<egl::Context*>(ctx); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateContext(display, context)) |
| { |
| return EGL_FALSE; |
| } |
| |
| if(ctx == EGL_NO_CONTEXT) |
| { |
| return error(EGL_BAD_CONTEXT, EGL_FALSE); |
| } |
| |
| display->destroyContext(context); |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSurface draw = %p, EGLSurface read = %p, EGLContext ctx = %p)", |
| dpy, draw, read, ctx); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Context *context = static_cast<egl::Context*>(ctx); |
| egl::Surface *drawSurface = static_cast<egl::Surface*>(draw); |
| egl::Surface *readSurface = static_cast<egl::Surface*>(read); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(ctx != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) |
| { |
| if(!validateDisplay(display)) |
| { |
| return EGL_FALSE; |
| } |
| } |
| |
| if(ctx == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) |
| { |
| return error(EGL_BAD_MATCH, EGL_FALSE); |
| } |
| |
| if(ctx != EGL_NO_CONTEXT && !validateContext(display, context)) |
| { |
| return EGL_FALSE; |
| } |
| |
| if((draw != EGL_NO_SURFACE && !validateSurface(display, drawSurface)) || |
| (read != EGL_NO_SURFACE && !validateSurface(display, readSurface))) |
| { |
| return EGL_FALSE; |
| } |
| |
| if((draw != EGL_NO_SURFACE) ^ (read != EGL_NO_SURFACE)) |
| { |
| return error(EGL_BAD_MATCH, EGL_FALSE); |
| } |
| |
| if(draw != read) |
| { |
| UNIMPLEMENTED(); // FIXME |
| } |
| |
| egl::setCurrentDrawSurface(drawSurface); |
| egl::setCurrentReadSurface(readSurface); |
| egl::setCurrentContext(context); |
| |
| if(context) |
| { |
| context->makeCurrent(drawSurface); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLContext EGLAPIENTRY GetCurrentContext(void) |
| { |
| TRACE("()"); |
| |
| EGLContext context = egl::getCurrentContext(); |
| |
| return success(context); |
| } |
| |
| EGLSurface EGLAPIENTRY GetCurrentSurface(EGLint readdraw) |
| { |
| TRACE("(EGLint readdraw = %d)", readdraw); |
| |
| if(readdraw == EGL_READ) |
| { |
| EGLSurface read = egl::getCurrentReadSurface(); |
| return success(read); |
| } |
| else if(readdraw == EGL_DRAW) |
| { |
| EGLSurface draw = egl::getCurrentDrawSurface(); |
| return success(draw); |
| } |
| else |
| { |
| return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); |
| } |
| } |
| |
| EGLDisplay EGLAPIENTRY GetCurrentDisplay(void) |
| { |
| TRACE("()"); |
| |
| egl::Context *context = egl::getCurrentContext(); |
| |
| if(!context) |
| { |
| return success(EGL_NO_DISPLAY); |
| } |
| |
| egl::Display *display = context->getDisplay(); |
| |
| if(!display) |
| { |
| return error(EGL_BAD_ACCESS, EGL_NO_DISPLAY); |
| } |
| |
| return success(display->getEGLDisplay()); |
| } |
| |
| EGLBoolean EGLAPIENTRY QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLint attribute = %d, EGLint *value = %p)", |
| dpy, ctx, attribute, value); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Context *context = static_cast<egl::Context*>(ctx); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateContext(display, context)) |
| { |
| return EGL_FALSE; |
| } |
| |
| switch(attribute) |
| { |
| case EGL_CONFIG_ID: |
| *value = context->getConfigID(); |
| break; |
| case EGL_CONTEXT_CLIENT_TYPE: |
| *value = egl::getCurrentAPI(); |
| break; |
| case EGL_CONTEXT_CLIENT_VERSION: |
| *value = context->getClientVersion(); |
| break; |
| case EGL_RENDER_BUFFER: |
| *value = EGL_BACK_BUFFER; |
| break; |
| default: |
| return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY WaitGL(void) |
| { |
| TRACE("()"); |
| |
| // glWaitGL is ignored if there is no current EGL rendering context for OpenGL ES. |
| egl::Context *context = egl::getCurrentContext(); |
| |
| if(context) |
| { |
| context->finish(); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY WaitNative(EGLint engine) |
| { |
| TRACE("(EGLint engine = %d)", engine); |
| |
| if(engine != EGL_CORE_NATIVE_ENGINE) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| // eglWaitNative is ignored if there is no current EGL rendering context. |
| egl::Context *context = egl::getCurrentContext(); |
| |
| if(context) |
| { |
| #if defined(USE_X11) |
| egl::Display *display = context->getDisplay(); |
| |
| if(!display) |
| { |
| return error(EGL_BAD_DISPLAY, EGL_FALSE); |
| } |
| |
| libX11->XSync((::Display*)display->getNativeDisplay(), False); |
| #else |
| UNIMPLEMENTED(); |
| #endif |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY SwapBuffers(EGLDisplay dpy, EGLSurface surface) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p)", dpy, surface); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Surface *eglSurface = (egl::Surface*)surface; |
| |
| { |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateSurface(display, eglSurface)) |
| { |
| return EGL_FALSE; |
| } |
| } |
| |
| if(surface == EGL_NO_SURFACE) |
| { |
| return error(EGL_BAD_SURFACE, EGL_FALSE); |
| } |
| |
| eglSurface->swap(); |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLBoolean EGLAPIENTRY CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSurface surface = %p, EGLNativePixmapType target = %p)", dpy, surface, target); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateSurface(display, eglSurface)) |
| { |
| return EGL_FALSE; |
| } |
| |
| UNIMPLEMENTED(); // FIXME |
| |
| return success(EGL_FALSE); |
| } |
| |
| EGLImage EGLAPIENTRY CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLenum target = 0x%X, buffer = %p, const EGLAttrib *attrib_list = %p)", dpy, ctx, target, buffer, attrib_list); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| egl::Context *context = static_cast<egl::Context*>(ctx); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateDisplay(display)) |
| { |
| return error(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR); |
| } |
| |
| if(context != EGL_NO_CONTEXT && !display->isValidContext(context)) |
| { |
| return error(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); |
| } |
| |
| EGLenum imagePreserved = EGL_FALSE; |
| (void)imagePreserved; // currently unused |
| |
| GLuint textureLevel = 0; |
| if(attrib_list) |
| { |
| for(const EGLAttrib *attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) |
| { |
| if(attribute[0] == EGL_IMAGE_PRESERVED_KHR) |
| { |
| imagePreserved = static_cast<EGLenum>(attribute[1]); |
| } |
| else if(attribute[0] == EGL_GL_TEXTURE_LEVEL_KHR) |
| { |
| textureLevel = static_cast<GLuint>(attribute[1]); |
| } |
| else |
| { |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR); |
| } |
| } |
| } |
| |
| #if defined(__ANDROID__) && !defined(ANDROID_NDK_BUILD) |
| if(target == EGL_NATIVE_BUFFER_ANDROID) |
| { |
| ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(buffer); |
| |
| if(!nativeBuffer || GLPixelFormatFromAndroid(nativeBuffer->format) == GL_NONE) |
| { |
| ERR("%s badness unsupported HAL format=%x", __FUNCTION__, nativeBuffer ? nativeBuffer->format : 0); |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR); |
| } |
| |
| Image *image = new AndroidNativeImage(nativeBuffer); |
| EGLImageKHR eglImage = display->createSharedImage(image); |
| |
| return success(eglImage); |
| } |
| #endif |
| |
| GLuint name = static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer)); |
| |
| if(name == 0) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); |
| } |
| |
| EGLenum validationResult = context->validateSharedImage(target, name, textureLevel); |
| |
| if(validationResult != EGL_SUCCESS) |
| { |
| return error(validationResult, EGL_NO_IMAGE_KHR); |
| } |
| |
| Image *image = context->createSharedImage(target, name, textureLevel); |
| |
| if(!image) |
| { |
| return error(EGL_BAD_MATCH, EGL_NO_IMAGE_KHR); |
| } |
| |
| if(image->getDepth() > 1) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); |
| } |
| |
| EGLImage eglImage = display->createSharedImage(image); |
| |
| return success(eglImage); |
| } |
| |
| EGLImageKHR EGLAPIENTRY CreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLContext ctx = %p, EGLenum target = 0x%X, buffer = %p, const EGLint attrib_list = %p)", dpy, ctx, target, buffer, attrib_list); |
| |
| EGLAttribs attribs(attrib_list); |
| return CreateImage(dpy, ctx, target, buffer, &attribs); |
| } |
| |
| EGLBoolean EGLAPIENTRY DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLImageKHR image = %p)", dpy, image); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateDisplay(display)) |
| { |
| return error(EGL_BAD_DISPLAY, EGL_FALSE); |
| } |
| |
| if(!display->destroySharedImage(image)) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLDisplay EGLAPIENTRY GetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list) |
| { |
| TRACE("(EGLenum platform = 0x%X, void *native_display = %p, const EGLAttrib *attrib_list = %p)", platform, native_display, attrib_list); |
| |
| #if defined(__linux__) && !defined(__ANDROID__) |
| switch(platform) |
| { |
| #if defined(USE_X11) |
| case EGL_PLATFORM_X11_EXT: break; |
| #endif |
| case EGL_PLATFORM_GBM_KHR: break; |
| default: |
| return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); |
| } |
| |
| if(platform == EGL_PLATFORM_GBM_KHR) |
| { |
| if(native_display != (void*)EGL_DEFAULT_DISPLAY) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); // Unimplemented |
| } |
| |
| if(attrib_list && attrib_list[0] != EGL_NONE) |
| { |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented |
| } |
| |
| return success(HEADLESS_DISPLAY); |
| } |
| #if defined(USE_X11) |
| else if(platform == EGL_PLATFORM_X11_EXT) |
| { |
| if(!libX11) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); |
| } |
| |
| if(native_display != (void*)EGL_DEFAULT_DISPLAY) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); // Unimplemented |
| } |
| |
| if(attrib_list && attrib_list[0] != EGL_NONE) |
| { |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented |
| } |
| } |
| #endif |
| |
| return success(PRIMARY_DISPLAY); // We only support the default display |
| #else |
| return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); |
| #endif |
| } |
| |
| EGLDisplay EGLAPIENTRY GetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) |
| { |
| TRACE("(EGLenum platform = 0x%X, void *native_display = %p, const EGLint *attrib_list = %p)", platform, native_display, attrib_list); |
| |
| EGLAttribs attribs(attrib_list); |
| return GetPlatformDisplay(platform, native_display, &attribs); |
| } |
| |
| EGLSync EGLAPIENTRY CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLAttrib *attrib_list=%p)", dpy, type, attrib_list); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateDisplay(display)) |
| { |
| return error(EGL_BAD_DISPLAY, EGL_NO_SYNC_KHR); |
| } |
| |
| if(type != EGL_SYNC_FENCE_KHR) |
| { |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR); |
| } |
| |
| if(attrib_list && attrib_list[0] != EGL_NONE) |
| { |
| return error(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR); |
| } |
| |
| egl::Context *context = egl::getCurrentContext(); |
| |
| if(!validateContext(display, context)) |
| { |
| return error(EGL_BAD_MATCH, EGL_NO_SYNC_KHR); |
| } |
| |
| EGLSyncKHR sync = display->createSync(context); |
| |
| return success(sync); |
| } |
| |
| EGLSyncKHR EGLAPIENTRY CreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLint *attrib_list=%p)", dpy, type, attrib_list); |
| |
| EGLAttribs attribs(attrib_list); |
| return CreateSync(dpy, type, &attribs); |
| } |
| |
| EGLBoolean EGLAPIENTRY DestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p)", dpy, sync); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| FenceSync *eglSync = static_cast<FenceSync*>(sync); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateDisplay(display)) |
| { |
| return error(EGL_BAD_DISPLAY, EGL_FALSE); |
| } |
| |
| if(!display->isValidSync(eglSync)) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| display->destroySync(eglSync); |
| |
| return success(EGL_TRUE); |
| } |
| |
| EGLint EGLAPIENTRY ClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint flags = %x, EGLTimeKHR value = %llx)", dpy, sync, flags, timeout); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| FenceSync *eglSync = static_cast<FenceSync*>(sync); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateDisplay(display)) |
| { |
| return error(EGL_BAD_DISPLAY, EGL_FALSE); |
| } |
| |
| if(!display->isValidSync(eglSync)) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| (void)flags; |
| (void)timeout; |
| |
| if(!eglSync->isSignaled()) |
| { |
| eglSync->wait(); |
| } |
| |
| return success(EGL_CONDITION_SATISFIED_KHR); |
| } |
| |
| EGLBoolean EGLAPIENTRY GetSyncAttrib(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLAttrib *value) |
| { |
| TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint attribute = %x, EGLAttrib *value = %p)", dpy, sync, attribute, value); |
| |
| egl::Display *display = egl::Display::get(dpy); |
| FenceSync *eglSync = static_cast<FenceSync*>(sync); |
| |
| RecursiveLockGuard lock(egl::getDisplayLock(display)); |
| |
| if(!validateDisplay(display)) |
| { |
| return error(EGL_BAD_DISPLAY, EGL_FALSE); |
| } |
| |
| if(!display->isValidSync(eglSync)) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| if(!value) |
| { |
| return error(EGL_BAD_PARAMETER, EGL_FALSE); |
| } |
| |
| switch(attribute) |
| { |
| case EGL_SYNC_TYPE_KHR: |
| *value = EGL_SYNC_FENCE_KHR; |
| return success(EGL_TRUE); |
| case EGL_SYNC_STATUS_KHR: |
| eglSync->wait(); // TODO: Don't block. Just poll based on sw::Query. |
| *value = eglSync->isSignaled() ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR; |
| return success(EGL_TRUE); |
| case EGL_SYNC_CONDITION_KHR: |
| *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR; |
| return success(EGL_TRUE); |
| default: |
| return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); |
| } |
| } |
| |
| EGLBoolean EGLAPIENTRY GetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) |
| { |
| EGLAttrib attrib_value; |
| EGLBoolean result = GetSyncAttrib(dpy, sync, attribute, &attrib_value); |
| *value = static_cast<EGLint>(attrib_value); |
| return result; |
| } |
| |
| __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *procname) |
| { |
| TRACE("(const char *procname = \"%s\")", procname); |
| |
| struct Function |
| { |
| const char *name; |
| __eglMustCastToProperFunctionPointerType address; |
| }; |
| |
| struct CompareFunctor |
| { |
| bool operator()(const Function &a, const Function &b) const |
| { |
| return strcmp(a.name, b.name) < 0; |
| } |
| }; |
| |
| // This array must be kept sorted with respect to strcmp(), so that binary search works correctly. |
| // The Unix command "LC_COLLATE=C sort" will generate the correct order. |
| static const Function eglFunctions[] = |
| { |
| #define FUNCTION(name) {#name, (__eglMustCastToProperFunctionPointerType)name} |
| |
| FUNCTION(eglBindAPI), |
| FUNCTION(eglBindTexImage), |
| FUNCTION(eglChooseConfig), |
| FUNCTION(eglClientWaitSync), |
| FUNCTION(eglClientWaitSyncKHR), |
| FUNCTION(eglCopyBuffers), |
| FUNCTION(eglCreateContext), |
| FUNCTION(eglCreateImage), |
| FUNCTION(eglCreateImageKHR), |
| FUNCTION(eglCreatePbufferFromClientBuffer), |
| FUNCTION(eglCreatePbufferSurface), |
| FUNCTION(eglCreatePixmapSurface), |
| FUNCTION(eglCreatePlatformPixmapSurface), |
| FUNCTION(eglCreatePlatformPixmapSurfaceEXT), |
| FUNCTION(eglCreatePlatformWindowSurface), |
| FUNCTION(eglCreatePlatformWindowSurfaceEXT), |
| FUNCTION(eglCreateSync), |
| FUNCTION(eglCreateSyncKHR), |
| FUNCTION(eglCreateWindowSurface), |
| FUNCTION(eglDestroyContext), |
| FUNCTION(eglDestroyImage), |
| FUNCTION(eglDestroyImageKHR), |
| FUNCTION(eglDestroySurface), |
| FUNCTION(eglDestroySync), |
| FUNCTION(eglDestroySyncKHR), |
| FUNCTION(eglGetConfigAttrib), |
| FUNCTION(eglGetConfigs), |
| FUNCTION(eglGetCurrentContext), |
| FUNCTION(eglGetCurrentDisplay), |
| FUNCTION(eglGetCurrentSurface), |
| FUNCTION(eglGetDisplay), |
| FUNCTION(eglGetError), |
| FUNCTION(eglGetPlatformDisplay), |
| FUNCTION(eglGetPlatformDisplayEXT), |
| FUNCTION(eglGetProcAddress), |
| FUNCTION(eglGetSyncAttrib), |
| FUNCTION(eglGetSyncAttribKHR), |
| FUNCTION(eglInitialize), |
| FUNCTION(eglMakeCurrent), |
| FUNCTION(eglQueryAPI), |
| FUNCTION(eglQueryContext), |
| FUNCTION(eglQueryString), |
| FUNCTION(eglQuerySurface), |
| FUNCTION(eglReleaseTexImage), |
| FUNCTION(eglReleaseThread), |
| FUNCTION(eglSurfaceAttrib), |
| FUNCTION(eglSwapBuffers), |
| FUNCTION(eglSwapInterval), |
| FUNCTION(eglTerminate), |
| FUNCTION(eglWaitClient), |
| FUNCTION(eglWaitGL), |
| FUNCTION(eglWaitNative), |
| FUNCTION(eglWaitSync), |
| FUNCTION(eglWaitSyncKHR), |
| |
| #undef FUNCTION |
| }; |
| |
| static const size_t numFunctions = sizeof eglFunctions / sizeof(Function); |
| static const Function *const eglFunctionsEnd = eglFunctions + numFunctions; |
| |
| Function needle; |
| needle.name = procname; |
| |
| if(procname && strncmp("egl", procname, 3) == 0) |
| { |
| const Function *result = std::lower_bound(eglFunctions, eglFunctionsEnd, needle, CompareFunctor()); |
| if (result != eglFunctionsEnd && strcmp(procname, result->name) == 0) |
| { |
| return success((__eglMustCastToProperFunctionPointerType)result->address); |
| } |
| } |
| |
| if(libGLESv2) |
| { |
| __eglMustCastToProperFunctionPointerType proc = libGLESv2->es2GetProcAddress(procname); |
| if(proc) return success(proc); |
| } |
| |
| if(libGLES_CM) |
| { |
| __eglMustCastToProperFunctionPointerType proc = libGLES_CM->es1GetProcAddress(procname); |
| if(proc) return success(proc); |
| } |
| |
| return success((__eglMustCastToProperFunctionPointerType)NULL); |
| } |
| } |