From fb1868addc74b2bb29a966bfec1fa1941301b8a8 Mon Sep 17 00:00:00 2001 From: Guy Zadickario Date: Wed, 27 Jul 2011 22:20:54 +0300 Subject: [PATCH] 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 --- .../host/libs/Translator/EGL/Android.mk | 3 +- .../libs/Translator/EGL/ClientAPIExts.cpp | 159 ++++++++++++++ .../host/libs/Translator/EGL/ClientAPIExts.h | 29 +++ .../host/libs/Translator/EGL/ClientAPIExts.in | 201 ++++++++++++++++++ .../libs/Translator/EGL/EglGlobalInfo.cpp | 11 + .../host/libs/Translator/EGL/EglGlobalInfo.h | 4 +- .../host/libs/Translator/EGL/EglImp.cpp | 18 +- 7 files changed, 418 insertions(+), 7 deletions(-) create mode 100644 tools/emulator/opengl/host/libs/Translator/EGL/ClientAPIExts.cpp create mode 100644 tools/emulator/opengl/host/libs/Translator/EGL/ClientAPIExts.h create mode 100644 tools/emulator/opengl/host/libs/Translator/EGL/ClientAPIExts.in diff --git a/tools/emulator/opengl/host/libs/Translator/EGL/Android.mk b/tools/emulator/opengl/host/libs/Translator/EGL/Android.mk index 1109f121e..96e87de3c 100644 --- a/tools/emulator/opengl/host/libs/Translator/EGL/Android.mk +++ b/tools/emulator/opengl/host/libs/Translator/EGL/Android.mk @@ -37,7 +37,8 @@ LOCAL_SRC_FILES := \ EglPbufferSurface.cpp \ EglPixmapSurface.cpp \ EglThreadInfo.cpp \ - EglDisplay.cpp + EglDisplay.cpp \ + ClientAPIExts.cpp $(call emugl-end-module) diff --git a/tools/emulator/opengl/host/libs/Translator/EGL/ClientAPIExts.cpp b/tools/emulator/opengl/host/libs/Translator/EGL/ClientAPIExts.cpp new file mode 100644 index 000000000..42d5764b3 --- /dev/null +++ b/tools/emulator/opengl/host/libs/Translator/EGL/ClientAPIExts.cpp @@ -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 +#include + +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 +#include "ClientAPIExts.h" int EglGlobalInfo::m_refCount = 0; EglGlobalInfo* EglGlobalInfo::m_singleton = NULL; @@ -27,6 +28,7 @@ EglGlobalInfo::EglGlobalInfo(){ EglOS::initPtrToWglFunctions(); #endif memset(m_gles_ifaces,0,sizeof(m_gles_ifaces)); + memset(m_gles_extFuncs_inited,0,sizeof(m_gles_extFuncs_inited)); } EglGlobalInfo* EglGlobalInfo::getInstance() { @@ -91,3 +93,12 @@ EglDisplay* EglGlobalInfo::getDisplay(EGLDisplay dpy) { EGLNativeInternalDisplayType EglGlobalInfo::generateInternalDisplay(EGLNativeDisplayType 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; + } +} diff --git a/tools/emulator/opengl/host/libs/Translator/EGL/EglGlobalInfo.h b/tools/emulator/opengl/host/libs/Translator/EGL/EglGlobalInfo.h index 6be76efc1..ec07ffe1d 100644 --- a/tools/emulator/opengl/host/libs/Translator/EGL/EglGlobalInfo.h +++ b/tools/emulator/opengl/host/libs/Translator/EGL/EglGlobalInfo.h @@ -40,9 +40,10 @@ public: void setIface(GLESiface* iface,GLESVersion ver) { m_gles_ifaces[ver] = iface;}; GLESiface* getIface(GLESVersion ver){ return m_gles_ifaces[ver];} - int nDisplays() const { return m_displays.size();}; + void initClientExtFuncTable(GLESVersion ver); + static EglGlobalInfo* getInstance(); static void delInstance(); @@ -56,6 +57,7 @@ private: DisplaysMap m_displays; EGLNativeInternalDisplayType m_default; GLESiface* m_gles_ifaces[MAX_GLES_VERSION]; + bool m_gles_extFuncs_inited[MAX_GLES_VERSION]; android::Mutex m_lock; }; diff --git a/tools/emulator/opengl/host/libs/Translator/EGL/EglImp.cpp b/tools/emulator/opengl/host/libs/Translator/EGL/EglImp.cpp index fd9779fb7..9205aa9f2 100644 --- a/tools/emulator/opengl/host/libs/Translator/EGL/EglImp.cpp +++ b/tools/emulator/opengl/host/libs/Translator/EGL/EglImp.cpp @@ -36,6 +36,7 @@ #include "EglContext.h" #include "EglConfig.h" #include "EglOsApi.h" +#include "ClientAPIExts.h" #define MAJOR 1 #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())); 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 @@ -928,14 +935,15 @@ EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY 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; } + //not supported for now /************************* NOT SUPPORTED FOR NOW ***********************/ EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(