diff options
author | keunyoung <keunyoung@google.com> | 2013-03-08 12:28:03 -0800 |
---|---|---|
committer | keunyoung <keunyoung@google.com> | 2013-03-11 10:57:27 -0700 |
commit | 8a94683196406b83b14218d1beef66067f126a16 (patch) | |
tree | a4b534173fee983175f175d611eb0840d0a4ff59 /opengl/system/egl | |
parent | a76102f225ebb6b00b0d3f84624a285e0f8df773 (diff) | |
download | android_device_generic_goldfish-8a94683196406b83b14218d1beef66067f126a16.tar.gz android_device_generic_goldfish-8a94683196406b83b14218d1beef66067f126a16.tar.bz2 android_device_generic_goldfish-8a94683196406b83b14218d1beef66067f126a16.zip |
migrate opengl and system from development/tools
- components under system are moved one directory up like all other HALs
Change-Id: I03b870b870d83b247ac398cadfb155f03c9adfa0
Diffstat (limited to 'opengl/system/egl')
-rw-r--r-- | opengl/system/egl/Android.mk | 41 | ||||
-rw-r--r-- | opengl/system/egl/ClientAPIExts.cpp | 157 | ||||
-rw-r--r-- | opengl/system/egl/ClientAPIExts.h | 29 | ||||
-rw-r--r-- | opengl/system/egl/ClientAPIExts.in | 201 | ||||
-rw-r--r-- | opengl/system/egl/egl.cfg | 1 | ||||
-rw-r--r-- | opengl/system/egl/egl.cpp | 1254 | ||||
-rw-r--r-- | opengl/system/egl/eglContext.h | 51 | ||||
-rw-r--r-- | opengl/system/egl/eglDisplay.cpp | 497 | ||||
-rw-r--r-- | opengl/system/egl/eglDisplay.h | 89 | ||||
-rw-r--r-- | opengl/system/egl/egl_ftable.h | 64 |
10 files changed, 2384 insertions, 0 deletions
diff --git a/opengl/system/egl/Android.mk b/opengl/system/egl/Android.mk new file mode 100644 index 0000000..a979089 --- /dev/null +++ b/opengl/system/egl/Android.mk @@ -0,0 +1,41 @@ +ifneq (false,$(BUILD_EMULATOR_OPENGL_DRIVER)) + +LOCAL_PATH := $(call my-dir) + +$(call emugl-begin-shared-library,libEGL_emulation) +$(call emugl-import,libOpenglSystemCommon) +$(call emugl-set-shared-library-subpath,egl) + +LOCAL_CFLAGS += -DLOG_TAG=\"EGL_emulation\" -DEGL_EGLEXT_PROTOTYPES -DWITH_GLES2 + +LOCAL_SRC_FILES := \ + eglDisplay.cpp \ + egl.cpp \ + ClientAPIExts.cpp + +LOCAL_SHARED_LIBRARIES += libdl + +# Used to access the Bionic private OpenGL TLS slot +LOCAL_C_INCLUDES += bionic/libc/private + +$(call emugl-end-module) + +#### egl.cfg #### + +# Ensure that this file is only copied to emulator-specific builds. +# Other builds are device-specific and will provide their own +# version of this file to point to the appropriate HW EGL libraries. +# +ifneq (,$(filter full full_x86 full_mips sdk sdk_x86 sdk_mips google_sdk google_sdk_x86 google_sdk_mips,$(TARGET_PRODUCT))) +include $(CLEAR_VARS) + +LOCAL_MODULE := egl.cfg +LOCAL_SRC_FILES := $(LOCAL_MODULE) + +LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/egl +LOCAL_MODULE_CLASS := ETC + +include $(BUILD_PREBUILT) +endif # TARGET_PRODUCT in 'full full_x86 full_mips sdk sdk_x86 sdk_mips google_sdk google_sdk_x86 google_sdk_mips') + +endif # BUILD_EMULATOR_OPENGL_DRIVER != false diff --git a/opengl/system/egl/ClientAPIExts.cpp b/opengl/system/egl/ClientAPIExts.cpp new file mode 100644 index 0000000..5e81afe --- /dev/null +++ b/opengl/system/egl/ClientAPIExts.cpp @@ -0,0 +1,157 @@ +/* +* 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 "ThreadInfo.h" +#include <GLES/gl.h> +#include <GLES/glext.h> +#include "eglContext.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[2]; + +#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(const EGLClient_glesInterface *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 \ + { \ + EGLThreadInfo* thread = getEGLThreadInfo(); \ + if (!thread->currentContext) { \ + return; \ + } \ + int idx = (int)thread->currentContext->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 \ + { \ + EGLThreadInfo* thread = getEGLThreadInfo(); \ + if (!thread->currentContext) { \ + return (rtype)0; \ + } \ + int idx = (int)thread->currentContext->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, (void*)_egl_ ## fname}, +#define API_ENTRY_RET(rtype,fname,params,args) \ + API_ENTRY(fname,params,args) + +static const struct _client_ext_funcs { + const char *fname; + void* 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. +// +void* 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 diff --git a/opengl/system/egl/ClientAPIExts.h b/opengl/system/egl/ClientAPIExts.h new file mode 100644 index 0000000..eee9172 --- /dev/null +++ b/opengl/system/egl/ClientAPIExts.h @@ -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 "EGLClientIface.h" + +namespace ClientAPIExts +{ + +void initClientFuncs(const EGLClient_glesInterface *iface, int idx); +void* getProcAddress(const char *fname); + +} // of namespace ClientAPIExts + +#endif diff --git a/opengl/system/egl/ClientAPIExts.in b/opengl/system/egl/ClientAPIExts.in new file mode 100644 index 0000000..5850701 --- /dev/null +++ b/opengl/system/egl/ClientAPIExts.in @@ -0,0 +1,201 @@ +// +// Each extension function should have one of the following +// macro definitions: +// API_ENTRY(funcname, paramlist, arglist) +// -or- (if the function has a 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)) diff --git a/opengl/system/egl/egl.cfg b/opengl/system/egl/egl.cfg new file mode 100644 index 0000000..9d3f2dc --- /dev/null +++ b/opengl/system/egl/egl.cfg @@ -0,0 +1 @@ +0 0 emulation diff --git a/opengl/system/egl/egl.cpp b/opengl/system/egl/egl.cpp new file mode 100644 index 0000000..da89c4d --- /dev/null +++ b/opengl/system/egl/egl.cpp @@ -0,0 +1,1254 @@ +/* +* 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 <cutils/log.h> +#include "gralloc_cb.h" +#include "GLClientState.h" +#include "GLSharedGroup.h" +#include "eglContext.h" +#include "ClientAPIExts.h" + +#include "GLEncoder.h" +#ifdef WITH_GLES2 +#include "GL2Encoder.h" +#endif + +#include <system/window.h> + +template<typename T> +static T setErrorFunc(GLint error, T returnValue) { + getEGLThreadInfo()->eglError = error; + return returnValue; +} + +const char * eglStrError(EGLint err) +{ + switch (err){ + case EGL_SUCCESS: return "EGL_SUCCESS"; + case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; + case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; + case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; + case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; + case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; + case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; + case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; + case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; + case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; + default: return "UNKNOWN"; + } +} + +#define LOG_EGL_ERRORS 1 + +#ifdef LOG_EGL_ERRORS + +#define setErrorReturn(error, retVal) \ + { \ + ALOGE("tid %d: %s(%d): error 0x%x (%s)", gettid(), __FUNCTION__, __LINE__, error, eglStrError(error)); \ + return setErrorFunc(error, retVal); \ + } + +#define RETURN_ERROR(ret,err) \ + ALOGE("tid %d: %s(%d): error 0x%x (%s)", gettid(), __FUNCTION__, __LINE__, err, eglStrError(err)); \ + getEGLThreadInfo()->eglError = err; \ + return ret; + +#else //!LOG_EGL_ERRORS + +#define setErrorReturn(error, retVal) return setErrorFunc(error, retVal); + +#define RETURN_ERROR(ret,err) \ + getEGLThreadInfo()->eglError = err; \ + return ret; + +#endif //LOG_EGL_ERRORS + +#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) { \ + RETURN_ERROR(ret, EGL_BAD_DISPLAY); \ + } + +#define VALIDATE_DISPLAY_INIT(dpy,ret) \ + VALIDATE_DISPLAY(dpy, ret) \ + if (!s_display.initialized()) { \ + RETURN_ERROR(ret, EGL_NOT_INITIALIZED); \ + } + +#define DEFINE_HOST_CONNECTION \ + HostConnection *hostCon = HostConnection::get(); \ + renderControl_encoder_context_t *rcEnc = (hostCon ? hostCon->rcEncoder() : NULL) + +#define DEFINE_AND_VALIDATE_HOST_CONNECTION(ret) \ + HostConnection *hostCon = HostConnection::get(); \ + if (!hostCon) { \ + ALOGE("egl: Failed to get host connection\n"); \ + return ret; \ + } \ + renderControl_encoder_context_t *rcEnc = hostCon->rcEncoder(); \ + if (!rcEnc) { \ + ALOGE("egl: Failed to get renderControl encoder context\n"); \ + return ret; \ + } + +#define VALIDATE_CONTEXT_RETURN(context,ret) \ + if (!context) { \ + RETURN_ERROR(ret,EGL_BAD_CONTEXT); \ + } + +#define VALIDATE_SURFACE_RETURN(surface, ret) \ + if (surface != EGL_NO_SURFACE) { \ + egl_surface_t* s( static_cast<egl_surface_t*>(surface) ); \ + if (s->dpy != (EGLDisplay)&s_display) \ + setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE); \ + } + + +EGLContext_t::EGLContext_t(EGLDisplay dpy, EGLConfig config, EGLContext_t* shareCtx) : + dpy(dpy), + config(config), + read(EGL_NO_SURFACE), + draw(EGL_NO_SURFACE), + shareCtx(shareCtx), + rcContext(0), + versionString(NULL), + vendorString(NULL), + rendererString(NULL), + extensionString(NULL) +{ + flags = 0; + version = 1; + clientState = new GLClientState(); + if (shareCtx) + sharedGroup = shareCtx->getSharedGroup(); + else + sharedGroup = GLSharedGroupPtr(new GLSharedGroup()); +}; + +EGLContext_t::~EGLContext_t() +{ + delete clientState; + delete [] versionString; + delete [] vendorString; + delete [] rendererString; + delete [] extensionString; +} + +// ---------------------------------------------------------------------------- +//egl_surface_t + +//we don't need to handle depth since it's handled when window created on the host + +struct egl_surface_t { + + EGLDisplay dpy; + EGLConfig config; + + + egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType); + virtual ~egl_surface_t(); + + virtual void setSwapInterval(int interval) = 0; + virtual EGLBoolean swapBuffers() = 0; + + EGLint getSwapBehavior() const; + uint32_t getRcSurface() { return rcSurface; } + EGLint getSurfaceType() { return surfaceType; } + + EGLint getWidth(){ return width; } + EGLint getHeight(){ return height; } + void setTextureFormat(EGLint _texFormat) { texFormat = _texFormat; } + EGLint getTextureFormat() { return texFormat; } + void setTextureTarget(EGLint _texTarget) { texTarget = _texTarget; } + EGLint getTextureTarget() { return texTarget; } + +private: + // + //Surface attributes + // + EGLint width; + EGLint height; + EGLint texFormat; + EGLint texTarget; + +protected: + void setWidth(EGLint w) { width = w; } + void setHeight(EGLint h) { height = h; } + + EGLint surfaceType; + uint32_t rcSurface; //handle to surface created via remote control +}; + +egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType) + : dpy(dpy), config(config), surfaceType(surfaceType), rcSurface(0) +{ + width = 0; + height = 0; + texFormat = EGL_NO_TEXTURE; + texTarget = EGL_NO_TEXTURE; +} + +EGLint egl_surface_t::getSwapBehavior() const { + return EGL_BUFFER_PRESERVED; +} + +egl_surface_t::~egl_surface_t() +{ +} + +// ---------------------------------------------------------------------------- +// egl_window_surface_t + +struct egl_window_surface_t : public egl_surface_t { + static egl_window_surface_t* create( + EGLDisplay dpy, EGLConfig config, EGLint surfType, + ANativeWindow* window); + + virtual ~egl_window_surface_t(); + + virtual void setSwapInterval(int interval); + virtual EGLBoolean swapBuffers(); + +private: + egl_window_surface_t( + EGLDisplay dpy, EGLConfig config, EGLint surfType, + ANativeWindow* window); + EGLBoolean init(); + + ANativeWindow* nativeWindow; + android_native_buffer_t* buffer; +}; + +egl_window_surface_t::egl_window_surface_t ( + EGLDisplay dpy, EGLConfig config, EGLint surfType, + ANativeWindow* window) +: egl_surface_t(dpy, config, surfType), + nativeWindow(window), + buffer(NULL) +{ + // keep a reference on the window + nativeWindow->common.incRef(&nativeWindow->common); + EGLint w,h; + nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &w); + setWidth(w); + nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &h); + setHeight(h); +} + +EGLBoolean egl_window_surface_t::init() +{ + if (nativeWindow->dequeueBuffer_DEPRECATED(nativeWindow, &buffer) != NO_ERROR) { + setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE); + } + + DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); + rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config, + getWidth(), getHeight()); + if (!rcSurface) { + ALOGE("rcCreateWindowSurface returned 0"); + return EGL_FALSE; + } + rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, + ((cb_handle_t*)(buffer->handle))->hostHandle); + + return EGL_TRUE; +} + +egl_window_surface_t* egl_window_surface_t::create( + EGLDisplay dpy, EGLConfig config, EGLint surfType, + ANativeWindow* window) +{ + egl_window_surface_t* wnd = new egl_window_surface_t( + dpy, config, surfType, window); + if (wnd && !wnd->init()) { + delete wnd; + wnd = NULL; + } + return wnd; +} + +egl_window_surface_t::~egl_window_surface_t() { + DEFINE_HOST_CONNECTION; + if (rcSurface && rcEnc) { + rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface); + } + if (buffer) { + nativeWindow->cancelBuffer_DEPRECATED(nativeWindow, buffer); + } + nativeWindow->common.decRef(&nativeWindow->common); +} + +void egl_window_surface_t::setSwapInterval(int interval) +{ + nativeWindow->setSwapInterval(nativeWindow, interval); +} + +EGLBoolean egl_window_surface_t::swapBuffers() +{ + DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); + + rcEnc->rcFlushWindowColorBuffer(rcEnc, rcSurface); + + nativeWindow->queueBuffer_DEPRECATED(nativeWindow, buffer); + if (nativeWindow->dequeueBuffer_DEPRECATED(nativeWindow, &buffer)) { + buffer = NULL; + setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE); + } + + rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, + ((cb_handle_t *)(buffer->handle))->hostHandle); + + return EGL_TRUE; +} + +// ---------------------------------------------------------------------------- +//egl_pbuffer_surface_t + +struct egl_pbuffer_surface_t : public egl_surface_t { + static egl_pbuffer_surface_t* create(EGLDisplay dpy, EGLConfig config, + EGLint surfType, int32_t w, int32_t h, GLenum pixelFormat); + + virtual ~egl_pbuffer_surface_t(); + + virtual void setSwapInterval(int interval) {} + virtual EGLBoolean swapBuffers() { return EGL_TRUE; } + + uint32_t getRcColorBuffer() { return rcColorBuffer; } + +private: + egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfType, + int32_t w, int32_t h); + EGLBoolean init(GLenum format); + + uint32_t rcColorBuffer; +}; + +egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, + EGLint surfType, int32_t w, int32_t h) +: egl_surface_t(dpy, config, surfType), + rcColorBuffer(0) +{ + setWidth(w); + setHeight(h); +} + +egl_pbuffer_surface_t::~egl_pbuffer_surface_t() +{ + DEFINE_HOST_CONNECTION; + if (rcEnc) { + if (rcColorBuffer) rcEnc->rcCloseColorBuffer(rcEnc, rcColorBuffer); + if (rcSurface) rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface); + } +} + +EGLBoolean egl_pbuffer_surface_t::init(GLenum pixelFormat) +{ + DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); + + rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config, + getWidth(), getHeight()); + if (!rcSurface) { + ALOGE("rcCreateWindowSurface returned 0"); + return EGL_FALSE; + } + + rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(), + pixelFormat); + if (!rcColorBuffer) { + ALOGE("rcCreateColorBuffer returned 0"); + return EGL_FALSE; + } + + rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, rcColorBuffer); + + return EGL_TRUE; +} + +egl_pbuffer_surface_t* egl_pbuffer_surface_t::create(EGLDisplay dpy, + EGLConfig config, EGLint surfType, int32_t w, int32_t h, + GLenum pixelFormat) +{ + egl_pbuffer_surface_t* pb = new egl_pbuffer_surface_t(dpy, config, surfType, + w, h); + if (pb && !pb->init(pixelFormat)) { + delete pb; + pb = NULL; + } + return pb; +} + +static const char *getGLString(int glEnum) +{ + EGLThreadInfo *tInfo = getEGLThreadInfo(); + if (!tInfo || !tInfo->currentContext) { + return NULL; + } + + const char** strPtr = NULL; + +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 + + switch(glEnum) { + case GL_VERSION: + strPtr = &tInfo->currentContext->versionString; + break; + case GL_VENDOR: + strPtr = &tInfo->currentContext->vendorString; + break; + case GL_RENDERER: + strPtr = &tInfo->currentContext->rendererString; + break; + case GL_EXTENSIONS: + strPtr = &tInfo->currentContext->extensionString; + break; + } + + if (!strPtr) { + return NULL; + } + + if (*strPtr != NULL) { + // + // string is already cached + // + return *strPtr; + } + + // + // first query of that string - need to query host + // + DEFINE_AND_VALIDATE_HOST_CONNECTION(NULL); + char *hostStr = NULL; + int n = rcEnc->rcGetGLString(rcEnc, glEnum, NULL, 0); + if (n < 0) { + hostStr = new char[-n+1]; + n = rcEnc->rcGetGLString(rcEnc, glEnum, hostStr, -n); + if (n <= 0) { + delete [] hostStr; + hostStr = NULL; + } + } + + // + // keep the string in the context and return its value + // + *strPtr = hostStr; + return hostStr; +} + +// ---------------------------------------------------------------------------- + +// The one and only supported display object. +static eglDisplay s_display; + +static EGLClient_eglInterface s_eglIface = { + getThreadInfo: getEGLThreadInfo, + getGLString: getGLString +}; + +#define DBG_FUNC DBG("%s\n", __FUNCTION__) +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; + } + if (major!=NULL) + *major = s_display.getVersionMajor(); + if (minor!=NULL) + *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() +{ + EGLint error = getEGLThreadInfo()->eglError; + getEGLThreadInfo()->eglError = EGL_SUCCESS; + return error; +} + +__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) +{ + // search in EGL function table + for (int i=0; i<egl_num_funcs; i++) { + if (!strcmp(egl_funcs_by_name[i].name, procname)) { + return (__eglMustCastToProperFunctionPointerType)egl_funcs_by_name[i].proc; + } + } + + // + // Make sure display is initialized before searching in client APIs + // + if (!s_display.initialized()) { + if (!s_display.initialize(&s_eglIface)) { + return NULL; + } + } + + // look in gles client api's extensions table + return (__eglMustCastToProperFunctionPointerType)ClientAPIExts::getProcAddress(procname); + + // 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<numConfigs && i<config_size ; i++) { + *configs++ = (EGLConfig)i; + } + *num_config = i; + return EGL_TRUE; +} + +EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + + int attribs_size = 0; + if (attrib_list) { + const EGLint * attrib_p = attrib_list; + while (attrib_p[0] != EGL_NONE) { + attribs_size += 2; + attrib_p += 2; + } + attribs_size++; //for the terminating EGL_NONE + } + + DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); + *num_config = rcEnc->rcChooseConfig(rcEnc, (EGLint*)attrib_list, attribs_size * sizeof(EGLint), (uint32_t*)configs, config_size); + + return EGL_TRUE; +} + +EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) +{ + VALIDATE_DISPLAY_INIT(dpy, NULL); + VALIDATE_CONFIG(config, EGL_FALSE); + + if (s_display.getConfigAttrib(config, attribute, value)) + { + return EGL_TRUE; + } + else + { + RETURN_ERROR(EGL_FALSE, EGL_BAD_ATTRIBUTE); + } +} + +EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) +{ + VALIDATE_DISPLAY_INIT(dpy, NULL); + VALIDATE_CONFIG(config, EGL_FALSE); + if (win == 0) { + setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + EGLint surfaceType; + if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE; + + if (!(surfaceType & EGL_WINDOW_BIT)) { + setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + if (static_cast<ANativeWindow*>(win)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) { + setErrorReturn(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + + egl_surface_t* surface = egl_window_surface_t::create( + &s_display, config, surfaceType, static_cast<ANativeWindow*>(win)); + if (!surface) { + setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + + return surface; +} + +EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) +{ + VALIDATE_DISPLAY_INIT(dpy, NULL); + VALIDATE_CONFIG(config, EGL_FALSE); + + EGLint surfaceType; + if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE; + + if (!(surfaceType & EGL_PBUFFER_BIT)) { + setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + int32_t w = 0; + int32_t h = 0; + EGLint texFormat = EGL_NO_TEXTURE; + EGLint texTarget = EGL_NO_TEXTURE; + while (attrib_list[0]) { + switch (attrib_list[0]) { + case EGL_WIDTH: + w = attrib_list[1]; + break; + case EGL_HEIGHT: + h = attrib_list[1]; + break; + case EGL_TEXTURE_FORMAT: + texFormat = attrib_list[1]; + break; + case EGL_TEXTURE_TARGET: + texTarget = attrib_list[1]; + break; + default: + break; + }; + attrib_list+=2; + } + if (((texFormat == EGL_NO_TEXTURE)&&(texTarget != EGL_NO_TEXTURE)) || + ((texFormat != EGL_NO_TEXTURE)&&(texTarget == EGL_NO_TEXTURE))) { + setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + // TODO: check EGL_TEXTURE_FORMAT - need to support eglBindTexImage + + GLenum pixelFormat; + if (s_display.getConfigGLPixelFormat(config, &pixelFormat) == EGL_FALSE) + setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); + + egl_surface_t* surface = egl_pbuffer_surface_t::create(dpy, config, + surfaceType, w, h, pixelFormat); + if (!surface) { + setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + + //setup attributes + surface->setTextureFormat(texFormat); + surface->setTextureTarget(texTarget); + + return surface; +} + +EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) +{ + //XXX: Pixmap not supported. The host cannot render to a pixmap resource + // located on host. In order to support Pixmaps we should either punt + // to s/w rendering -or- let the host render to a buffer that will be + // copied back to guest at some sync point. None of those methods not + // implemented and pixmaps are not used with OpenGL anyway ... + return EGL_NO_SURFACE; +} + +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE); + + egl_surface_t* surface(static_cast<egl_surface_t*>(eglSurface)); + delete surface; + + return EGL_TRUE; +} + +EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface eglSurface, EGLint attribute, EGLint *value) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE); + + egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) ); + EGLBoolean ret = EGL_TRUE; + switch (attribute) { + case EGL_CONFIG_ID: + ret = s_display.getConfigAttrib(surface->config, EGL_CONFIG_ID, value); + break; + case EGL_WIDTH: + *value = surface->getWidth(); + break; + case EGL_HEIGHT: + *value = surface->getHeight(); + break; + case EGL_TEXTURE_FORMAT: + *value = surface->getTextureFormat(); + break; + case EGL_TEXTURE_TARGET: + *value = surface->getTextureTarget(); + break; + case EGL_SWAP_BEHAVIOR: + *value = surface->getSwapBehavior(); + break; + case EGL_LARGEST_PBUFFER: + // not modified for a window or pixmap surface + // and we ignore it when creating a PBuffer surface (default is EGL_FALSE) + if (surface->getSurfaceType() & EGL_PBUFFER_BIT) *value = EGL_FALSE; + break; + //TODO: complete other attributes + default: + ALOGE("eglQuerySurface %x EGL_BAD_ATTRIBUTE", attribute); + ret = setErrorFunc(EGL_BAD_ATTRIBUTE, EGL_FALSE); + break; + } + + return ret; +} + +EGLBoolean eglBindAPI(EGLenum api) +{ + if (api != EGL_OPENGL_ES_API) + setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); + return EGL_TRUE; +} + +EGLenum eglQueryAPI() +{ + return EGL_OPENGL_ES_API; +} + +EGLBoolean eglWaitClient() +{ + return eglWaitGL(); +} + +EGLBoolean eglReleaseThread() +{ + EGLThreadInfo *tInfo = getEGLThreadInfo(); + if (tInfo && tInfo->currentContext) { + return eglMakeCurrent(&s_display, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); + } + return EGL_TRUE; +} + +EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) +{ + //TODO + ALOGW("%s not implemented", __FUNCTION__); + return 0; +} + +EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) +{ + //TODO + ALOGW("%s not implemented", __FUNCTION__); + return 0; +} + +EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface eglSurface, EGLint buffer) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE); + if (eglSurface == EGL_NO_SURFACE) { + setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); + } + + if (buffer != EGL_BACK_BUFFER) { + setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); + } + + egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) ); + + if (surface->getTextureFormat() == EGL_NO_TEXTURE) { + setErrorReturn(EGL_BAD_MATCH, EGL_FALSE); + } + + if (!(surface->getSurfaceType() & EGL_PBUFFER_BIT)) { + setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); + } + + //It's now safe to cast to pbuffer surface + egl_pbuffer_surface_t* pbSurface = (egl_pbuffer_surface_t*)surface; + + DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); + rcEnc->rcBindTexture(rcEnc, pbSurface->getRcColorBuffer()); + + return GL_TRUE; +} + +EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + //TODO + ALOGW("%s not implemented", __FUNCTION__); + return 0; +} + +EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); + + EGLContext_t* ctx = getEGLThreadInfo()->currentContext; + if (!ctx) { + setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE); + } + if (!ctx->draw) { + setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); + } + egl_surface_t* draw(static_cast<egl_surface_t*>(ctx->draw)); + draw->setSwapInterval(interval); + + rcEnc->rcFBSetSwapInterval(rcEnc, interval); //TODO: implement on the host + + return EGL_TRUE; +} + +EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_NO_CONTEXT); + VALIDATE_CONFIG(config, EGL_NO_CONTEXT); + + EGLint version = 1; //default + while (attrib_list && attrib_list[0]) { + if (attrib_list[0] == EGL_CONTEXT_CLIENT_VERSION) version = attrib_list[1]; + attrib_list+=2; + } + + uint32_t rcShareCtx = 0; + EGLContext_t * shareCtx = NULL; + if (share_context) { + shareCtx = static_cast<EGLContext_t*>(share_context); + rcShareCtx = shareCtx->rcContext; + if (shareCtx->dpy != dpy) + setErrorReturn(EGL_BAD_MATCH, EGL_NO_CONTEXT); + } + + DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_NO_CONTEXT); + uint32_t rcContext = rcEnc->rcCreateContext(rcEnc, (uint32_t)config, rcShareCtx, version); + if (!rcContext) { + ALOGE("rcCreateContext returned 0"); + setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT); + } + + EGLContext_t * context = new EGLContext_t(dpy, config, shareCtx); + if (!context) + setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT); + + context->version = version; + context->rcContext = rcContext; + + + return context; +} + +EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE); + + EGLContext_t * context = static_cast<EGLContext_t*>(ctx); + + if (getEGLThreadInfo()->currentContext == context) + { + eglMakeCurrent(dpy, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); + } + + if (context->rcContext) { + DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); + rcEnc->rcDestroyContext(rcEnc, context->rcContext); + context->rcContext = 0; + } + + delete context; + return EGL_TRUE; +} + +EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + VALIDATE_SURFACE_RETURN(draw, EGL_FALSE); + VALIDATE_SURFACE_RETURN(read, EGL_FALSE); + + if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT)) + setErrorReturn(EGL_BAD_MATCH, EGL_FALSE); + if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT)) + setErrorReturn(EGL_BAD_MATCH, EGL_FALSE); + + EGLContext_t * context = static_cast<EGLContext_t*>(ctx); + uint32_t ctxHandle = (context) ? context->rcContext : 0; + egl_surface_t * drawSurf = static_cast<egl_surface_t *>(draw); + uint32_t drawHandle = (drawSurf) ? drawSurf->getRcSurface() : 0; + egl_surface_t * readSurf = static_cast<egl_surface_t *>(read); + uint32_t readHandle = (readSurf) ? readSurf->getRcSurface() : 0; + + // + // Nothing to do if no binding change has made + // + EGLThreadInfo *tInfo = getEGLThreadInfo(); + if (tInfo->currentContext == context && + (context == NULL || + (context && context->draw == draw && context->read == read))) { + return EGL_TRUE; + } + + if (context && (context->flags & EGLContext_t::IS_CURRENT) && (context != tInfo->currentContext)) { + //context is current to another thread + setErrorReturn(EGL_BAD_ACCESS, EGL_FALSE); + } + + DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); + if (rcEnc->rcMakeCurrent(rcEnc, ctxHandle, drawHandle, readHandle) == EGL_FALSE) { + ALOGE("rcMakeCurrent returned EGL_FALSE"); + setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE); + } + + //Now make the local bind + if (context) { + context->draw = draw; + context->read = read; + context->flags |= EGLContext_t::IS_CURRENT; + //set the client state + if (context->version == 2) { + hostCon->gl2Encoder()->setClientState(context->getClientState()); + hostCon->gl2Encoder()->setSharedGroup(context->getSharedGroup()); + } + else { + hostCon->glEncoder()->setClientState(context->getClientState()); + hostCon->glEncoder()->setSharedGroup(context->getSharedGroup()); + } + } + else { + //release ClientState & SharedGroup + if (tInfo->currentContext->version == 2) { + hostCon->gl2Encoder()->setClientState(NULL); + hostCon->gl2Encoder()->setSharedGroup(GLSharedGroupPtr(NULL)); + } + else { + hostCon->glEncoder()->setClientState(NULL); + hostCon->glEncoder()->setSharedGroup(GLSharedGroupPtr(NULL)); + } + + } + + if (tInfo->currentContext) + tInfo->currentContext->flags &= ~EGLContext_t::IS_CURRENT; + + //Now make current + tInfo->currentContext = context; + + //Check maybe we need to init the encoder, if it's first eglMakeCurrent + if (tInfo->currentContext) { + if (tInfo->currentContext->version == 2) { + if (!hostCon->gl2Encoder()->isInitialized()) { + s_display.gles2_iface()->init(); + hostCon->gl2Encoder()->setInitialized(); + ClientAPIExts::initClientFuncs(s_display.gles2_iface(), 1); + } + } + else { + if (!hostCon->glEncoder()->isInitialized()) { + s_display.gles_iface()->init(); + hostCon->glEncoder()->setInitialized(); + ClientAPIExts::initClientFuncs(s_display.gles_iface(), 0); + } + } + } + + return EGL_TRUE; +} + +EGLContext eglGetCurrentContext() +{ + return getEGLThreadInfo()->currentContext; +} + +EGLSurface eglGetCurrentSurface(EGLint readdraw) +{ + EGLContext_t * context = getEGLThreadInfo()->currentContext; + if (!context) + return EGL_NO_SURFACE; //not an error + + switch (readdraw) { + case EGL_READ: + return context->read; + case EGL_DRAW: + return context->draw; + default: + setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + } +} + +EGLDisplay eglGetCurrentDisplay() +{ + EGLContext_t * context = getEGLThreadInfo()->currentContext; + if (!context) + return EGL_NO_DISPLAY; //not an error + + return context->dpy; +} + +EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE); + + EGLContext_t * context = static_cast<EGLContext_t*>(ctx); + + EGLBoolean ret = EGL_TRUE; + switch (attribute) { + case EGL_CONFIG_ID: + ret = s_display.getConfigAttrib(context->config, EGL_CONFIG_ID, value); + break; + case EGL_CONTEXT_CLIENT_TYPE: + *value = EGL_OPENGL_ES_API; + break; + case EGL_CONTEXT_CLIENT_VERSION: + *value = context->version; + break; + case EGL_RENDER_BUFFER: + if (!context->draw) + *value = EGL_NONE; + else + *value = EGL_BACK_BUFFER; //single buffer not supported + break; + default: + ALOGE("eglQueryContext %x EGL_BAD_ATTRIBUTE", attribute); + setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE); + break; + } + + return ret; +} + +EGLBoolean eglWaitGL() +{ + EGLThreadInfo *tInfo = getEGLThreadInfo(); + if (!tInfo || !tInfo->currentContext) { + return EGL_FALSE; + } + + if (tInfo->currentContext->version == 2) { + s_display.gles2_iface()->finish(); + } + else { + s_display.gles_iface()->finish(); + } + + return EGL_TRUE; +} + +EGLBoolean eglWaitNative(EGLint engine) +{ + return EGL_TRUE; +} + +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface eglSurface) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + if (eglSurface == EGL_NO_SURFACE) + setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); + + DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); + + egl_surface_t* d = static_cast<egl_surface_t*>(eglSurface); + if (d->dpy != dpy) + setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE); + + // post the surface + d->swapBuffers(); + + hostCon->flush(); + return EGL_TRUE; +} + +EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) +{ + //TODO :later + return 0; +} + +EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list) +{ + //TODO later + return 0; +} + +EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface) +{ + //TODO later + return 0; +} + +EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_NO_IMAGE_KHR); + if (ctx != EGL_NO_CONTEXT) { + setErrorReturn(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); + } + if (target != EGL_NATIVE_BUFFER_ANDROID) { + setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + } + + android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer; + + if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) + setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + + if (native_buffer->common.version != sizeof(android_native_buffer_t)) + setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + + cb_handle_t *cb = (cb_handle_t *)(native_buffer->handle); + + switch (cb->format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGB_888: + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + break; + default: + setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + } + + native_buffer->common.incRef(&native_buffer->common); + return (EGLImageKHR)native_buffer; +} + +EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) +{ + VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); + android_native_buffer_t* native_buffer = (android_native_buffer_t*)img; + + if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) + setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); + + if (native_buffer->common.version != sizeof(android_native_buffer_t)) + setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); + + native_buffer->common.decRef(&native_buffer->common); + + return EGL_TRUE; +} + +#define FENCE_SYNC_HANDLE (EGLSyncKHR)0xFE4CE + +EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, + const EGLint *attrib_list) +{ + // TODO: This implementation could be faster. We should require the host EGL + // to support KHR_fence_sync, or at least pipe the fence command to the host + // and wait for it (probably involving a glFinish on the host) in + // eglClientWaitSyncKHR. + + VALIDATE_DISPLAY(dpy, EGL_NO_SYNC_KHR); + + if (type != EGL_SYNC_FENCE_KHR || + (attrib_list != NULL && attrib_list[0] != EGL_NONE)) { + setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR); + } + + EGLThreadInfo *tInfo = getEGLThreadInfo(); + if (!tInfo || !tInfo->currentContext) { + setErrorReturn(EGL_BAD_MATCH, EGL_NO_SYNC_KHR); + } + + if (tInfo->currentContext->version == 2) { + s_display.gles2_iface()->finish(); + } else { + s_display.gles_iface()->finish(); + } + + return FENCE_SYNC_HANDLE; +} + +EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) +{ + if (sync != FENCE_SYNC_HANDLE) { + setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); + } + + return EGL_TRUE; +} + +EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, + EGLTimeKHR timeout) +{ + if (sync != FENCE_SYNC_HANDLE) { + setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); + } + + return EGL_CONDITION_SATISFIED_KHR; +} + +EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, + EGLint attribute, EGLint *value) +{ + if (sync != FENCE_SYNC_HANDLE) { + setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE); + } + + switch (attribute) { + case EGL_SYNC_TYPE_KHR: + *value = EGL_SYNC_FENCE_KHR; + return EGL_TRUE; + case EGL_SYNC_STATUS_KHR: + *value = EGL_SIGNALED_KHR; + return EGL_TRUE; + case EGL_SYNC_CONDITION_KHR: + *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR; + return EGL_TRUE; + default: + setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } +} diff --git a/opengl/system/egl/eglContext.h b/opengl/system/egl/eglContext.h new file mode 100644 index 0000000..2ca6d0c --- /dev/null +++ b/opengl/system/egl/eglContext.h @@ -0,0 +1,51 @@ +/* +* 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 _EGL_CONTEXT_H +#define _EGL_CONTEXT_H + +#include "GLClientState.h" +#include "GLSharedGroup.h" + +struct EGLContext_t { + + enum { + IS_CURRENT = 0x00010000, + NEVER_CURRENT = 0x00020000 + }; + + EGLContext_t(EGLDisplay dpy, EGLConfig config, EGLContext_t* shareCtx); + ~EGLContext_t(); + uint32_t flags; + EGLDisplay dpy; + EGLConfig config; + EGLSurface read; + EGLSurface draw; + EGLContext_t * shareCtx; + EGLint version; + uint32_t rcContext; + const char* versionString; + const char* vendorString; + const char* rendererString; + const char* extensionString; + + GLClientState * getClientState(){ return clientState; } + GLSharedGroupPtr getSharedGroup(){ return sharedGroup; } +private: + GLClientState * clientState; + GLSharedGroupPtr sharedGroup; +}; + +#endif diff --git a/opengl/system/egl/eglDisplay.cpp b/opengl/system/egl/eglDisplay.cpp new file mode 100644 index 0000000..bcb0d4b --- /dev/null +++ b/opengl/system/egl/eglDisplay.cpp @@ -0,0 +1,497 @@ +/* +* 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 "eglDisplay.h" +#include "HostConnection.h" +#include <dlfcn.h> + +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 " + "EGL_KHR_fence_sync "; + +// 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<EGLint, EGLint>(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); +} + +eglDisplay::~eglDisplay() +{ + pthread_mutex_destroy(&m_lock); +} + +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); + ALOGE("Failed to load gles1 iface"); + 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); + ALOGE("Failed to establish connection with the host\n"); + return false; + } + + // + // get renderControl encoder instance + // + renderControl_encoder_context_t *rcEnc = hcon->rcEncoder(); + if (!rcEnc) { + pthread_mutex_unlock(&m_lock); + ALOGE("Failed to get renderControl encoder instance"); + 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-m_numConfigAttribs]; + 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; i<m_numConfigAttribs; i++) { + m_attribs.add(tmp_buf[i], i); + } + + //Copy the actual configs data to m_configs + memcpy(m_configs, tmp_buf + m_numConfigAttribs, m_numConfigs*m_numConfigAttribs*sizeof(EGLint)); + + m_initialized = true; + } + pthread_mutex_unlock(&m_lock); + + processConfigs(); + + return true; +} + +void eglDisplay::processConfigs() +{ + for (int i=0; i<m_numConfigs; i++) { + EGLConfig config = (EGLConfig)i; + //Setup the EGL_NATIVE_VISUAL_ID attribute + PixelFormat format; + if (getConfigNativePixelFormat(config, &format)) { + setConfigAttrib(config, EGL_NATIVE_VISUAL_ID, format); + } + } +} + +void eglDisplay::terminate() +{ + pthread_mutex_lock(&m_lock); + if (m_initialized) { + m_initialized = false; + delete [] m_configs; + m_configs = NULL; + + if (m_versionString) { + free(m_versionString); + m_versionString = NULL; + } + if (m_vendorString) { + free(m_vendorString); + m_vendorString = NULL; + } + if (m_extensionString) { + free(m_extensionString); + m_extensionString = NULL; + } + } + pthread_mutex_unlock(&m_lock); +} + +EGLClient_glesInterface *eglDisplay::loadGLESClientAPI(const char *libName, + EGLClient_eglInterface *eglIface, + void **libHandle) +{ + void *lib = dlopen(libName, RTLD_NOW); + if (!lib) { + ALOGE("Failed to dlopen %s", libName); + return NULL; + } + + init_emul_gles_t init_gles_func = (init_emul_gles_t)dlsym(lib,"init_emul_gles"); + if (!init_gles_func) { + ALOGE("Failed to find init_emul_gles"); + dlclose((void*)lib); + return NULL; + } + + *libHandle = lib; + return (*init_gles_func)(eglIface); +} + +static char *queryHostEGLString(EGLint name) +{ + HostConnection *hcon = HostConnection::get(); + if (hcon) { + renderControl_encoder_context_t *rcEnc = hcon->rcEncoder(); + 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 { + ALOGE("[%s] Unknown name %d\n", __FUNCTION__, name); + return NULL; + } +} + +/* To get the value of attribute <a> of config <c> use the following formula: + * value = *(m_configs + (int)c*m_numConfigAttribs + a); + */ +EGLBoolean eglDisplay::getAttribValue(EGLConfig config, EGLint attribIdx, EGLint * value) +{ + if (attribIdx == ATTRIBUTE_NONE) + { + ALOGE("[%s] Bad attribute idx\n", __FUNCTION__); + return EGL_FALSE; + } + *value = *(m_configs + (int)config*m_numConfigAttribs + attribIdx); + return EGL_TRUE; +} + +EGLBoolean eglDisplay::getConfigAttrib(EGLConfig config, EGLint attrib, EGLint * value) +{ + //Though it seems that valueFor() is thread-safe, we don't take chanses + pthread_mutex_lock(&m_lock); + EGLBoolean ret = getAttribValue(config, m_attribs.valueFor(attrib), value); + pthread_mutex_unlock(&m_lock); + return ret; +} + +void eglDisplay::dumpConfig(EGLConfig config) +{ + EGLint value = 0; + DBG("^^^^^^^^^^ dumpConfig %d ^^^^^^^^^^^^^^^^^^", (int)config); + for (int i=0; i<m_numConfigAttribs; i++) { + getAttribValue(config, i, &value); + DBG("{%d}[%d] %d\n", (int)config, i, value); + } +} + +/* To set the value of attribute <a> of config <c> use the following formula: + * *(m_configs + (int)c*m_numConfigAttribs + a) = value; + */ +EGLBoolean eglDisplay::setAttribValue(EGLConfig config, EGLint attribIdx, EGLint value) +{ + if (attribIdx == ATTRIBUTE_NONE) + { + ALOGE("[%s] Bad attribute idx\n", __FUNCTION__); + return EGL_FALSE; + } + *(m_configs + (int)config*m_numConfigAttribs + attribIdx) = value; + return EGL_TRUE; +} + +EGLBoolean eglDisplay::setConfigAttrib(EGLConfig config, EGLint attrib, EGLint value) +{ + //Though it seems that valueFor() is thread-safe, we don't take chanses + pthread_mutex_lock(&m_lock); + EGLBoolean ret = setAttribValue(config, m_attribs.valueFor(attrib), value); + pthread_mutex_unlock(&m_lock); + return ret; +} + + +EGLBoolean eglDisplay::getConfigNativePixelFormat(EGLConfig config, PixelFormat * format) +{ + EGLint redSize, blueSize, greenSize, alphaSize; + + if ( !(getAttribValue(config, m_attribs.valueFor(EGL_RED_SIZE), &redSize) && + getAttribValue(config, m_attribs.valueFor(EGL_BLUE_SIZE), &blueSize) && + getAttribValue(config, m_attribs.valueFor(EGL_GREEN_SIZE), &greenSize) && + getAttribValue(config, m_attribs.valueFor(EGL_ALPHA_SIZE), &alphaSize)) ) + { + ALOGE("Couldn't find value for one of the pixel format attributes"); + return EGL_FALSE; + } + + //calculate the GL internal format + if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==8)) *format = PIXEL_FORMAT_RGBA_8888; //XXX: BGR? + else if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==0)) *format = PIXEL_FORMAT_RGBX_8888; //XXX or PIXEL_FORMAT_RGB_888 + else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = PIXEL_FORMAT_RGB_565; + else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = PIXEL_FORMAT_RGBA_5551; + else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = PIXEL_FORMAT_RGBA_4444; + else { + return EGL_FALSE; + } + return EGL_TRUE; +} +EGLBoolean eglDisplay::getConfigGLPixelFormat(EGLConfig config, GLenum * format) +{ + EGLint redSize, blueSize, greenSize, alphaSize; + + if ( !(getAttribValue(config, m_attribs.valueFor(EGL_RED_SIZE), &redSize) && + getAttribValue(config, m_attribs.valueFor(EGL_BLUE_SIZE), &blueSize) && + getAttribValue(config, m_attribs.valueFor(EGL_GREEN_SIZE), &greenSize) && + getAttribValue(config, m_attribs.valueFor(EGL_ALPHA_SIZE), &alphaSize)) ) + { + ALOGE("Couldn't find value for one of the pixel format attributes"); + return EGL_FALSE; + } + + //calculate the GL internal format + if ((redSize==8)&&(blueSize==8)&&(blueSize==8)&&(alphaSize==8)) *format = GL_RGBA; + else if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==0)) *format = GL_RGB; + else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = GL_RGB565_OES; + else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = GL_RGB5_A1_OES; + else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = GL_RGBA4_OES; + else return EGL_FALSE; + + return EGL_TRUE; +} diff --git a/opengl/system/egl/eglDisplay.h b/opengl/system/egl/eglDisplay.h new file mode 100644 index 0000000..9d979d9 --- /dev/null +++ b/opengl/system/egl/eglDisplay.h @@ -0,0 +1,89 @@ +/* +* 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 <pthread.h> +#include "glUtils.h" +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include "EGLClientIface.h" +#include <utils/KeyedVector.h> + +#include <ui/PixelFormat.h> + +#define ATTRIBUTE_NONE -1 +//FIXME: are we in this namespace? +using namespace android; + +class eglDisplay +{ +public: + eglDisplay(); + ~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; } + EGLBoolean getConfigAttrib(EGLConfig config, EGLint attrib, EGLint * value); + EGLBoolean setConfigAttrib(EGLConfig config, EGLint attrib, EGLint value); + EGLBoolean getConfigGLPixelFormat(EGLConfig config, GLenum * format); + EGLBoolean getConfigNativePixelFormat(EGLConfig config, PixelFormat * format); + + void dumpConfig(EGLConfig config); +private: + EGLClient_glesInterface *loadGLESClientAPI(const char *libName, + EGLClient_eglInterface *eglIface, + void **libHandle); + EGLBoolean getAttribValue(EGLConfig config, EGLint attribIdxi, EGLint * value); + EGLBoolean setAttribValue(EGLConfig config, EGLint attribIdxi, EGLint value); + void processConfigs(); + +private: + pthread_mutex_t m_lock; + bool m_initialized; + int m_major; + int m_minor; + int m_hostRendererVersion; + int m_numConfigs; + int m_numConfigAttribs; + + /* This is the mapping between an attribute name to it's index in any given config */ + DefaultKeyedVector<EGLint, EGLint> m_attribs; + /* This is an array of all config's attributes values stored in the following sequencial fasion (read: v[c,a] = the value of attribute <a> of config <c>) + * v[0,0],..,v[0,m_numConfigAttribs-1], + *... + * v[m_numConfigs-1,0],..,v[m_numConfigs-1,m_numConfigAttribs-1] + */ + 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/opengl/system/egl/egl_ftable.h b/opengl/system/egl/egl_ftable.h new file mode 100644 index 0000000..16d130c --- /dev/null +++ b/opengl/system/egl/egl_ftable.h @@ -0,0 +1,64 @@ +/* +* 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 const 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}, + {"eglGetSyncAttribKHR", (void *)eglGetSyncAttribKHR} +}; + +static const int egl_num_funcs = sizeof(egl_funcs_by_name) / sizeof(struct _egl_funcs_by_name); |