From 37db3deb7bfddffa66b16297b5afdd7c750ff072 Mon Sep 17 00:00:00 2001 From: Stas Gurtovoy Date: Tue, 26 Apr 2011 11:19:21 +0300 Subject: [PATCH] First commit of the system egl implementation. At this point system/egl should build without errors Change-Id: Ieabae930fc20a8df4f3d68f179d685401e946e74 --- .../OpenglSystemCommon/EGLClientIface.h | 22 + .../system/OpenglSystemCommon/ThreadInfo.h | 3 +- tools/emulator/opengl/system/egl/Android.mk | 50 +++ tools/emulator/opengl/system/egl/egl.cpp | 387 ++++++++++++++++++ .../emulator/opengl/system/egl/eglDisplay.cpp | 376 +++++++++++++++++ tools/emulator/opengl/system/egl/eglDisplay.h | 71 ++++ tools/emulator/opengl/system/egl/egl_ftable.h | 66 +++ 7 files changed, 974 insertions(+), 1 deletion(-) create mode 100644 tools/emulator/opengl/system/OpenglSystemCommon/EGLClientIface.h create mode 100644 tools/emulator/opengl/system/egl/Android.mk create mode 100644 tools/emulator/opengl/system/egl/egl.cpp create mode 100644 tools/emulator/opengl/system/egl/eglDisplay.cpp create mode 100644 tools/emulator/opengl/system/egl/eglDisplay.h create mode 100644 tools/emulator/opengl/system/egl/egl_ftable.h diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/EGLClientIface.h b/tools/emulator/opengl/system/OpenglSystemCommon/EGLClientIface.h new file mode 100644 index 000000000..b71bb1f6a --- /dev/null +++ b/tools/emulator/opengl/system/OpenglSystemCommon/EGLClientIface.h @@ -0,0 +1,22 @@ +#ifndef _SYSTEM_COMMON_EGL_CLIENT_IFACE_H +#define _SYSTEM_COMMON_EGL_CLIENT_IFACE_H + +struct EGLThreadInfo; // defined in ThreadInfo.h + +typedef struct { + EGLThreadInfo* (*getThreadInfo)(); +} EGLClient_eglInterface; + +typedef struct { + void* (*getProcAddress)(const char *funcName); +} EGLClient_glesInterface; + +// +// Any GLES/GLES2 client API library should define a function named "init_emul_gles" +// with the following prototype, +// It will be called by EGL after loading the GLES library for initialization +// and exchanging interface function pointers. +// +typedef EGLClient_glesInterface *(*init_emul_gles_t)(EGLClient_eglInterface *eglIface); + +#endif diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/ThreadInfo.h b/tools/emulator/opengl/system/OpenglSystemCommon/ThreadInfo.h index cdb66a165..82936cbe2 100644 --- a/tools/emulator/opengl/system/OpenglSystemCommon/ThreadInfo.h +++ b/tools/emulator/opengl/system/OpenglSystemCommon/ThreadInfo.h @@ -22,10 +22,11 @@ struct EGLContext_t; struct EGLThreadInfo { - EGLThreadInfo() : currentContext(NULL), hostConn(NULL) {} + EGLThreadInfo() : currentContext(NULL), hostConn(NULL), eglError(0) {} EGLContext_t *currentContext; HostConnection *hostConn; + int eglError; }; diff --git a/tools/emulator/opengl/system/egl/Android.mk b/tools/emulator/opengl/system/egl/Android.mk new file mode 100644 index 000000000..8fcbd8ed3 --- /dev/null +++ b/tools/emulator/opengl/system/egl/Android.mk @@ -0,0 +1,50 @@ +ifneq (,$(BUILD_EMULATOR_OPENGL_DRIVER)) + +LOCAL_PATH := $(call my-dir) +emulatorOpengl := $(LOCAL_PATH)/../.. + +### EGL implementation ########################################### +include $(CLEAR_VARS) + +# add additional depencies to ensure that the generated code that we depend on +# is generated +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(TARGET_OUT_SHARED_LIBRARIES)/lib_renderControl_enc$(TARGET_SHLIB_SUFFIX) \ + $(TARGET_OUT_SHARED_LIBRARIES)/libGLESv1_enc$(TARGET_SHLIB_SUFFIX) + +LOCAL_SRC_FILES := \ + eglDisplay.cpp \ + egl.cpp + + +LOCAL_PRELINK_MODULE := false +LOCAL_CFLAGS += -DLOG_TAG=\"EGL_emulation\" -DEGL_EGLEXT_PROTOTYPES +LOCAL_C_INCLUDES += \ + $(emulatorOpengl)/host/include/libOpenglRender \ + $(emulatorOpengl)/shared/OpenglCodecCommon \ + $(emulatorOpengl)/system/OpenglSystemCommon \ + $(emulatorOpengl)/system/GLESv1_enc \ + $(emulatorOpengl)/system/renderControl_enc \ + $(call intermediates-dir-for, SHARED_LIBRARIES, lib_renderControl_enc) \ + $(call intermediates-dir-for, SHARED_LIBRARIES, libGLESv1_enc) + +LOCAL_MODULE_TAGS := debug +LOCAL_MODULE := libEGL_emulation +LOCAL_MODULE_CLASS := SHARED_LIBRARIES + + +LOCAL_STATIC_LIBRARIES := \ + libOpenglSystemCommon \ + libOpenglCodecCommon + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libdl \ + libGLESv1_enc \ + lib_renderControl_enc + + +include $(BUILD_SHARED_LIBRARY) + +endif # of ifneq (,$(BUILD_EMULATOR_OPENGL_DRIVER)) diff --git a/tools/emulator/opengl/system/egl/egl.cpp b/tools/emulator/opengl/system/egl/egl.cpp new file mode 100644 index 000000000..9ee231dcc --- /dev/null +++ b/tools/emulator/opengl/system/egl/egl.cpp @@ -0,0 +1,387 @@ +/* +* 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 "HostConnection.h" +#include "ThreadInfo.h" +#include "eglDisplay.h" +#include "egl_ftable.h" +#include + +// The one and only supported display object. +static eglDisplay s_display; + +static EGLClient_eglInterface s_eglIface = { + getThreadInfo: getEGLThreadInfo +}; + +#define RETURN_ERROR(ret,err) \ + getEGLThreadInfo()->eglError = err; \ + return ret; + +#define VALIDATE_CONFIG(cfg,ret) \ + if(((int)cfg<0)||((int)cfg>s_display.getNumConfigs())) { \ + RETURN_ERROR(ret,EGL_BAD_CONFIG); \ + } + +#define VALIDATE_DISPLAY(dpy,ret) \ + if ((dpy) != (EGLDisplay)&s_display) { \ + getEGLThreadInfo()->eglError = EGL_BAD_DISPLAY; \ + return ret; \ + } + +#define VALIDATE_DISPLAY_INIT(dpy,ret) \ + VALIDATE_DISPLAY(dpy, ret) \ + if (!s_display.initialized()) { \ + getEGLThreadInfo()->eglError = EGL_NOT_INITIALIZED; \ + return ret; \ + } + +EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) +{ + // + // we support only EGL_DEFAULT_DISPLAY. + // + if (display_id != EGL_DEFAULT_DISPLAY) { + return EGL_NO_DISPLAY; + } + + return (EGLDisplay)&s_display; +} + +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + VALIDATE_DISPLAY(dpy,EGL_FALSE); + + if (!s_display.initialize(&s_eglIface)) { + return EGL_FALSE; + } + + *major = s_display.getVersionMajor(); + *minor = s_display.getVersionMinor(); + return EGL_TRUE; +} + +EGLBoolean eglTerminate(EGLDisplay dpy) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + + s_display.terminate(); + return EGL_TRUE; +} + +EGLint eglGetError() +{ + return getEGLThreadInfo()->eglError; +} + +__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) +{ + // search in EGL function table + for (int i=0; igetProcAddress( procname ); + if (proc != NULL) { + return (__eglMustCastToProperFunctionPointerType)proc; + } + + // look in gles2 + if (s_display.gles2_iface() != NULL) { + proc = s_display.gles2_iface()->getProcAddress( procname ); + if (proc != NULL) { + return (__eglMustCastToProperFunctionPointerType)proc; + } + } + + // Fail - function not found. + return NULL; +} + +const char* eglQueryString(EGLDisplay dpy, EGLint name) +{ + VALIDATE_DISPLAY_INIT(dpy, NULL); + + return s_display.queryString(name); +} + +EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + VALIDATE_DISPLAY_INIT(dpy, NULL); + + if(!num_config) { + RETURN_ERROR(EGL_FALSE,EGL_BAD_PARAMETER); + } + + GLint numConfigs = s_display.getNumConfigs(); + if (!configs) { + *num_config = numConfigs; + return EGL_TRUE; + } + + int i=0; + for (i=0 ; i + +static const int systemEGLVersionMajor = 1; +static const int systemEGLVersionMinor = 4; +static const char *systemEGLVendor = "Google Android emulator"; + +// list of extensions supported by this EGL implementation +// NOTE that each extension name should be suffixed with space +static const char *systemStaticEGLExtensions = + "EGL_ANDROID_image_native_buffer "; + +// list of extensions supported by this EGL implementation only if supported +// on the host implementation. +// NOTE that each extension name should be suffixed with space +static const char *systemDynamicEGLExtensions = + "EGL_KHR_image_base " + "EGL_KHR_gl_texture_2d_image "; + + +static void *s_gles_lib = NULL; +static void *s_gles2_lib = NULL; + +// The following function will be called when we (libEGL) +// gets unloaded +// At this point we want to unload the gles libraries we +// might have loaded during initialization +static void __attribute__ ((destructor)) do_on_unload(void) +{ + if (s_gles_lib) { + dlclose(s_gles_lib); + } + + if (s_gles2_lib) { + dlclose(s_gles2_lib); + } +} + +eglDisplay::eglDisplay() : + m_initialized(false), + m_major(0), + m_minor(0), + m_hostRendererVersion(0), + m_numConfigs(0), + m_numConfigAttribs(0), + m_attribs(DefaultKeyedVector(ATTRIBUTE_NONE)), + m_configs(NULL), + m_gles_iface(NULL), + m_gles2_iface(NULL), + m_versionString(NULL), + m_vendorString(NULL), + m_extensionString(NULL) +{ + pthread_mutex_init(&m_lock, NULL); +} + +bool eglDisplay::initialize(EGLClient_eglInterface *eglIface) +{ + pthread_mutex_lock(&m_lock); + if (!m_initialized) { + + // + // load GLES client API + // + m_gles_iface = loadGLESClientAPI("/system/lib/egl/libGLESv1_CM_emulation.so", + eglIface, + &s_gles_lib); + if (!m_gles_iface) { + pthread_mutex_unlock(&m_lock); + return false; + } + +#ifdef WITH_GLES2 + m_gles2_iface = loadGLESClientAPI("/system/lib/egl/libGLESv2_emulation.so", + eglIface, + &s_gles2_lib); + // Note that if loading gles2 failed, we can still run with no + // GLES2 support, having GLES2 is not mandatory. +#endif + + // + // establish connection with the host + // + HostConnection *hcon = HostConnection::get(); + if (!hcon) { + pthread_mutex_unlock(&m_lock); + return false; + } + + // + // get renderControl encoder instance + // + renderControl_encoder_context_t *rcEnc = hcon->rcEncoder(); + if (!rcEnc) { + pthread_mutex_unlock(&m_lock); + return false; + } + + // + // Query host reneder and EGL version + // + m_hostRendererVersion = rcEnc->rcGetRendererVersion(rcEnc); + EGLint status = rcEnc->rcGetEGLVersion(rcEnc, &m_major, &m_minor); + if (status != EGL_TRUE) { + // host EGL initialization failed !! + pthread_mutex_unlock(&m_lock); + return false; + } + + // + // Take minimum version beween what we support and what the host support + // + if (m_major > systemEGLVersionMajor) { + m_major = systemEGLVersionMajor; + m_minor = systemEGLVersionMinor; + } + else if (m_major == systemEGLVersionMajor && + m_minor > systemEGLVersionMinor) { + m_minor = systemEGLVersionMinor; + } + + // + // Query the host for the set of configs + // + m_numConfigs = rcEnc->rcGetNumConfigs(rcEnc, (uint32_t*)&m_numConfigAttribs); + if (m_numConfigs <= 0 || m_numConfigAttribs <= 0) { + // just sanity check - should never happen + pthread_mutex_unlock(&m_lock); + return false; + } + + uint32_t nInts = m_numConfigAttribs * (m_numConfigs + 1); + EGLint tmp_buf[nInts]; + m_configs = new EGLint[nInts-1]; + if (!m_configs) { + pthread_mutex_unlock(&m_lock); + return false; + } + + //EGLint n = rcEnc->rcGetConfigs(rcEnc, nInts*sizeof(EGLint), m_configs); + EGLint n = rcEnc->rcGetConfigs(rcEnc, nInts*sizeof(EGLint), (GLuint*)tmp_buf); + if (n != m_numConfigs) { + pthread_mutex_unlock(&m_lock); + return false; + } + + //Fill the attributes vector. + //The first m_numConfigAttribs values of tmp_buf are the actual attributes enums. + for (int i=0; ircEncoder(); + if (rcEnc) { + int n = rcEnc->rcQueryEGLString(rcEnc, name, NULL, 0); + if (n < 0) { + // allocate space for the string with additional + // space charachter to be suffixed at the end. + char *str = (char *)malloc(-n+2); + n = rcEnc->rcQueryEGLString(rcEnc, name, str, -n); + if (n > 0) { + // add extra space at end of string which will be + // needed later when filtering the extension list. + strcat(str, " "); + return str; + } + + free(str); + } + } + } + + return NULL; +} + +static bool findExtInList(const char* token, int tokenlen, const char* list) +{ + const char* p = list; + while (*p != '\0') { + const char* q = strchr(p, ' '); + if (q == NULL) { + /* should not happen, list must be space-terminated */ + break; + } + if (tokenlen == (q - p) && !memcmp(token, p, tokenlen)) { + return true; /* found it */ + } + p = q+1; + } + return false; /* not found */ +} + +static char *buildExtensionString() +{ + //Query host extension string + char *hostExt = queryHostEGLString(EGL_EXTENSIONS); + if (!hostExt || (hostExt[1] == '\0')) { + // no extensions on host - only static extension list supported + return strdup(systemStaticEGLExtensions); + } + + // + // Filter host extension list to include only extensions + // we can support (in the systemDynamicEGLExtensions list) + // + char *ext = (char *)hostExt; + char *c = ext; + char *insert = ext; + while(*c != '\0') { + if (*c == ' ') { + int len = c - ext; + if (findExtInList(ext, len, systemDynamicEGLExtensions)) { + if (ext != insert) { + memcpy(insert, ext, len+1); // including space + } + insert += (len + 1); + } + ext = c + 1; + } + c++; + } + *insert = '\0'; + + int n = strlen(hostExt); + if (n > 0) { + char *str; + asprintf(&str,"%s%s", systemStaticEGLExtensions, hostExt); + free((char*)hostExt); + return str; + } + else { + free((char*)hostExt); + return strdup(systemStaticEGLExtensions); + } +} + +const char *eglDisplay::queryString(EGLint name) +{ + if (name == EGL_CLIENT_APIS) { + return "OpenGL_ES"; + } + else if (name == EGL_VERSION) { + pthread_mutex_lock(&m_lock); + if (m_versionString) { + pthread_mutex_unlock(&m_lock); + return m_versionString; + } + + // build version string + asprintf(&m_versionString, "%d.%d", m_major, m_minor); + pthread_mutex_unlock(&m_lock); + + return m_versionString; + } + else if (name == EGL_VENDOR) { + pthread_mutex_lock(&m_lock); + if (m_vendorString) { + pthread_mutex_unlock(&m_lock); + return m_vendorString; + } + + // build vendor string + const char *hostVendor = queryHostEGLString(EGL_VENDOR); + + if (hostVendor) { + asprintf(&m_vendorString, "%s Host: %s", + systemEGLVendor, hostVendor); + free((char*)hostVendor); + } + else { + m_vendorString = (char *)systemEGLVendor; + } + pthread_mutex_unlock(&m_lock); + + return m_vendorString; + } + else if (name == EGL_EXTENSIONS) { + pthread_mutex_lock(&m_lock); + if (m_extensionString) { + pthread_mutex_unlock(&m_lock); + return m_extensionString; + } + + // build extension string + m_extensionString = buildExtensionString(); + pthread_mutex_unlock(&m_lock); + + return m_extensionString; + } + else { + LOGE("[%s] Unknown name %d\n", __FUNCTION__, name); + return NULL; + } +} + +EGLint eglDisplay::getConfigAttrib(EGLConfig config, EGLint attrib) +{ + EGLint attrIdx = m_attribs.valueFor(attrib); + + if (attrIdx == ATTRIBUTE_NONE) return ATTRIBUTE_NONE; + else return *(m_configs + (int)config*m_numConfigAttribs + attrIdx); +} diff --git a/tools/emulator/opengl/system/egl/eglDisplay.h b/tools/emulator/opengl/system/egl/eglDisplay.h new file mode 100644 index 000000000..8e52ee09a --- /dev/null +++ b/tools/emulator/opengl/system/egl/eglDisplay.h @@ -0,0 +1,71 @@ +/* +* 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 _SYSTEM_EGL_DISPLAY_H +#define _SYSTEM_EGL_DISPLAY_H + +#include +#include +#include +#include "EGLClientIface.h" +#include + +#define ATTRIBUTE_NONE -1 +//FIXME: are we in this namespace? +using namespace android; + +class eglDisplay +{ +public: + eglDisplay(); + + bool initialize(EGLClient_eglInterface *eglIface); + void terminate(); + + int getVersionMajor() const { return m_major; } + int getVersionMinor() const { return m_minor; } + bool initialized() const { return m_initialized; } + + const char *queryString(EGLint name); + + const EGLClient_glesInterface *gles_iface() const { return m_gles_iface; } + const EGLClient_glesInterface *gles2_iface() const { return m_gles2_iface; } + + int getNumConfigs(){ return m_numConfigs; } + EGLint getConfigAttrib(EGLConfig config, EGLint attrib); + +private: + EGLClient_glesInterface *loadGLESClientAPI(const char *libName, + EGLClient_eglInterface *eglIface, + void **libHandle); + +private: + pthread_mutex_t m_lock; + bool m_initialized; + int m_major; + int m_minor; + int m_hostRendererVersion; + int m_numConfigs; + int m_numConfigAttribs; + DefaultKeyedVector m_attribs; + EGLint *m_configs; + EGLClient_glesInterface *m_gles_iface; + EGLClient_glesInterface *m_gles2_iface; + char *m_versionString; + char *m_vendorString; + char *m_extensionString; +}; + +#endif diff --git a/tools/emulator/opengl/system/egl/egl_ftable.h b/tools/emulator/opengl/system/egl/egl_ftable.h new file mode 100644 index 000000000..ee4058590 --- /dev/null +++ b/tools/emulator/opengl/system/egl/egl_ftable.h @@ -0,0 +1,66 @@ +/* +* 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. +*/ +static struct _egl_funcs_by_name { + const char *name; + void *proc; +} egl_funcs_by_name[] = { + {"eglGetError", (void *)eglGetError}, + {"eglGetDisplay", (void *)eglGetDisplay}, + {"eglInitialize", (void *)eglInitialize}, + {"eglTerminate", (void *)eglTerminate}, + {"eglQueryString", (void *)eglQueryString}, + {"eglGetConfigs", (void *)eglGetConfigs}, + {"eglChooseConfig", (void *)eglChooseConfig}, + {"eglGetConfigAttrib", (void *)eglGetConfigAttrib}, + {"eglCreateWindowSurface", (void *)eglCreateWindowSurface}, + {"eglCreatePbufferSurface", (void *)eglCreatePbufferSurface}, + {"eglCreatePixmapSurface", (void *)eglCreatePixmapSurface}, + {"eglDestroySurface", (void *)eglDestroySurface}, + {"eglQuerySurface", (void *)eglQuerySurface}, + {"eglBindAPI", (void *)eglBindAPI}, + {"eglQueryAPI", (void *)eglQueryAPI}, + {"eglWaitClient", (void *)eglWaitClient}, + {"eglReleaseThread", (void *)eglReleaseThread}, + {"eglCreatePbufferFromClientBuffer", (void *)eglCreatePbufferFromClientBuffer}, + {"eglSurfaceAttrib", (void *)eglSurfaceAttrib}, + {"eglBindTexImage", (void *)eglBindTexImage}, + {"eglReleaseTexImage", (void *)eglReleaseTexImage}, + {"eglSwapInterval", (void *)eglSwapInterval}, + {"eglCreateContext", (void *)eglCreateContext}, + {"eglDestroyContext", (void *)eglDestroyContext}, + {"eglMakeCurrent", (void *)eglMakeCurrent}, + {"eglGetCurrentContext", (void *)eglGetCurrentContext}, + {"eglGetCurrentSurface", (void *)eglGetCurrentSurface}, + {"eglGetCurrentDisplay", (void *)eglGetCurrentDisplay}, + {"eglQueryContext", (void *)eglQueryContext}, + {"eglWaitGL", (void *)eglWaitGL}, + {"eglWaitNative", (void *)eglWaitNative}, + {"eglSwapBuffers", (void *)eglSwapBuffers}, + {"eglCopyBuffers", (void *)eglCopyBuffers}, + {"eglGetProcAddress", (void *)eglGetProcAddress}, + {"eglLockSurfaceKHR", (void *)eglLockSurfaceKHR}, + {"eglUnlockSurfaceKHR", (void *)eglUnlockSurfaceKHR}, + {"eglCreateImageKHR", (void *)eglCreateImageKHR}, + {"eglDestroyImageKHR", (void *)eglDestroyImageKHR}, + {"eglCreateSyncKHR", (void *)eglCreateSyncKHR}, + {"eglDestroySyncKHR", (void *)eglDestroySyncKHR}, + {"eglClientWaitSyncKHR", (void *)eglClientWaitSyncKHR}, + {"eglSignalSyncKHR", (void *)eglSignalSyncKHR}, + {"eglGetSyncAttribKHR", (void *)eglGetSyncAttribKHR}, + {"eglSetSwapRectangleANDROID", (void *)eglSetSwapRectangleANDROID} +}; + +static int egl_num_funcs = sizeof(egl_funcs_by_name) / sizeof(struct _egl_funcs_by_name);