blob: 94e3cec02bc71fee91f3173f03d52bc6aa380843 [file] [log] [blame]
/*
* 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.
*/
#include <EGL/egl.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <GLcommon/ThreadInfo.h>
#include <GLcommon/TranslatorIfaces.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"
#define MINOR 1
#define MAJOR 4
EglGlobalInfo* g_eglInfo = EglGlobalInfo::getInstance();
__thread EglThreadInfo* tls_thread = NULL;
static EGLiface s_eglIface = {
getThreadInfo: getThreadInfo // implemented in ThreadInfo.cpp
};
//extentions
typedef struct {
const char* name;
__eglMustCastToProperFunctionPointerType address;
} EglExtentionDescriptor;
#define EGL_EXTENTIONS 0
//supported extentions;
static EglExtentionDescriptor s_extentions[] = {};
//macros for accessing global egl info & tls objects
#define CURRENT_THREAD() \
if(!tls_thread) { \
tls_thread = new EglThreadInfo(); \
}
#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)
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;
if( display_id == EGL_DEFAULT_DISPLAY) {
display_id = g_eglInfo->getDefaultNativeDisplay();
}
if ((dpy = g_eglInfo->getDisplay(display_id))) {
return dpy;
} else {
dpy = g_eglInfo->addDisplay(display_id);
if(dpy) return dpy;
return EGL_NO_DISPLAY;
}
}
static __translator_getGLESIfaceFunc loadIfaces(const char* libName){
void* libGLES = dlopen(libName, RTLD_NOW);
if(!libGLES) return NULL;
__translator_getGLESIfaceFunc func = (__translator_getGLESIfaceFunc)dlsym(libGLES,"__translator_getIfaces");
if(!func) return NULL;
return func;
}
EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay display, EGLint *major, EGLint *minor) {
EglDisplay* dpy = g_eglInfo->getDisplay(display);
if(!dpy) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_DISPLAY);
}
if(major) *major = MAJOR;
if(minor) *minor = MINOR;
if(!g_eglInfo->getIface(GLES_1_1)) {
__translator_getGLESIfaceFunc func = loadIfaces("libGLES_CM_translator.so");
if(func){
g_eglInfo->setIface(func(&s_eglIface),GLES_1_1);
} else {
return EGL_FALSE;
}
}
dpy->initialize();
return EGL_TRUE;
}
//TODO check this func definitions later on
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"; //XXX: Not implemented yet
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;
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:
continue; //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_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) {
configs[0] = static_cast<EGLConfig>(pConfig);
*num_config = 0;
return EGL_TRUE;
} else {
RETURN_ERROR(EGL_FALSE,EGL_BAD_ATTRIBUTE);
}
}
}
EglConfig dummy(red_size,green_size,blue_size,alpha_size,caveat,config_id,depth_size,
frame_buffer_level,0,0,0,native_renderable,0,native_visual_type,
samples_per_pixel,stencil_size,surface_type,transparent_type,
trans_red_val,trans_green_val,trans_blue_val);
*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(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(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(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);
}
EGLNativePbufferType pb = EglOS::createPbuffer(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(pixmap,cfg));
if(!pixSurface.Ptr()) {
RETURN_ERROR(EGL_NO_SURFACE,EGL_BAD_ALLOC);
}
return dpy->addSurface(pixSurface);
}
static bool destroySurfaceIfNotCurrent(EglDisplay* dpy,SurfacePtr surface) {
ThreadInfo* thread = getThreadInfo();
EglContext* currCtx = static_cast<EglContext*>(thread->eglContext);
if(currCtx && !currCtx->usingSurface(surface)){
if(surface->type() == EglSurface::PBUFFER) {
EglOS::releasePbuffer(dpy->nativeType(),reinterpret_cast<EGLNativePbufferType>(surface->native()));
return true;
}
}
return false;
}
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);
}
srfc->destroy(); //mark surface for destruction
if(destroySurfaceIfNotCurrent(dpy,srfc)) { //removes surface from the list if not current
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 nativeContext = EglOS::createContext(dpy->nativeType(),cfg,static_cast<EGLNativeContextType>(dpy->getManager(version)->getGlobalContext()));
if(nativeContext) {
ContextPtr ctx(new EglContext(nativeContext,sharedCtxPtr,cfg,glesCtx,version,dpy->getManager(version)));
return dpy->addContext(ctx);
} else {
iface->deleteGLESContext(glesCtx);
}
return EGL_NO_CONTEXT;
}
static bool destroyContextIfNotCurrent(EglDisplay* dpy,ContextPtr ctx ) {
ThreadInfo* thread = getThreadInfo();
EglContext* currCtx = static_cast<EglContext*>(thread->eglContext);
if(ctx.Ptr() != currCtx ){
EglOS::destroyContext(dpy->nativeType(),ctx->nativeType());
return true;
}
return false;
}
EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay display, EGLContext context) {
VALIDATE_DISPLAY(display);
VALIDATE_CONTEXT(context);
ctx->destroy(); //mark for destruction
if(destroyContextIfNotCurrent(dpy,ctx)){ //removes the context from the list if it is not current
g_eglInfo->getIface(ctx->version())->deleteGLESContext(ctx->getGlesContext());
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);
}
VALIDATE_CONTEXT(context);
VALIDATE_SURFACE(draw,newDrawSrfc);
VALIDATE_SURFACE(read,newReadSrfc);
EglSurface* newDrawPtr = newDrawSrfc.Ptr();
EglSurface* newReadPtr = newReadSrfc.Ptr();
EglContext* newCtx = ctx.Ptr();
ThreadInfo* thread = getThreadInfo();
EglContext* prevCtx = static_cast<EglContext*>(thread->eglContext);
if(releaseContext) { //releasing current context
if(prevCtx) {
g_eglInfo->getIface(prevCtx->version())->flush();
if(!EglOS::makeCurrent(dpy->nativeType(),NULL,NULL,NULL)) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_ACCESS);
}
thread->updateInfo(newCtx,dpy,NULL,newCtx->getShareGroup(),dpy->getManager(newCtx->version()));
g_eglInfo->getIface(prevCtx->version())->setShareGroup(newCtx->getGlesContext(),ShareGroupPtr(NULL));
ctx->setSurfaces(SurfacePtr(NULL),SurfacePtr(NULL));
}
} else { //assining new context
//surfaces compitability check
if(!((*ctx->getConfig()).compitableWith((*newDrawPtr->getConfig()))) ||
!((*ctx->getConfig()).compitableWith((*newReadPtr->getConfig())))) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_MATCH);
}
//checking native window validity
if(newReadPtr->type() == EglSurface::WINDOW && !EglOS::validNativeWin(reinterpret_cast<EGLNativeWindowType>(newReadPtr->native()))) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_NATIVE_WINDOW);
}
if(newDrawPtr->type() == EglSurface::WINDOW && !EglOS::validNativeWin(reinterpret_cast<EGLNativeWindowType>(newDrawPtr->native()))) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_NATIVE_WINDOW);
}
//checking native pixmap validity
if(newReadPtr->type() == EglSurface::PIXMAP && !EglOS::validNativePixmap(reinterpret_cast<EGLNativePixmapType>(newReadPtr->native()))) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_NATIVE_PIXMAP);
}
if(newDrawPtr->type() == EglSurface::PIXMAP && !EglOS::validNativePixmap(reinterpret_cast<EGLNativePixmapType>(newDrawPtr->native()))) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_NATIVE_PIXMAP);
}
if(prevCtx) {
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());
g_eglInfo->getIface(newCtx->version())->setShareGroup(newCtx->getGlesContext(),newCtx->getShareGroup());
}
SurfacePtr prevRead;
SurfacePtr prevDraw;
//removing terminated surfaces & context
if(prevCtx) {
prevRead = prevCtx->read();
if(prevRead->destroy()){
if(destroySurfaceIfNotCurrent(dpy,prevRead)) { //removes surface from the list if not current
dpy->removeSurface(prevRead);
}
}
prevDraw = prevCtx->draw();
if(prevDraw->destroy()){
if(destroySurfaceIfNotCurrent(dpy,prevDraw)) { //removes surface from the list if not current
dpy->removeSurface(prevDraw);
}
}
if(prevCtx->destroy()) {
ContextPtr prevCtxPtr = ContextPtr(prevCtx);
if(destroyContextIfNotCurrent(dpy,prevCtxPtr)){ //removes the context from the list if it is not current
g_eglInfo->getIface(prevCtx->version())->deleteGLESContext(prevCtx->getGlesContext());
dpy->removeContext(prevCtxPtr);
}
}
}
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();
EglContext* currentCtx = static_cast<EglContext*>(thread->eglContext);
//if surface not window return
if(Srfc->type() != EglSurface::WINDOW){
RETURN_ERROR(EGL_TRUE,EGL_SUCCESS);
}
if(!currentCtx || !currentCtx->usingSurface(Srfc) || !EglOS::validNativeWin(reinterpret_cast<EGLNativeWindowType>(Srfc.Ptr()->native()))) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE);
}
EglOS::swapBuffers(dpy->nativeType(),reinterpret_cast<EGLNativeWindowType>(Srfc->native()));
return EGL_TRUE;
}
EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay display, EGLint interval) {
VALIDATE_DISPLAY(display);
ThreadInfo* thread = getThreadInfo();
EglContext* currCtx = static_cast<EglContext*>(thread->eglContext);
if(currCtx) {
if(!currCtx->read().Ptr() || !currCtx->draw().Ptr() || currCtx->draw()->type()!=EglSurface::WINDOW) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_CURRENT_SURFACE);
}
EglOS::swapInterval(dpy->nativeType(),reinterpret_cast<EGLNativeWindowType>(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);
EglContext* ctx = static_cast<EglContext*>(thread->eglContext);
if(dpy && ctx){
return dpy->getContext(ContextPtr(ctx));
}
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);
EglContext* ctx = static_cast<EglContext*>(thread->eglContext);
if(dpy && ctx) {
SurfacePtr surface = readdraw == EGL_READ ? ctx->read() : ctx->draw();
return dpy->getSurface(surface);
}
return EGL_NO_SURFACE;
}
EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void) {
ThreadInfo* thread = getThreadInfo();
return (thread->eglContext) ? 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();
EglContext* currCtx = static_cast<EglContext*>(thread->eglContext);
if(currCtx) {
EglSurface* read = currCtx->read().Ptr();
EglSurface* draw = currCtx->read().Ptr();
if(read) {
if(read->type() == EglSurface::WINDOW &&
!EglOS::validNativeWin(reinterpret_cast<EGLNativeWindowType>(read->native()))) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE);
}
if(read->type() == EglSurface::PIXMAP &&
!EglOS::validNativePixmap(reinterpret_cast<EGLNativePixmapType>(read->native()))) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE);
}
}
if(draw) {
if(draw->type() == EglSurface::WINDOW &&
!EglOS::validNativeWin(reinterpret_cast<EGLNativeWindowType>(draw->native()))) {
RETURN_ERROR(EGL_FALSE,EGL_BAD_SURFACE);
}
if(draw->type() == EglSurface::PIXMAP &&
!EglOS::validNativePixmap(reinterpret_cast<EGLNativePixmapType>(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();
EglContext* currCtx = static_cast<EglContext*>(thread->eglContext);
if(currCtx) {
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){
if(!strncmp(procname,"egl",3)) { //EGL proc
for(int i=0;i < EGL_EXTENSIONS;i++){
if(strcmp(procname,s_extentions[i].name) == 0){
return s_extentions[i].address;
}
}
} else if (!strncmp(procname,"gl",2)){ //GL proc
//TODO:call glGetProcAdress
}
return NULL;
}
//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(target)) {
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;
}
/*********************************************************************************************************/