opengles emulator: fix eglGetProcAddress

eglGetProcAddress should return a function pointer that does not
depends on the current bounded context (if any), when the user
calls one of the function pointers returned from eglGetProcAddress
for one of the GLES extension functions, the GLESv1 or GLESv2
version of the extension function shold be called depending on
the current bounded context.

For this we have added a ClientAPI (GLES) extension dispatch
table in the EGL level which points to static functions in libEGL
where each function checks in runtime the current bound context and
calls down to the GLES_CM -or- GLESv2 library function.
See ClientAPIExts.cpp, when new GLES extension functions are added
to GLESv1 or GLESv2 its definition should be added to
ClientAPIExts.in as well.

This fixes the segfault in egl_image conformance test.

Change-Id: I8464d87c2fcbe57d67bd8b891b695a690dec89f3
This commit is contained in:
Guy Zadickario
2011-07-27 22:20:54 +03:00
committed by David 'Digit' Turner
parent d8b376d76d
commit fb1868addc
7 changed files with 418 additions and 7 deletions

View File

@@ -37,7 +37,8 @@ LOCAL_SRC_FILES := \
EglPbufferSurface.cpp \ EglPbufferSurface.cpp \
EglPixmapSurface.cpp \ EglPixmapSurface.cpp \
EglThreadInfo.cpp \ EglThreadInfo.cpp \
EglDisplay.cpp EglDisplay.cpp \
ClientAPIExts.cpp
$(call emugl-end-module) $(call emugl-end-module)

View File

@@ -0,0 +1,159 @@
/*
* 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 "ClientAPIExts.h"
#include "EglGlobalInfo.h"
#include "GLcommon/GLutils.h"
#include "GLcommon/TranslatorIfaces.h"
#include "ThreadInfo.h"
#include <GLES/gl.h>
#include <GLES/glext.h>
namespace ClientAPIExts
{
//
// define function pointer type for each extention function
// typename has the form __egl_{funcname}_t
//
#define FUNC_TYPE(fname) __egl_ ## fname ## _t
#define API_ENTRY(fname,params,args) \
typedef void (GL_APIENTRY *FUNC_TYPE(fname)) params;
#define API_ENTRY_RET(rtype,fname,params,args) \
typedef rtype (GL_APIENTRY *FUNC_TYPE(fname)) params;
#include "ClientAPIExts.in"
#undef API_ENTRY
#undef API_ENTRY_RET
/////
// Define static table to store the function value for each
// client API. functions pointers will get initialized through
// ClientAPIExts::initClientFuncs function after each client API has been
// loaded.
/////
#define API_ENTRY(fname,params,args) \
FUNC_TYPE(fname) fname;
#define API_ENTRY_RET(rtype,fname,params,args) \
API_ENTRY(fname,params,args)
static struct _ext_table
{
#include "ClientAPIExts.in"
} s_client_extensions[MAX_GLES_VERSION-1];
#undef API_ENTRY
#undef API_ENTRY_RET
//
// This function initialized each entry in the s_client_extensions
// struct at the givven index using the givven client interface
//
void initClientFuncs(GLESiface *iface, int idx)
{
#define API_ENTRY(fname,params,args) \
s_client_extensions[idx].fname = \
(FUNC_TYPE(fname))iface->getProcAddress(#fname);
#define API_ENTRY_RET(rtype,fname,params,args) \
API_ENTRY(fname,params,args)
//
// reset all func pointers to NULL
//
memset(&s_client_extensions[idx], 0, sizeof(struct _ext_table));
//
// And now query the GLES library for each proc address
//
#include "ClientAPIExts.in"
#undef API_ENTRY
#undef API_ENTRY_RET
}
//
// Define implementation for each extension function which checks
// the current context version and calls to the correct client API
// function.
//
#define API_ENTRY(fname,params,args) \
static void _egl_ ## fname params \
{ \
ThreadInfo* thread = getThreadInfo(); \
if (!thread->eglContext.Ptr()) { \
return; \
} \
int idx = (int)thread->eglContext->version() - 1; \
if (!s_client_extensions[idx].fname) { \
return; \
} \
(*s_client_extensions[idx].fname) args; \
}
#define API_ENTRY_RET(rtype,fname,params,args) \
static rtype _egl_ ## fname params \
{ \
ThreadInfo* thread = getThreadInfo(); \
if (!thread->eglContext.Ptr()) { \
return (rtype)0; \
} \
int idx = (int)thread->eglContext->version() - 1; \
if (!s_client_extensions[idx].fname) { \
return (rtype)0; \
} \
return (*s_client_extensions[idx].fname) args; \
}
#include "ClientAPIExts.in"
#undef API_ENTRY
#undef API_ENTRY_RET
//
// Define a table to map function names to the local _egl_ version of
// the extension function, to be used in eglGetProcAddress.
//
#define API_ENTRY(fname,params,args) \
{ #fname, (__translatorMustCastToProperFunctionPointerType)_egl_ ## fname},
#define API_ENTRY_RET(rtype,fname,params,args) \
API_ENTRY(fname,params,args)
static struct _client_ext_funcs {
const char *fname;
__translatorMustCastToProperFunctionPointerType proc;
} s_client_ext_funcs[] = {
#include "ClientAPIExts.in"
};
static const int numExtFuncs = sizeof(s_client_ext_funcs) /
sizeof(s_client_ext_funcs[0]);
#undef API_ENTRY
#undef API_ENTRY_RET
//
// returns the __egl_ version of the givven extension function name.
//
__translatorMustCastToProperFunctionPointerType getProcAddress(const char *fname)
{
for (int i=0; i<numExtFuncs; i++) {
if (!strcmp(fname, s_client_ext_funcs[i].fname)) {
return s_client_ext_funcs[i].proc;
}
}
return NULL;
}
} // of namespace ClientAPIExts

View File

@@ -0,0 +1,29 @@
/*
* 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.
*/
#ifndef _CLIENT_APIS_EXTS_H
#define _CLIENT_APIS_EXTS_H
#include "GLcommon/TranslatorIfaces.h"
namespace ClientAPIExts
{
void initClientFuncs(GLESiface *iface, int idx);
__translatorMustCastToProperFunctionPointerType getProcAddress(const char *fname);
} // of namespace ClientAPIExts
#endif

View File

@@ -0,0 +1,201 @@
//
// Each extension function should have one of the following
// macro definitions:
// API_ENTRY(funcname, paramlist, arglist)
// -or- (in case funciton has return value)
// API_ENTRY_RET(return_type,funcname, paramlist, arglist)
//
API_ENTRY(glEGLImageTargetTexture2DOES,
(GLenum target, GLeglImageOES image),
(target, image))
API_ENTRY(glEGLImageTargetRenderbufferStorageOES,
(GLenum target, GLeglImageOES image),
(target, image))
API_ENTRY(glBlendEquationSeparateOES,
(GLenum modeRGB, GLenum modeAlpha),
(modeRGB, modeAlpha))
API_ENTRY(glBlendFuncSeparateOES,
(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha),
(srcRGB, dstRGB, srcAlpha, dstAlpha))
API_ENTRY(glBlendEquationOES,
(GLenum mode),
(mode))
API_ENTRY(glCurrentPaletteMatrixOES,
(GLuint matrixpaletteindex),
(matrixpaletteindex))
API_ENTRY(glLoadPaletteFromModelViewMatrixOES,
(void),
())
API_ENTRY(glMatrixIndexPointerOES,
(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer),
(size, type, stride, pointer))
API_ENTRY(glWeightPointerOES,
(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer),
(size, type, stride, pointer))
API_ENTRY(glDepthRangefOES,
(GLclampf zNear, GLclampf zFar),
(zNear, zFar))
API_ENTRY(glFrustumfOES,
(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar),
(left, right, bottom, top, zNear, zFar))
API_ENTRY(glOrthofOES,
(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar),
(left, right, bottom, top, zNear, zFar))
API_ENTRY(glClipPlanefOES,
(GLenum plane, const GLfloat *equation),
(plane, equation))
API_ENTRY(glGetClipPlanefOES,
(GLenum pname, GLfloat * eqn),
(pname, eqn))
API_ENTRY(glClearDepthfOES,
(GLclampf depth),
(depth))
API_ENTRY(glPointSizePointerOES,
(GLenum type, GLsizei stride, const GLvoid *pointer),
(type, stride, pointer))
API_ENTRY(glTexGenfOES,
(GLenum coord, GLenum pname, GLfloat param),
(coord, pname, param))
API_ENTRY(glTexGenfvOES,
(GLenum coord, GLenum pname, const GLfloat *params),
(coord, pname, params))
API_ENTRY(glTexGeniOES,
(GLenum coord, GLenum pname, GLint param),
(coord, pname, param))
API_ENTRY(glTexGenivOES,
(GLenum coord, GLenum pname, const GLint *params),
(coord, pname, params))
API_ENTRY(glTexGenxOES,
(GLenum coord, GLenum pname, GLfixed param),
(coord, pname, param))
API_ENTRY(glTexGenxvOES,
(GLenum coord, GLenum pname, const GLfixed *params),
(coord, pname, params))
API_ENTRY(glGetTexGenfvOES,
(GLenum coord, GLenum pname, GLfloat *params),
(coord, pname, params))
API_ENTRY(glGetTexGenivOES,
(GLenum coord, GLenum pname, GLint *params),
(coord, pname, params))
API_ENTRY(glGetTexGenxvOES,
(GLenum coord, GLenum pname, GLfixed *params),
(coord, pname, params))
API_ENTRY_RET(GLboolean,
glIsRenderbufferOES,
(GLuint renderbuffer),
(renderbuffer))
API_ENTRY(glBindRenderbufferOES,
(GLenum target, GLuint renderbuffer),
(target, renderbuffer))
API_ENTRY(glDeleteRenderbuffersOES,
(GLsizei n, const GLuint* renderbuffers),
(n, renderbuffers))
API_ENTRY(glGenRenderbuffersOES,
(GLsizei n, GLuint* renderbuffers),
(n, renderbuffers))
API_ENTRY(glRenderbufferStorageOES,
(GLenum target, GLenum internalformat, GLsizei width, GLsizei height),
(target, internalformat, width, height))
API_ENTRY(glGetRenderbufferParameterivOES,
(GLenum target, GLenum pname, GLint* params),
(target, pname, params))
API_ENTRY_RET(GLboolean,
glIsFramebufferOES,
(GLuint framebuffer),
(framebuffer))
API_ENTRY(glBindFramebufferOES,
(GLenum target, GLuint framebuffer),
(target, framebuffer))
API_ENTRY(glDeleteFramebuffersOES,
(GLsizei n, const GLuint* framebuffers),
(n, framebuffers))
API_ENTRY(glGenFramebuffersOES,
(GLsizei n, GLuint* framebuffers),
(n, framebuffers))
API_ENTRY_RET(GLenum,
glCheckFramebufferStatusOES,
(GLenum target),
(target))
API_ENTRY(glFramebufferTexture2DOES,
(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level),
(target, attachment, textarget, texture, level))
API_ENTRY(glFramebufferRenderbufferOES,
(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer),
(target, attachment, renderbuffertarget, renderbuffer))
API_ENTRY(glGetFramebufferAttachmentParameterivOES,
(GLenum target, GLenum attachment, GLenum pname, GLint* params),
(target, attachment, pname, params))
API_ENTRY(glGenerateMipmapOES,
(GLenum target),
(target))
API_ENTRY(glDrawTexsOES,
(GLshort x, GLshort y, GLshort z, GLshort width, GLshort height),
(x, y, z, width, height))
API_ENTRY(glDrawTexiOES,
(GLint x, GLint y, GLint z, GLint width, GLint height),
(x, y, z, width, height))
API_ENTRY(glDrawTexfOES,
(GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height),
(x, y, z, width, height))
API_ENTRY(glDrawTexxOES,
(GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height),
(x, y, z, width, height))
API_ENTRY(glDrawTexsvOES,
(const GLshort *coords),
(coords))
API_ENTRY(glDrawTexivOES,
(const GLint *coords),
(coords))
API_ENTRY(glDrawTexfvOES,
(const GLfloat *coords),
(coords))
API_ENTRY(glDrawTexxvOES,
(const GLfixed *coords),
(coords))

View File

@@ -16,6 +16,7 @@
#include "EglGlobalInfo.h" #include "EglGlobalInfo.h"
#include "EglOsApi.h" #include "EglOsApi.h"
#include <string.h> #include <string.h>
#include "ClientAPIExts.h"
int EglGlobalInfo::m_refCount = 0; int EglGlobalInfo::m_refCount = 0;
EglGlobalInfo* EglGlobalInfo::m_singleton = NULL; EglGlobalInfo* EglGlobalInfo::m_singleton = NULL;
@@ -27,6 +28,7 @@ EglGlobalInfo::EglGlobalInfo(){
EglOS::initPtrToWglFunctions(); EglOS::initPtrToWglFunctions();
#endif #endif
memset(m_gles_ifaces,0,sizeof(m_gles_ifaces)); memset(m_gles_ifaces,0,sizeof(m_gles_ifaces));
memset(m_gles_extFuncs_inited,0,sizeof(m_gles_extFuncs_inited));
} }
EglGlobalInfo* EglGlobalInfo::getInstance() { EglGlobalInfo* EglGlobalInfo::getInstance() {
@@ -91,3 +93,12 @@ EglDisplay* EglGlobalInfo::getDisplay(EGLDisplay dpy) {
EGLNativeInternalDisplayType EglGlobalInfo::generateInternalDisplay(EGLNativeDisplayType dpy){ EGLNativeInternalDisplayType EglGlobalInfo::generateInternalDisplay(EGLNativeDisplayType dpy){
return EglOS::getInternalDisplay(dpy); return EglOS::getInternalDisplay(dpy);
} }
void EglGlobalInfo::initClientExtFuncTable(GLESVersion ver)
{
android::Mutex::Autolock mutex(m_lock);
if (!m_gles_extFuncs_inited[ver]) {
ClientAPIExts::initClientFuncs(m_gles_ifaces[ver], (int)ver - 1);
m_gles_extFuncs_inited[ver] = true;
}
}

View File

@@ -40,9 +40,10 @@ public:
void setIface(GLESiface* iface,GLESVersion ver) { m_gles_ifaces[ver] = iface;}; void setIface(GLESiface* iface,GLESVersion ver) { m_gles_ifaces[ver] = iface;};
GLESiface* getIface(GLESVersion ver){ return m_gles_ifaces[ver];} GLESiface* getIface(GLESVersion ver){ return m_gles_ifaces[ver];}
int nDisplays() const { return m_displays.size();}; int nDisplays() const { return m_displays.size();};
void initClientExtFuncTable(GLESVersion ver);
static EglGlobalInfo* getInstance(); static EglGlobalInfo* getInstance();
static void delInstance(); static void delInstance();
@@ -56,6 +57,7 @@ private:
DisplaysMap m_displays; DisplaysMap m_displays;
EGLNativeInternalDisplayType m_default; EGLNativeInternalDisplayType m_default;
GLESiface* m_gles_ifaces[MAX_GLES_VERSION]; GLESiface* m_gles_ifaces[MAX_GLES_VERSION];
bool m_gles_extFuncs_inited[MAX_GLES_VERSION];
android::Mutex m_lock; android::Mutex m_lock;
}; };

View File

@@ -36,6 +36,7 @@
#include "EglContext.h" #include "EglContext.h"
#include "EglConfig.h" #include "EglConfig.h"
#include "EglOsApi.h" #include "EglOsApi.h"
#include "ClientAPIExts.h"
#define MAJOR 1 #define MAJOR 1
#define MINOR 4 #define MINOR 4
@@ -739,6 +740,12 @@ EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay display, EGLSurface draw
thread->updateInfo(newCtx,dpy,newCtx->getGlesContext(),newCtx->getShareGroup(),dpy->getManager(newCtx->version())); thread->updateInfo(newCtx,dpy,newCtx->getGlesContext(),newCtx->getShareGroup(),dpy->getManager(newCtx->version()));
newCtx->setSurfaces(newReadSrfc,newDrawSrfc); newCtx->setSurfaces(newReadSrfc,newDrawSrfc);
g_eglInfo->getIface(newCtx->version())->initContext(newCtx->getGlesContext(),newCtx->getShareGroup()); 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 // release previous context surface binding
@@ -928,14 +935,15 @@ EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
break; break;
} }
} }
} else if (!strncmp(procname,"gl",2)){ //GL proc
retVal = g_eglInfo->getIface(GLES_1_1)->getProcAddress(procname); //try to get it from GLES 1.0
if(!retVal){ //try to get it from GLES 2.0
retVal = g_eglInfo->getIface(GLES_2_0)->getProcAddress(procname);
} }
else {
// Look at the clientAPI (GLES) supported extension
// function table.
retVal = ClientAPIExts::getProcAddress(procname);
} }
return retVal; return retVal;
} }
//not supported for now //not supported for now
/************************* NOT SUPPORTED FOR NOW ***********************/ /************************* NOT SUPPORTED FOR NOW ***********************/
EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer( EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(