/* * Copyright (C) 2011 The Android Open Source Project * * 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. */ #ifdef _WIN32 #undef EGLAPI #define EGLAPI __declspec(dllexport) #endif #include <EGL/egl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include "ThreadInfo.h" #include <GLcommon/TranslatorIfaces.h> #include <OpenglOsUtils/osDynLibrary.h> #include "EglWindowSurface.h" #include "EglPbufferSurface.h" #include "EglPixmapSurface.h" #include "EglGlobalInfo.h" #include "EglThreadInfo.h" #include "EglValidate.h" #include "EglDisplay.h" #include "EglContext.h" #include "EglConfig.h" #include "EglOsApi.h" #include "ClientAPIExts.h" #define MAJOR 1 #define MINOR 4 //declarations EglImage *attachEGLImage(unsigned int imageId); void detachEGLImage(unsigned int imageId); GLEScontext* getGLESContext(); #define tls_thread EglThreadInfo::get() EglGlobalInfo* g_eglInfo = NULL; android::Mutex s_eglLock; void initGlobalInfo() { android::Mutex::Autolock mutex(s_eglLock); if (!g_eglInfo) { g_eglInfo = EglGlobalInfo::getInstance(); } } static EGLiface s_eglIface = { getGLESContext : getGLESContext, eglAttachEGLImage:attachEGLImage, eglDetachEGLImage:detachEGLImage }; /***************************************** supported extentions ***********************************************************************/ //extentions #define EGL_EXTENTIONS 2 //decleration EGLImageKHR eglCreateImageKHR(EGLDisplay display, EGLContext context, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); EGLBoolean eglDestroyImageKHR(EGLDisplay display, EGLImageKHR image); // extentions descriptors static ExtentionDescriptor s_eglExtentions[] = { {"eglCreateImageKHR" ,(__eglMustCastToProperFunctionPointerType)eglCreateImageKHR}, {"eglDestroyImageKHR",(__eglMustCastToProperFunctionPointerType)eglDestroyImageKHR} }; static int s_eglExtentionsSize = sizeof(s_eglExtentions) / sizeof(ExtentionDescriptor); /****************************************************************************************************************************************/ //macros for accessing global egl info & tls objects #define CURRENT_THREAD() do {} while (0); #define RETURN_ERROR(ret,err) \ CURRENT_THREAD() \ if(tls_thread->getError() == EGL_SUCCESS) { \ tls_thread->setError(err); \ } \ return ret; #define VALIDATE_DISPLAY_RETURN(EGLDisplay,ret) \ EglDisplay* dpy = g_eglInfo->getDisplay(EGLDisplay); \ if(!dpy){ \ RETURN_ERROR(ret,EGL_BAD_DISPLAY); \ } \ if(!dpy->isInitialize()) { \ RETURN_ERROR(ret,EGL_NOT_INITIALIZED); \ } #define VALIDATE_CONFIG_RETURN(EGLConfig,ret) \ EglConfig* cfg = dpy->getConfig(EGLConfig); \ if(!cfg) { \ RETURN_ERROR(ret,EGL_BAD_CONFIG); \ } #define VALIDATE_SURFACE_RETURN(EGLSurface,ret,varName) \ SurfacePtr varName = dpy->getSurface(EGLSurface); \ if(!varName.Ptr()) { \ RETURN_ERROR(ret,EGL_BAD_SURFACE); \ } #define VALIDATE_CONTEXT_RETURN(EGLContext,ret) \ ContextPtr ctx = dpy->getContext(EGLContext); \ if(!ctx.Ptr()) { \ RETURN_ERROR(ret,EGL_BAD_CONTEXT); \ } #define VALIDATE_DISPLAY(EGLDisplay) \ VALIDATE_DISPLAY_RETURN(EGLDisplay,EGL_FALSE) #define VALIDATE_CONFIG(EGLConfig) \ VALIDATE_CONFIG_RETURN(EGLConfig,EGL_FALSE) #define VALIDATE_SURFACE(EGLSurface,varName) \ VALIDATE_SURFACE_RETURN(EGLSurface,EGL_FALSE,varName) #define VALIDATE_CONTEXT(EGLContext) \ VALIDATE_CONTEXT_RETURN(EGLContext,EGL_FALSE) GLEScontext* getGLESContext() { ThreadInfo* thread = getThreadInfo(); return thread->glesContext; } EGLAPI EGLint EGLAPIENTRY eglGetError(void) { CURRENT_THREAD(); EGLint err = tls_thread->getError(); tls_thread->setError(EGL_SUCCESS); return err; } EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id) { EglDisplay* dpy = NULL; EGLNativeInternalDisplayType internalDisplay = NULL; initGlobalInfo(); if ((dpy = g_eglInfo->getDisplay(display_id))) { return dpy; } else { if( display_id == EGL_DEFAULT_DISPLAY) { internalDisplay = g_eglInfo->getDefaultNativeDisplay(); } else { internalDisplay = g_eglInfo->generateInternalDisplay(display_id); } dpy = g_eglInfo->addDisplay(display_id,internalDisplay); if(dpy) return dpy; return EGL_NO_DISPLAY; } } #define TRANSLATOR_GETIFACE_NAME "__translator_getIfaces" static __translator_getGLESIfaceFunc loadIfaces(const char* libName){ osUtils::dynLibrary* libGLES = osUtils::dynLibrary::open(libName); if(!libGLES) return NULL; __translator_getGLESIfaceFunc func = (__translator_getGLESIfaceFunc)libGLES->findSymbol(TRANSLATOR_GETIFACE_NAME); if(!func) return NULL; return func; } #define LIB_GLES_CM_NAME EMUGL_LIBNAME("GLES_CM_translator") #define LIB_GLES_V2_NAME EMUGL_LIBNAME("GLES_V2_translator") EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay display, EGLint *major, EGLint *minor) { initGlobalInfo(); EglDisplay* dpy = g_eglInfo->getDisplay(display); if(!dpy) { RETURN_ERROR(EGL_FALSE,EGL_BAD_DISPLAY); } if(major) *major = MAJOR; if(minor) *minor = MINOR; __translator_getGLESIfaceFunc func = NULL; int renderableType = EGL_OPENGL_ES_BIT; if(!g_eglInfo->getIface(GLES_1_1)) { func = loadIfaces(LIB_GLES_CM_NAME); if(func){ g_eglInfo->setIface(func(&s_eglIface),GLES_1_1); } else { fprintf(stderr,"could not find ifaces for GLES CM 1.1\n"); return EGL_FALSE; } } if(!g_eglInfo->getIface(GLES_2_0)) { func = loadIfaces(LIB_GLES_V2_NAME); if(func){ renderableType |= EGL_OPENGL_ES2_BIT; g_eglInfo->setIface(func(&s_eglIface),GLES_2_0); } else { fprintf(stderr,"could not find ifaces for GLES 2.0\n"); } } dpy->initialize(renderableType); return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay display) { VALIDATE_DISPLAY(display); dpy->terminate(); return EGL_TRUE; } EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay display, EGLint name) { VALIDATE_DISPLAY(display); static const char* vendor = "Google"; static const char* version = "1.4"; static const char* extensions = "EGL_KHR_image_base EGL_KHR_gl_texture_2D_image"; if(!EglValidate::stringName(name)) { RETURN_ERROR(NULL,EGL_BAD_PARAMETER); } switch(name) { case EGL_VENDOR: return vendor; case EGL_VERSION: return version; case EGL_EXTENSIONS: return extensions; } return NULL; } EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay display, EGLConfig *configs, EGLint config_size, EGLint *num_config) { VALIDATE_DISPLAY(display); if(!num_config) { RETURN_ERROR(EGL_FALSE,EGL_BAD_PARAMETER); } if(configs == NULL) { *num_config = dpy->nConfigs(); } else { *num_config = dpy->getConfigs(configs,config_size); } return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay display, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) { VALIDATE_DISPLAY(display); if(!num_config) { RETURN_ERROR(EGL_FALSE,EGL_BAD_PARAMETER); } //selection defaults EGLint surface_type = EGL_WINDOW_BIT; EGLint renderable_type = EGL_OPENGL_ES_BIT; EGLBoolean bind_to_tex_rgb = EGL_DONT_CARE; EGLBoolean bind_to_tex_rgba = EGL_DONT_CARE; EGLenum caveat = EGL_DONT_CARE; EGLint config_id = EGL_DONT_CARE; EGLBoolean native_renderable = EGL_DONT_CARE; EGLint native_visual_type = EGL_DONT_CARE; EGLint max_swap_interval = EGL_DONT_CARE; EGLint min_swap_interval = EGL_DONT_CARE; EGLint trans_red_val = EGL_DONT_CARE; EGLint trans_green_val = EGL_DONT_CARE; EGLint trans_blue_val = EGL_DONT_CARE; EGLenum transparent_type = EGL_NONE; EGLint buffer_size = 0; EGLint red_size = 0; EGLint green_size = 0; EGLint blue_size = 0; EGLint alpha_size = 0; EGLint depth_size = 0; EGLint frame_buffer_level = 0; EGLint sample_buffers_num = 0; EGLint samples_per_pixel = 0; EGLint stencil_size = 0; if(!EglValidate::noAttribs(attrib_list)) { //there are attribs int i = 0 ; bool hasConfigId = false; while(attrib_list[i] != EGL_NONE && !hasConfigId) { switch(attrib_list[i]) { case EGL_MAX_PBUFFER_WIDTH: case EGL_MAX_PBUFFER_HEIGHT: case EGL_MAX_PBUFFER_PIXELS: case EGL_NATIVE_VISUAL_ID: break; //we dont care from those selection crateria case EGL_LEVEL: if(attrib_list[i+1] == EGL_DONT_CARE) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } frame_buffer_level = attrib_list[i+1]; break; case EGL_BUFFER_SIZE: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } buffer_size = attrib_list[i+1]; break; case EGL_RED_SIZE: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } red_size = attrib_list[i+1]; break; case EGL_GREEN_SIZE: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } green_size = attrib_list[i+1]; break; case EGL_BLUE_SIZE: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } blue_size = attrib_list[i+1]; break; case EGL_ALPHA_SIZE: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } alpha_size = attrib_list[i+1]; break; case EGL_BIND_TO_TEXTURE_RGB: bind_to_tex_rgb = attrib_list[i+1]; break; case EGL_BIND_TO_TEXTURE_RGBA: bind_to_tex_rgba = attrib_list[i+1]; break; case EGL_CONFIG_CAVEAT: if(attrib_list[i+1] != EGL_NONE && attrib_list[i+1] != EGL_SLOW_CONFIG && attrib_list[i+1] != EGL_NON_CONFORMANT_CONFIG) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } caveat = attrib_list[i+1]; break; case EGL_CONFIG_ID: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } config_id = attrib_list[i+1]; hasConfigId = true; break; case EGL_DEPTH_SIZE: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } depth_size = attrib_list[i+1]; break; case EGL_MAX_SWAP_INTERVAL: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } max_swap_interval = attrib_list[i+1]; break; case EGL_MIN_SWAP_INTERVAL: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } min_swap_interval = attrib_list[i+1]; break; case EGL_NATIVE_RENDERABLE: native_renderable = attrib_list[i+1]; break; case EGL_RENDERABLE_TYPE: renderable_type = attrib_list[i+1]; break; case EGL_NATIVE_VISUAL_TYPE: native_visual_type = attrib_list[i+1]; break; if(attrib_list[i+1] < 0 || attrib_list[i+1] > 1 ) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } case EGL_SAMPLE_BUFFERS: sample_buffers_num = attrib_list[i+1]; break; if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } case EGL_SAMPLES: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } samples_per_pixel = attrib_list[i+1]; break; case EGL_STENCIL_SIZE: if(attrib_list[i+1] < 0) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } stencil_size = attrib_list[i+1]; break; case EGL_SURFACE_TYPE: surface_type = attrib_list[i+1]; break; case EGL_TRANSPARENT_TYPE: if(attrib_list[i+1] != EGL_NONE && attrib_list[i+1] != EGL_TRANSPARENT_RGB ) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } transparent_type = attrib_list[i+1]; break; case EGL_TRANSPARENT_RED_VALUE: trans_red_val = attrib_list[i+1]; break; case EGL_TRANSPARENT_GREEN_VALUE: trans_green_val = attrib_list[i+1]; break; case EGL_TRANSPARENT_BLUE_VALUE: trans_blue_val = attrib_list[i+1]; break; default: RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } i+=2; } if(hasConfigId) { EglConfig* pConfig = dpy->getConfig(config_id); if(pConfig) { if(configs) { configs[0] = static_cast<EGLConfig>(pConfig); } *num_config = 1; return EGL_TRUE; } else { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } } } EGLNativePixelFormatType tmpfrmt = PIXEL_FORMAT_INITIALIZER; EglConfig dummy(red_size,green_size,blue_size,alpha_size,caveat,config_id,depth_size, frame_buffer_level,0,0,0,native_renderable,renderable_type,0,native_visual_type, samples_per_pixel,stencil_size,surface_type,transparent_type, trans_red_val,trans_green_val,trans_blue_val,tmpfrmt); *num_config = dpy->chooseConfigs(dummy,configs,config_size); return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay display, EGLConfig config, EGLint attribute, EGLint *value) { VALIDATE_DISPLAY(display); VALIDATE_CONFIG(config); if(!EglValidate::confAttrib(attribute)){ RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } return cfg->getConfAttrib(attribute,value)? EGL_TRUE:EGL_FALSE; } EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay display, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) { VALIDATE_DISPLAY_RETURN(display,EGL_NO_SURFACE); VALIDATE_CONFIG_RETURN(config,EGL_NO_SURFACE); if(!(cfg->surfaceType() & EGL_WINDOW_BIT)) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_MATCH); } if(!EglOS::validNativeWin(dpy->nativeType(),win)) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_NATIVE_WINDOW); } if(!EglValidate::noAttribs(attrib_list)) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ATTRIBUTE); } if(EglWindowSurface::alreadyAssociatedWithConfig(win)) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ALLOC); } unsigned int width,height; if(!EglOS::checkWindowPixelFormatMatch(dpy->nativeType(),win,cfg,&width,&height)) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ALLOC); } SurfacePtr wSurface(new EglWindowSurface(dpy, win,cfg,width,height)); if(!wSurface.Ptr()) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ALLOC); } return dpy->addSurface(wSurface); } EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, const EGLint *attrib_list) { VALIDATE_DISPLAY_RETURN(display,EGL_NO_SURFACE); VALIDATE_CONFIG_RETURN(config,EGL_NO_SURFACE); if(!(cfg->surfaceType() & EGL_PBUFFER_BIT)) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_MATCH); } SurfacePtr pbSurface(new EglPbufferSurface(dpy,cfg)); if(!pbSurface.Ptr()) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ALLOC); } if(!EglValidate::noAttribs(attrib_list)) { //there are attribs int i = 0 ; while(attrib_list[i] != EGL_NONE) { if(!pbSurface->setAttrib(attrib_list[i],attrib_list[i+1])) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ATTRIBUTE); } i+=2; } } EGLint width,height,largest,texTarget,texFormat; EglPbufferSurface* tmpPbSurfacePtr = static_cast<EglPbufferSurface*>(pbSurface.Ptr()); tmpPbSurfacePtr->getDim(&width,&height,&largest); tmpPbSurfacePtr->getTexInfo(&texTarget,&texFormat); if(!EglValidate::pbufferAttribs(width,height,texFormat == EGL_NO_TEXTURE,texTarget == EGL_NO_TEXTURE)) { //TODO: RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_VALUE); dont have bad_value RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ATTRIBUTE); } EGLNativeSurfaceType pb = EglOS::createPbufferSurface(dpy->nativeType(),cfg,tmpPbSurfacePtr); if(!pb) { //TODO: RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_VALUE); dont have bad value RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ATTRIBUTE); } tmpPbSurfacePtr->setNativePbuffer(pb); return dpy->addSurface(pbSurface); } EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay display, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) { VALIDATE_DISPLAY_RETURN(display,EGL_NO_SURFACE); VALIDATE_CONFIG_RETURN(config,EGL_NO_SURFACE); if(!(cfg->surfaceType() & EGL_PIXMAP_BIT)) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_MATCH); } if(!EglValidate::noAttribs(attrib_list)) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ATTRIBUTE); } if(EglPixmapSurface::alreadyAssociatedWithConfig(pixmap)) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ALLOC); } unsigned int width,height; if(!EglOS::checkPixmapPixelFormatMatch(dpy->nativeType(),pixmap,cfg,&width,&height)) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ALLOC); } SurfacePtr pixSurface(new EglPixmapSurface(dpy, pixmap,cfg)); if(!pixSurface.Ptr()) { RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ALLOC); } return dpy->addSurface(pixSurface); } EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay display, EGLSurface surface) { VALIDATE_DISPLAY(display); SurfacePtr srfc = dpy->getSurface(surface); if(!srfc.Ptr()) { RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE); } dpy->removeSurface(surface); return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint *value) { VALIDATE_DISPLAY(display); VALIDATE_SURFACE(surface,srfc); if(!srfc->getAttrib(attribute,value)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint value) { VALIDATE_DISPLAY(display); VALIDATE_SURFACE(surface,srfc); if(!srfc->setAttrib(attribute,value)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } return EGL_TRUE; } EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) { VALIDATE_DISPLAY_RETURN(display,EGL_NO_CONTEXT); VALIDATE_CONFIG_RETURN(config,EGL_NO_CONTEXT); GLESVersion version = GLES_1_1; if(!EglValidate::noAttribs(attrib_list)) { int i = 0; while(attrib_list[i] != EGL_NONE) { switch(attrib_list[i]) { case EGL_CONTEXT_CLIENT_VERSION: if(attrib_list[i+1] == 2) { version = GLES_2_0; } else { version = GLES_1_1; } break; default: RETURN_ERROR(EGL_NO_CONTEXT,EGL_BAD_ATTRIBUTE); } i+=2; } } GLESiface* iface = g_eglInfo->getIface(version); GLEScontext* glesCtx = NULL; if(iface) { glesCtx = iface->createGLESContext(); } else { // there is no interface for this gles version RETURN_ERROR(EGL_NO_CONTEXT,EGL_BAD_ATTRIBUTE); } ContextPtr sharedCtxPtr; EGLNativeContextType nativeShared = NULL; if(share_context != EGL_NO_CONTEXT) { sharedCtxPtr = dpy->getContext(share_context); if(!sharedCtxPtr.Ptr()) { RETURN_ERROR(EGL_NO_CONTEXT,EGL_BAD_CONTEXT); } nativeShared = sharedCtxPtr->nativeType(); } EGLNativeContextType globalSharedContext = dpy->getGlobalSharedContext(); EGLNativeContextType nativeContext = EglOS::createContext(dpy->nativeType(),cfg,globalSharedContext); if(nativeContext) { ContextPtr ctx(new EglContext(dpy, nativeContext,sharedCtxPtr,cfg,glesCtx,version,dpy->getManager(version))); return dpy->addContext(ctx); } else { iface->deleteGLESContext(glesCtx); } return EGL_NO_CONTEXT; } EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay display, EGLContext context) { VALIDATE_DISPLAY(display); VALIDATE_CONTEXT(context); dpy->removeContext(context); return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context) { VALIDATE_DISPLAY(display); bool releaseContext = EglValidate::releaseContext(context,read,draw); if(!releaseContext && EglValidate::badContextMatch(context,read,draw)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_MATCH); } ThreadInfo* thread = getThreadInfo(); ContextPtr prevCtx = thread->eglContext; if(releaseContext) { //releasing current context if(prevCtx.Ptr()) { g_eglInfo->getIface(prevCtx->version())->flush(); if(!EglOS::makeCurrent(dpy->nativeType(),NULL,NULL,NULL)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ACCESS); } thread->updateInfo(ContextPtr(NULL),dpy,NULL,ShareGroupPtr(NULL),dpy->getManager(prevCtx->version())); } } else { //assining new context VALIDATE_CONTEXT(context); VALIDATE_SURFACE(draw,newDrawSrfc); VALIDATE_SURFACE(read,newReadSrfc); EglSurface* newDrawPtr = newDrawSrfc.Ptr(); EglSurface* newReadPtr = newReadSrfc.Ptr(); ContextPtr newCtx = ctx; if (newCtx.Ptr() && prevCtx.Ptr()) { if (newCtx.Ptr() == prevCtx.Ptr()) { if (newDrawPtr == prevCtx->draw().Ptr() && newReadPtr == prevCtx->read().Ptr()) { // nothing to do return EGL_TRUE; } } else { // Make sure previous context is detached from surfaces releaseContext = true; } } //surfaces compitability check if(!((*ctx->getConfig()).compitableWith((*newDrawPtr->getConfig()))) || !((*ctx->getConfig()).compitableWith((*newReadPtr->getConfig())))) { RETURN_ERROR(EGL_FALSE,EGL_BAD_MATCH); } EGLNativeInternalDisplayType nativeDisplay = dpy->nativeType(); EGLNativeSurfaceType nativeRead = newReadPtr->native(); EGLNativeSurfaceType nativeDraw = newDrawPtr->native(); //checking native window validity if(newReadPtr->type() == EglSurface::WINDOW && !EglOS::validNativeWin(nativeDisplay,nativeRead)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_NATIVE_WINDOW); } if(newDrawPtr->type() == EglSurface::WINDOW && !EglOS::validNativeWin(nativeDisplay,nativeDraw)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_NATIVE_WINDOW); } //checking native pixmap validity if(newReadPtr->type() == EglSurface::PIXMAP && !EglOS::validNativePixmap(nativeDisplay,nativeRead)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_NATIVE_PIXMAP); } if(newDrawPtr->type() == EglSurface::PIXMAP && !EglOS::validNativePixmap(nativeDisplay,nativeDraw)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_NATIVE_PIXMAP); } if(prevCtx.Ptr()) { g_eglInfo->getIface(prevCtx->version())->flush(); } if(!EglOS::makeCurrent(dpy->nativeType(),newReadPtr,newDrawPtr,newCtx->nativeType())) { RETURN_ERROR(EGL_FALSE,EGL_BAD_ACCESS); } //TODO: handle the following errors // EGL_BAD_CURRENT_SURFACE , EGL_CONTEXT_LOST , EGL_BAD_ACCESS thread->updateInfo(newCtx,dpy,newCtx->getGlesContext(),newCtx->getShareGroup(),dpy->getManager(newCtx->version())); newCtx->setSurfaces(newReadSrfc,newDrawSrfc); g_eglInfo->getIface(newCtx->version())->initContext(newCtx->getGlesContext(),newCtx->getShareGroup()); // Initialize the GLES extension function table used in // eglGetProcAddress for the context's GLES version if not // yet initialized. We initialize it here to make sure we call the // GLES getProcAddress after when a context is bound. g_eglInfo->initClientExtFuncTable(newCtx->version()); } // release previous context surface binding if(prevCtx.Ptr() && releaseContext) { prevCtx->setSurfaces(SurfacePtr(NULL),SurfacePtr(NULL)); } return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay display, EGLContext context, EGLint attribute, EGLint *value) { VALIDATE_DISPLAY(display); VALIDATE_CONTEXT(context); if(!ctx->getAttrib(attribute,value)){ RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE); } return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay display, EGLSurface surface) { VALIDATE_DISPLAY(display); VALIDATE_SURFACE(surface,Srfc); ThreadInfo* thread = getThreadInfo(); ContextPtr currentCtx = thread->eglContext; //if surface not window return if(Srfc->type() != EglSurface::WINDOW){ RETURN_ERROR(EGL_TRUE,EGL_SUCCESS); } if(!currentCtx.Ptr() || !currentCtx->usingSurface(Srfc) || !EglOS::validNativeWin(dpy->nativeType(),Srfc.Ptr()->native())) { RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE); } EglOS::swapBuffers(dpy->nativeType(),Srfc->native()); return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay display, EGLint interval) { VALIDATE_DISPLAY(display); ThreadInfo* thread = getThreadInfo(); ContextPtr currCtx = thread->eglContext; if(currCtx.Ptr()) { if(!currCtx->read().Ptr() || !currCtx->draw().Ptr() || currCtx->draw()->type()!=EglSurface::WINDOW) { RETURN_ERROR(EGL_FALSE,EGL_BAD_CURRENT_SURFACE); } EglOS::swapInterval(dpy->nativeType(),currCtx->draw()->native(),interval); } else { RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE); } return EGL_TRUE; } EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void) { ThreadInfo* thread = getThreadInfo(); EglDisplay* dpy = static_cast<EglDisplay*>(thread->eglDisplay); ContextPtr ctx = thread->eglContext; if(dpy && ctx.Ptr()){ // This double check is required because a context might still be current after it is destroyed - in which case // its handle should be invalid, that is EGL_NO_CONTEXT should be returned even though the context is current EGLContext c = (EGLContext)ctx->getHndl(); if(dpy->getContext(c).Ptr()) { return c; } } return EGL_NO_CONTEXT; } EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw) { if(!EglValidate::surfaceTarget(readdraw)) return EGL_NO_SURFACE; ThreadInfo* thread = getThreadInfo(); EglDisplay* dpy = static_cast<EglDisplay*>(thread->eglDisplay); ContextPtr ctx = thread->eglContext; if(dpy && ctx.Ptr()) { SurfacePtr surface = readdraw == EGL_READ ? ctx->read() : ctx->draw(); if(surface.Ptr()) { // This double check is required because a surface might still be // current after it is destroyed - in which case its handle should // be invalid, that is EGL_NO_SURFACE should be returned even // though the surface is current. EGLSurface s = (EGLSurface)surface->getHndl(); surface = dpy->getSurface(s); if(surface.Ptr()) { return s; } } } return EGL_NO_SURFACE; } EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void) { ThreadInfo* thread = getThreadInfo(); return (thread->eglContext.Ptr()) ? thread->eglDisplay : EGL_NO_DISPLAY; } EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void) { EGLenum api = eglQueryAPI(); eglBindAPI(EGL_OPENGL_ES_API); return eglWaitClient(); } EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine) { if(!EglValidate::engine(engine)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_PARAMETER); } ThreadInfo* thread = getThreadInfo(); ContextPtr currCtx = thread->eglContext; EglDisplay* dpy = static_cast<EglDisplay*>(thread->eglDisplay); if(currCtx.Ptr()) { SurfacePtr read = currCtx->read(); SurfacePtr draw = currCtx->draw(); EGLNativeInternalDisplayType nativeDisplay = dpy->nativeType(); if(read.Ptr()) { if(read->type() == EglSurface::WINDOW && !EglOS::validNativeWin(nativeDisplay,read->native())) { RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE); } if(read->type() == EglSurface::PIXMAP && !EglOS::validNativePixmap(nativeDisplay,read->native())) { RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE); } } if(draw.Ptr()) { if(draw->type() == EglSurface::WINDOW && !EglOS::validNativeWin(nativeDisplay,draw->native())) { RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE); } if(draw->type() == EglSurface::PIXMAP && !EglOS::validNativePixmap(nativeDisplay,draw->native())) { RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE); } } } EglOS::waitNative(); return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api) { if(!EglValidate::supportedApi(api)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_PARAMETER); } CURRENT_THREAD(); tls_thread->setApi(api); return EGL_TRUE; } EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void) { CURRENT_THREAD(); return tls_thread->getApi(); } EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void) { ThreadInfo* thread = getThreadInfo(); ContextPtr currCtx = thread->eglContext; if(currCtx.Ptr()) { if(!currCtx->read().Ptr() || !currCtx->draw().Ptr()) { RETURN_ERROR(EGL_FALSE,EGL_BAD_CURRENT_SURFACE); } g_eglInfo->getIface(currCtx->version())->finish(); } return EGL_TRUE; } EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void) { ThreadInfo* thread = getThreadInfo(); EglDisplay* dpy = static_cast<EglDisplay*>(thread->eglDisplay); return eglMakeCurrent(dpy,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT); } EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const char *procname){ __eglMustCastToProperFunctionPointerType retVal = NULL; initGlobalInfo(); if(!strncmp(procname,"egl",3)) { //EGL proc for(int i=0;i < s_eglExtentionsSize;i++){ if(strcmp(procname,s_eglExtentions[i].name) == 0){ retVal = s_eglExtentions[i].address; break; } } } else { // Look at the clientAPI (GLES) supported extension // function table. retVal = ClientAPIExts::getProcAddress(procname); } return retVal; } //not supported for now /************************* NOT SUPPORTED FOR NOW ***********************/ EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer( EGLDisplay display, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) { VALIDATE_DISPLAY(display); VALIDATE_CONFIG(config); //we do not support for now openVG, and the only client API resources which may be bound in this fashion are OpenVG RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_PARAMETER); } EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay display, EGLSurface surface, EGLNativePixmapType target) { VALIDATE_DISPLAY(display); VALIDATE_SURFACE(surface,srfc); if(!EglOS::validNativePixmap(dpy->nativeType(),NULL)) { RETURN_ERROR(EGL_FALSE,EGL_BAD_NATIVE_PIXMAP); } //we do not need to support this for android , since we are not gonna use pixmaps RETURN_ERROR(EGL_FALSE,EGL_BAD_NATIVE_PIXMAP); } /***********************************************************************/ //do last ( only if needed) /*********************************************************************************************************/ EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { //TODO: return 0; } EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { //TODO: return 0; } /*********************************************************************************************************/ /************************** KHR IMAGE *************************************************************/ EglImage *attachEGLImage(unsigned int imageId) { ThreadInfo* thread = getThreadInfo(); EglDisplay* dpy = static_cast<EglDisplay*>(thread->eglDisplay); ContextPtr ctx = thread->eglContext; if (ctx.Ptr()) { ImagePtr img = dpy->getImage(reinterpret_cast<EGLImageKHR>(imageId)); if(img.Ptr()) { ctx->attachImage(imageId,img); return img.Ptr(); } } return NULL; } void detachEGLImage(unsigned int imageId) { ThreadInfo* thread = getThreadInfo(); EglDisplay* dpy = static_cast<EglDisplay*>(thread->eglDisplay); ContextPtr ctx = thread->eglContext; if (ctx.Ptr()) { ctx->detachImage(imageId); } } EGLImageKHR eglCreateImageKHR(EGLDisplay display, EGLContext context, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { VALIDATE_DISPLAY(display); VALIDATE_CONTEXT(context); // We only support EGL_GL_TEXTURE_2D images if (target != EGL_GL_TEXTURE_2D_KHR) { RETURN_ERROR(EGL_NO_IMAGE_KHR,EGL_BAD_PARAMETER); } ThreadInfo* thread = getThreadInfo(); ShareGroupPtr sg = thread->shareGroup; if (sg.Ptr() != NULL) { unsigned int globalTexName = sg->getGlobalName(TEXTURE, (uintptr_t)buffer); if (!globalTexName) return EGL_NO_IMAGE_KHR; ImagePtr img( new EglImage() ); if (img.Ptr() != NULL) { ObjectDataPtr objData = sg->getObjectData(TEXTURE, (uintptr_t)buffer); if (!objData.Ptr()) return EGL_NO_IMAGE_KHR; TextureData *texData = (TextureData *)objData.Ptr(); if(!texData->width || !texData->height) return EGL_NO_IMAGE_KHR; img->width = texData->width; img->height = texData->height; img->border = texData->border; img->internalFormat = texData->internalFormat; img->globalTexName = globalTexName; return dpy->addImageKHR(img); } } return EGL_NO_IMAGE_KHR; } EGLBoolean eglDestroyImageKHR(EGLDisplay display, EGLImageKHR image) { VALIDATE_DISPLAY(display); return dpy->destroyImageKHR(image) ? EGL_TRUE:EGL_FALSE; } /*********************************************************************************/