Apply the Apache 2.0 license. Change-Id: I4a7aeefedcd2d891093520d5a10ebefadcddb5be Reviewed-on: https://swiftshader-review.googlesource.com/5320 Reviewed-by: Nicolas Capens <capn@google.com> Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libEGL/libEGL.cpp b/src/OpenGL/libEGL/libEGL.cpp index b626562..7a801d9 100644 --- a/src/OpenGL/libEGL/libEGL.cpp +++ b/src/OpenGL/libEGL/libEGL.cpp
@@ -1,1187 +1,1190 @@ -// SwiftShader Software Renderer -// -// Copyright(c) 2005-2012 TransGaming Inc. -// -// All rights reserved. No part of this software may be copied, distributed, transmitted, -// transcribed, stored in a retrieval system, translated into any human or computer -// language by any means, or disclosed to third parties without the explicit written -// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express -// or implied, including but not limited to any patent rights, are granted to you. -// - -// libEGL.cpp: Implements the exported EGL functions. - -#include "main.h" -#include "Display.h" -#include "Surface.h" -#include "Texture.hpp" -#include "Context.hpp" -#include "common/Image.hpp" -#include "common/debug.h" -#include "Common/Version.h" - -#if defined(__ANDROID__) -#include <system/window.h> -#elif defined(__linux__) -#include "Main/libX11.hpp" -#endif - -#include <string.h> - -using namespace egl; - -static 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; -} - -static bool validateConfig(egl::Display *display, EGLConfig config) -{ - if(!validateDisplay(display)) - { - return false; - } - - if(!display->isValidConfig(config)) - { - return error(EGL_BAD_CONFIG, false); - } - - return true; -} - -static 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; -} - -static 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; -} - -namespace egl -{ -EGLint GetError(void) -{ - TRACE("()"); - - EGLint error = egl::getCurrentError(); - - if(error != EGL_SUCCESS) - { - egl::setCurrentError(EGL_SUCCESS); - } - - return error; -} - -EGLDisplay 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(!libX11) - { - return success(HEADLESS_DISPLAY); - } - #endif - - return success(PRIMARY_DISPLAY); // We only support the default display -} - -EGLBoolean Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor) -{ - TRACE("(EGLDisplay dpy = %p, EGLint *major = %p, EGLint *minor = %p)", - dpy, major, minor); - - if(dpy == EGL_NO_DISPLAY) - { - return error(EGL_BAD_DISPLAY, EGL_FALSE); - } - - egl::Display *display = egl::Display::get(dpy); - - if(!display->initialize()) - { - return error(EGL_NOT_INITIALIZED, EGL_FALSE); - } - - if(major) *major = 1; - if(minor) *minor = 4; - - return success(EGL_TRUE); -} - -EGLBoolean 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); - - display->terminate(); - - return success(EGL_TRUE); -} - -const char *QueryString(EGLDisplay dpy, EGLint name) -{ - TRACE("(EGLDisplay dpy = %p, EGLint name = %d)", dpy, name); - - #if defined(__linux__) && !defined(__ANDROID__) - if(dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) - { - return success("EGL_KHR_platform_gbm " - "EGL_KHR_platform_x11 " - "EGL_EXT_client_extensions " - "EGL_EXT_platform_base"); - } - #endif - - egl::Display *display = egl::Display::get(dpy); - - if(!validateDisplay(display)) - { - return NULL; - } - - switch(name) - { - case EGL_CLIENT_APIS: - return success("OpenGL_ES"); - case EGL_EXTENSIONS: - return success("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_ANDROID_framebuffer_target " - "EGL_ANDROID_recordable"); - case EGL_VENDOR: - return success("TransGaming Inc."); - case EGL_VERSION: - return success("1.4 SwiftShader " VERSION_STRING); - } - - return error(EGL_BAD_PARAMETER, (const char*)NULL); -} - -EGLBoolean 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); - - 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 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); - - 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 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); - - 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 CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType window, const EGLint *attrib_list) -{ - TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativeWindowType win = %p, " - "const EGLint *attrib_list = %p)", dpy, config, window, attrib_list); - - egl::Display *display = egl::Display::get(dpy); - - if(!validateConfig(display, config)) - { - return EGL_NO_SURFACE; - } - - if(!display->isValidWindow(window)) - { - return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); - } - - return display->createWindowSurface(window, config, attrib_list); -} - -EGLSurface 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); - - if(!validateConfig(display, config)) - { - return EGL_NO_SURFACE; - } - - return display->createPBufferSurface(config, attrib_list); -} - -EGLSurface 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); - - egl::Display *display = egl::Display::get(dpy); - - if(!validateConfig(display, config)) - { - return EGL_NO_SURFACE; - } - - UNIMPLEMENTED(); // FIXME - - return success(EGL_NO_SURFACE); -} - -EGLBoolean 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); - - 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 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; - - 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: - UNIMPLEMENTED(); // FIXME - break; - case EGL_VG_COLORSPACE: - UNIMPLEMENTED(); // FIXME - break; - case EGL_CONFIG_ID: - *value = eglSurface->getConfigID(); - break; - case EGL_HEIGHT: - *value = eglSurface->getHeight(); - break; - case EGL_HORIZONTAL_RESOLUTION: - UNIMPLEMENTED(); // FIXME - 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: - UNIMPLEMENTED(); // FIXME - break; - case EGL_MIPMAP_LEVEL: - UNIMPLEMENTED(); // FIXME - break; - case EGL_MULTISAMPLE_RESOLVE: - UNIMPLEMENTED(); // FIXME - 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: - *value = eglSurface->getTextureFormat(); - break; - case EGL_TEXTURE_TARGET: - *value = eglSurface->getTextureTarget(); - break; - case EGL_VERTICAL_RESOLUTION: - UNIMPLEMENTED(); // FIXME - break; - case EGL_WIDTH: - *value = eglSurface->getWidth(); - break; - default: - return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); - } - - return success(EGL_TRUE); -} - -EGLBoolean 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 QueryAPI(void) -{ - TRACE("()"); - - EGLenum API = egl::getCurrentAPI(); - - return success(API); -} - -EGLBoolean WaitClient(void) -{ - TRACE("()"); - - UNIMPLEMENTED(); // FIXME - - return success(EGL_FALSE); -} - -EGLBoolean ReleaseThread(void) -{ - TRACE("()"); - - eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); - - return success(EGL_TRUE); -} - -EGLSurface 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); - - UNIMPLEMENTED(); - - return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); -} - -EGLBoolean 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); - - if(!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - switch(attribute) - { - case EGL_SWAP_BEHAVIOR: - if(value == EGL_BUFFER_PRESERVED) - { - if(!(eglSurface->getSurfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)) - { - return error(EGL_BAD_MATCH, EGL_FALSE); - } - } - else if(value != EGL_BUFFER_DESTROYED) - { - return error(EGL_BAD_PARAMETER, EGL_FALSE); - } - eglSurface->setSwapBehavior(value); - break; - default: - UNIMPLEMENTED(); // FIXME - } - - return success(EGL_TRUE); -} - -EGLBoolean 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); - - 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 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); - - 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 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(); - - 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 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 clientVersion = 1; - if(attrib_list) - { - for(const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) - { - if(attribute[0] == EGL_CONTEXT_CLIENT_VERSION) - { - clientVersion = attribute[1]; - } - else - { - return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); - } - } - } - - egl::Display *display = egl::Display::get(dpy); - egl::Context *shareContext = static_cast<egl::Context*>(share_context); - - if(!validateConfig(display, config)) - { - return EGL_NO_CONTEXT; - } - - if(shareContext && shareContext->getClientVersion() != clientVersion) - { - return error(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); - } - - return display->createContext(config, shareContext, clientVersion); -} - -EGLBoolean 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); - - 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 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); - - 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::setCurrentDisplay(dpy); - egl::setCurrentDrawSurface(drawSurface); - egl::setCurrentReadSurface(readSurface); - egl::setCurrentContext(context); - - if(context) - { - context->makeCurrent(drawSurface); - } - - return success(EGL_TRUE); -} - -EGLContext GetCurrentContext(void) -{ - TRACE("()"); - - EGLContext context = egl::getCurrentContext(); - - return success(context); -} - -EGLSurface 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 GetCurrentDisplay(void) -{ - TRACE("()"); - - return success(egl::getCurrentDisplay()); -} - -EGLBoolean 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); - - if(!validateContext(display, context)) - { - return EGL_FALSE; - } - - UNIMPLEMENTED(); // FIXME - - return success(0); -} - -EGLBoolean WaitGL(void) -{ - TRACE("()"); - - UNIMPLEMENTED(); // FIXME - - return success(EGL_FALSE); -} - -EGLBoolean WaitNative(EGLint engine) -{ - TRACE("(EGLint engine = %d)", engine); - - UNIMPLEMENTED(); // FIXME - - return success(EGL_FALSE); -} - -EGLBoolean 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; - - 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 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); - - if(!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - UNIMPLEMENTED(); // FIXME - - return success(EGL_FALSE); -} - -EGLImageKHR 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); - - egl::Display *display = egl::Display::get(dpy); - egl::Context *context = static_cast<egl::Context*>(ctx); - - 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; - GLuint textureLevel = 0; - if(attrib_list) - { - for(const EGLint *attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) - { - if(attribute[0] == EGL_IMAGE_PRESERVED_KHR) - { - imagePreserved = attribute[1]; - } - else if(attribute[0] == EGL_GL_TEXTURE_LEVEL_KHR) - { - textureLevel = attribute[1]; - } - else - { - return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR); - } - } - } - - #if defined(__ANDROID__) - if(target == EGL_NATIVE_BUFFER_ANDROID) - { - ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(buffer); - - if(!nativeBuffer || GLPixelFormatFromAndroid(nativeBuffer->format) == GL_NONE) - { - ALOGW("%s badness unsupported HAL format=%x", __FUNCTION__, nativeBuffer ? nativeBuffer->format : 0); - return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR); - } - - return success(new AndroidNativeImage(nativeBuffer)); - } - #endif - - GLuint name = reinterpret_cast<intptr_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); - } - - egl::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); - } - - return success((EGLImageKHR)image); -} - -EGLBoolean DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) -{ - TRACE("(EGLDisplay dpy = %p, EGLImageKHR image = %p)", dpy, image); - - egl::Display *display = egl::Display::get(dpy); - - if(!validateDisplay(display)) - { - return error(EGL_BAD_DISPLAY, EGL_FALSE); - } - - if(!image) - { - return error(EGL_BAD_PARAMETER, EGL_FALSE); - } - - egl::Image *glImage = static_cast<egl::Image*>(image); - glImage->destroyShared(); - - return success(EGL_TRUE); -} - -EGLDisplay 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); - - switch(platform) - { - #if defined(__linux__) && !defined(__ANDROID__) - case EGL_PLATFORM_X11_EXT: break; - case EGL_PLATFORM_GBM_KHR: break; - #endif - default: - return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); - } - - #if defined(__linux__) && !defined(__ANDROID__) - if(platform == EGL_PLATFORM_X11_EXT) - { - if(!libX11) - { - return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); - } - - if(native_display != (void*)EGL_DEFAULT_DISPLAY || attrib_list != NULL) - { - return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented - } - } - else if(platform == EGL_PLATFORM_GBM_KHR) - { - if(native_display != (void*)EGL_DEFAULT_DISPLAY || attrib_list != NULL) - { - return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented - } - - return success(HEADLESS_DISPLAY); - } - #endif - - return success(PRIMARY_DISPLAY); // We only support the default display -} - -EGLSurface CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list) -{ - return CreateWindowSurface(dpy, config, (EGLNativeWindowType)native_window, attrib_list); -} - -EGLSurface CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list) -{ - return CreatePixmapSurface(dpy, config, (EGLNativePixmapType)native_pixmap, attrib_list); -} - -EGLSyncKHR CreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) -{ - TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLint *attrib_list=%p)", dpy, type, attrib_list); - - egl::Display *display = egl::Display::get(dpy); - - 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); -} - -EGLBoolean 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); - - 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 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); - - 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 GetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) -{ - TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint attribute = %x, EGLint *value = %p)", dpy, sync, attribute, value); - - egl::Display *display = egl::Display::get(dpy); - FenceSync *eglSync = static_cast<FenceSync*>(sync); - - if(!validateDisplay(display)) - { - return error(EGL_BAD_DISPLAY, EGL_FALSE); - } - - if(!display->isValidSync(eglSync)) - { - 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); - } -} - -__eglMustCastToProperFunctionPointerType GetProcAddress(const char *procname) -{ - TRACE("(const char *procname = \"%s\")", procname); - - struct Extension - { - const char *name; - __eglMustCastToProperFunctionPointerType address; - }; - - static const Extension eglExtensions[] = - { - #define EXTENSION(name) {#name, (__eglMustCastToProperFunctionPointerType)name} - - EXTENSION(eglCreateImageKHR), - EXTENSION(eglDestroyImageKHR), - EXTENSION(eglGetPlatformDisplayEXT), - EXTENSION(eglCreatePlatformWindowSurfaceEXT), - EXTENSION(eglCreatePlatformPixmapSurfaceEXT), - EXTENSION(eglCreateSyncKHR), - EXTENSION(eglDestroySyncKHR), - EXTENSION(eglClientWaitSyncKHR), - EXTENSION(eglGetSyncAttribKHR), - - #undef EXTENSION - }; - - for(unsigned int ext = 0; ext < sizeof(eglExtensions) / sizeof(Extension); ext++) - { - if(strcmp(procname, eglExtensions[ext].name) == 0) - { - return success((__eglMustCastToProperFunctionPointerType)eglExtensions[ext].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); -} -} +// 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.h" +#include "Texture.hpp" +#include "Context.hpp" +#include "common/Image.hpp" +#include "common/debug.h" +#include "Common/Version.h" + +#if defined(__ANDROID__) +#include <system/window.h> +#elif defined(__linux__) +#include "Main/libX11.hpp" +#endif + +#include <string.h> + +using namespace egl; + +static 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; +} + +static bool validateConfig(egl::Display *display, EGLConfig config) +{ + if(!validateDisplay(display)) + { + return false; + } + + if(!display->isValidConfig(config)) + { + return error(EGL_BAD_CONFIG, false); + } + + return true; +} + +static 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; +} + +static 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; +} + +namespace egl +{ +EGLint GetError(void) +{ + TRACE("()"); + + EGLint error = egl::getCurrentError(); + + if(error != EGL_SUCCESS) + { + egl::setCurrentError(EGL_SUCCESS); + } + + return error; +} + +EGLDisplay 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(!libX11) + { + return success(HEADLESS_DISPLAY); + } + #endif + + return success(PRIMARY_DISPLAY); // We only support the default display +} + +EGLBoolean Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + TRACE("(EGLDisplay dpy = %p, EGLint *major = %p, EGLint *minor = %p)", + dpy, major, minor); + + if(dpy == EGL_NO_DISPLAY) + { + return error(EGL_BAD_DISPLAY, EGL_FALSE); + } + + egl::Display *display = egl::Display::get(dpy); + + if(!display->initialize()) + { + return error(EGL_NOT_INITIALIZED, EGL_FALSE); + } + + if(major) *major = 1; + if(minor) *minor = 4; + + return success(EGL_TRUE); +} + +EGLBoolean 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); + + display->terminate(); + + return success(EGL_TRUE); +} + +const char *QueryString(EGLDisplay dpy, EGLint name) +{ + TRACE("(EGLDisplay dpy = %p, EGLint name = %d)", dpy, name); + + #if defined(__linux__) && !defined(__ANDROID__) + if(dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) + { + return success("EGL_KHR_platform_gbm " + "EGL_KHR_platform_x11 " + "EGL_EXT_client_extensions " + "EGL_EXT_platform_base"); + } + #endif + + egl::Display *display = egl::Display::get(dpy); + + if(!validateDisplay(display)) + { + return nullptr; + } + + switch(name) + { + case EGL_CLIENT_APIS: + return success("OpenGL_ES"); + case EGL_EXTENSIONS: + return success("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_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 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); + + 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 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); + + 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 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); + + 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 CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType window, const EGLint *attrib_list) +{ + TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativeWindowType win = %p, " + "const EGLint *attrib_list = %p)", dpy, config, window, attrib_list); + + egl::Display *display = egl::Display::get(dpy); + + if(!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + if(!display->isValidWindow(window)) + { + return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + + return display->createWindowSurface(window, config, attrib_list); +} + +EGLSurface 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); + + if(!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + return display->createPBufferSurface(config, attrib_list); +} + +EGLSurface 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); + + egl::Display *display = egl::Display::get(dpy); + + if(!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_NO_SURFACE); +} + +EGLBoolean 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); + + 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 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; + + 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: + UNIMPLEMENTED(); // FIXME + break; + case EGL_VG_COLORSPACE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_CONFIG_ID: + *value = eglSurface->getConfigID(); + break; + case EGL_HEIGHT: + *value = eglSurface->getHeight(); + break; + case EGL_HORIZONTAL_RESOLUTION: + UNIMPLEMENTED(); // FIXME + 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: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MIPMAP_LEVEL: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MULTISAMPLE_RESOLVE: + UNIMPLEMENTED(); // FIXME + 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: + *value = eglSurface->getTextureFormat(); + break; + case EGL_TEXTURE_TARGET: + *value = eglSurface->getTextureTarget(); + break; + case EGL_VERTICAL_RESOLUTION: + UNIMPLEMENTED(); // FIXME + break; + case EGL_WIDTH: + *value = eglSurface->getWidth(); + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); +} + +EGLBoolean 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 QueryAPI(void) +{ + TRACE("()"); + + EGLenum API = egl::getCurrentAPI(); + + return success(API); +} + +EGLBoolean WaitClient(void) +{ + TRACE("()"); + + UNIMPLEMENTED(); // FIXME + + return success(EGL_FALSE); +} + +EGLBoolean ReleaseThread(void) +{ + TRACE("()"); + + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); + + return success(EGL_TRUE); +} + +EGLSurface 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); + + UNIMPLEMENTED(); + + return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); +} + +EGLBoolean 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); + + if(!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + switch(attribute) + { + case EGL_SWAP_BEHAVIOR: + if(value == EGL_BUFFER_PRESERVED) + { + if(!(eglSurface->getSurfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)) + { + return error(EGL_BAD_MATCH, EGL_FALSE); + } + } + else if(value != EGL_BUFFER_DESTROYED) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + eglSurface->setSwapBehavior(value); + break; + default: + UNIMPLEMENTED(); // FIXME + } + + return success(EGL_TRUE); +} + +EGLBoolean 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); + + 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 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); + + 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 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(); + + 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 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 clientVersion = 1; + if(attrib_list) + { + for(const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) + { + if(attribute[0] == EGL_CONTEXT_CLIENT_VERSION) + { + clientVersion = attribute[1]; + } + else + { + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + } + } + } + + egl::Display *display = egl::Display::get(dpy); + egl::Context *shareContext = static_cast<egl::Context*>(share_context); + + if(!validateConfig(display, config)) + { + return EGL_NO_CONTEXT; + } + + if(shareContext && shareContext->getClientVersion() != clientVersion) + { + return error(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); + } + + return display->createContext(config, shareContext, clientVersion); +} + +EGLBoolean 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); + + 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 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); + + 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::setCurrentDisplay(dpy); + egl::setCurrentDrawSurface(drawSurface); + egl::setCurrentReadSurface(readSurface); + egl::setCurrentContext(context); + + if(context) + { + context->makeCurrent(drawSurface); + } + + return success(EGL_TRUE); +} + +EGLContext GetCurrentContext(void) +{ + TRACE("()"); + + EGLContext context = egl::getCurrentContext(); + + return success(context); +} + +EGLSurface 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 GetCurrentDisplay(void) +{ + TRACE("()"); + + return success(egl::getCurrentDisplay()); +} + +EGLBoolean 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); + + if(!validateContext(display, context)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(0); +} + +EGLBoolean WaitGL(void) +{ + TRACE("()"); + + UNIMPLEMENTED(); // FIXME + + return success(EGL_FALSE); +} + +EGLBoolean WaitNative(EGLint engine) +{ + TRACE("(EGLint engine = %d)", engine); + + UNIMPLEMENTED(); // FIXME + + return success(EGL_FALSE); +} + +EGLBoolean 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; + + 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 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); + + if(!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_FALSE); +} + +EGLImageKHR 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); + + egl::Display *display = egl::Display::get(dpy); + egl::Context *context = static_cast<egl::Context*>(ctx); + + 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; + GLuint textureLevel = 0; + if(attrib_list) + { + for(const EGLint *attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) + { + if(attribute[0] == EGL_IMAGE_PRESERVED_KHR) + { + imagePreserved = attribute[1]; + } + else if(attribute[0] == EGL_GL_TEXTURE_LEVEL_KHR) + { + textureLevel = attribute[1]; + } + else + { + return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR); + } + } + } + + #if defined(__ANDROID__) + if(target == EGL_NATIVE_BUFFER_ANDROID) + { + ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(buffer); + + if(!nativeBuffer || GLPixelFormatFromAndroid(nativeBuffer->format) == GL_NONE) + { + ALOGW("%s badness unsupported HAL format=%x", __FUNCTION__, nativeBuffer ? nativeBuffer->format : 0); + return error(EGL_BAD_ATTRIBUTE, EGL_NO_IMAGE_KHR); + } + + return success(new AndroidNativeImage(nativeBuffer)); + } + #endif + + GLuint name = reinterpret_cast<intptr_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); + } + + egl::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); + } + + return success((EGLImageKHR)image); +} + +EGLBoolean DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) +{ + TRACE("(EGLDisplay dpy = %p, EGLImageKHR image = %p)", dpy, image); + + egl::Display *display = egl::Display::get(dpy); + + if(!validateDisplay(display)) + { + return error(EGL_BAD_DISPLAY, EGL_FALSE); + } + + if(!image) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + egl::Image *glImage = static_cast<egl::Image*>(image); + glImage->destroyShared(); + + return success(EGL_TRUE); +} + +EGLDisplay 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); + + switch(platform) + { + #if defined(__linux__) && !defined(__ANDROID__) + case EGL_PLATFORM_X11_EXT: break; + case EGL_PLATFORM_GBM_KHR: break; + #endif + default: + return error(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); + } + + #if defined(__linux__) && !defined(__ANDROID__) + if(platform == EGL_PLATFORM_X11_EXT) + { + if(!libX11) + { + return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); + } + + if(native_display != (void*)EGL_DEFAULT_DISPLAY || attrib_list != NULL) + { + return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented + } + } + else if(platform == EGL_PLATFORM_GBM_KHR) + { + if(native_display != (void*)EGL_DEFAULT_DISPLAY || attrib_list != NULL) + { + return error(EGL_BAD_ATTRIBUTE, EGL_NO_DISPLAY); // Unimplemented + } + + return success(HEADLESS_DISPLAY); + } + #endif + + return success(PRIMARY_DISPLAY); // We only support the default display +} + +EGLSurface CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list) +{ + return CreateWindowSurface(dpy, config, (EGLNativeWindowType)native_window, attrib_list); +} + +EGLSurface CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list) +{ + return CreatePixmapSurface(dpy, config, (EGLNativePixmapType)native_pixmap, attrib_list); +} + +EGLSyncKHR CreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) +{ + TRACE("(EGLDisplay dpy = %p, EGLunum type = %x, EGLint *attrib_list=%p)", dpy, type, attrib_list); + + egl::Display *display = egl::Display::get(dpy); + + 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); +} + +EGLBoolean 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); + + 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 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); + + 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 GetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) +{ + TRACE("(EGLDisplay dpy = %p, EGLSyncKHR sync = %p, EGLint attribute = %x, EGLint *value = %p)", dpy, sync, attribute, value); + + egl::Display *display = egl::Display::get(dpy); + FenceSync *eglSync = static_cast<FenceSync*>(sync); + + if(!validateDisplay(display)) + { + return error(EGL_BAD_DISPLAY, EGL_FALSE); + } + + if(!display->isValidSync(eglSync)) + { + 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); + } +} + +__eglMustCastToProperFunctionPointerType GetProcAddress(const char *procname) +{ + TRACE("(const char *procname = \"%s\")", procname); + + struct Extension + { + const char *name; + __eglMustCastToProperFunctionPointerType address; + }; + + static const Extension eglExtensions[] = + { + #define EXTENSION(name) {#name, (__eglMustCastToProperFunctionPointerType)name} + + EXTENSION(eglCreateImageKHR), + EXTENSION(eglDestroyImageKHR), + EXTENSION(eglGetPlatformDisplayEXT), + EXTENSION(eglCreatePlatformWindowSurfaceEXT), + EXTENSION(eglCreatePlatformPixmapSurfaceEXT), + EXTENSION(eglCreateSyncKHR), + EXTENSION(eglDestroySyncKHR), + EXTENSION(eglClientWaitSyncKHR), + EXTENSION(eglGetSyncAttribKHR), + + #undef EXTENSION + }; + + for(unsigned int ext = 0; ext < sizeof(eglExtensions) / sizeof(Extension); ext++) + { + if(strcmp(procname, eglExtensions[ext].name) == 0) + { + return success((__eglMustCastToProperFunctionPointerType)eglExtensions[ext].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); +} +}