diff options
Diffstat (limited to 'emulator/opengl/shared')
34 files changed, 4333 insertions, 0 deletions
diff --git a/emulator/opengl/shared/OpenglCodecCommon/Android.mk b/emulator/opengl/shared/OpenglCodecCommon/Android.mk new file mode 100644 index 0000000..7deb058 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/Android.mk @@ -0,0 +1,54 @@ +# This build script corresponds to a library containing many definitions +# common to both the guest and the host. They relate to +# +LOCAL_PATH := $(call my-dir) + +commonSources := \ + GLClientState.cpp \ + GLSharedGroup.cpp \ + glUtils.cpp \ + SocketStream.cpp \ + TcpStream.cpp \ + TimeUtils.cpp + +host_commonSources := $(commonSources) + +ifeq ($(HOST_OS),windows) + host_commonSources += Win32PipeStream.cpp +else + host_commonSources += UnixStream.cpp +endif + + +### CodecCommon guest ############################################## +$(call emugl-begin-static-library,libOpenglCodecCommon) + +LOCAL_SRC_FILES := $(commonSources) + +LOCAL_CFLAGS += -DLOG_TAG=\"eglCodecCommon\" + +$(call emugl-export,SHARED_LIBRARIES,libcutils libutils) +$(call emugl-export,C_INCLUDES,$(LOCAL_PATH)) +$(call emugl-end-module) + + +### OpenglCodecCommon host ############################################## +$(call emugl-begin-host-static-library,libOpenglCodecCommon) + +LOCAL_SRC_FILES := $(host_commonSources) + +$(call emugl-export,STATIC_LIBRARIES,libcutils) +$(call emugl-export,C_INCLUDES,$(LOCAL_PATH)) +$(call emugl-end-module) + + +### OpenglCodecCommon host, 64-bit ######################################### +$(call emugl-begin-host-static-library,lib64OpenglCodecCommon) + +LOCAL_SRC_FILES := $(host_commonSources) + +$(call emugl-export,STATIC_LIBRARIES,lib64cutils) +$(call emugl-export,C_INCLUDES,$(LOCAL_PATH)) +$(call emugl-export,CFLAGS,-m64) +$(call emugl-end-module) + diff --git a/emulator/opengl/shared/OpenglCodecCommon/ErrorLog.h b/emulator/opengl/shared/OpenglCodecCommon/ErrorLog.h new file mode 100644 index 0000000..6f41fd7 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/ErrorLog.h @@ -0,0 +1,37 @@ +/* +* 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 _ERROR_LOG_H_ +#define _ERROR_LOG_H_ + +#if (HAVE_ANDROID_OS == 1) +# include <cutils/log.h> +# define ERR(...) ALOGE(__VA_ARGS__) +# ifdef EMUGL_DEBUG +# define DBG(...) ALOGD(__VA_ARGS__) +# else +# define DBG(...) ((void)0) +# endif +#else +# include <stdio.h> +# define ERR(...) fprintf(stderr, __VA_ARGS__) +# ifdef EMUGL_DEBUG +# define DBG(...) fprintf(stderr, __VA_ARGS__) +# else +# define DBG(...) ((void)0) +# endif +#endif + +#endif diff --git a/emulator/opengl/shared/OpenglCodecCommon/FixedBuffer.h b/emulator/opengl/shared/OpenglCodecCommon/FixedBuffer.h new file mode 100644 index 0000000..30b9a80 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/FixedBuffer.h @@ -0,0 +1,53 @@ +/* +* 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 _FIXED_BUFFER_H +#define _FIXED_BUFFER_H + +class FixedBuffer { +public: + FixedBuffer(size_t initialSize = 0) { + m_buffer = NULL; + m_bufferLen = 0; + alloc(m_bufferLen); + } + + ~FixedBuffer() { + delete [] m_buffer; + m_bufferLen = 0; + } + + void * alloc(size_t size) { + if (m_bufferLen >= size) + return (void *)(m_buffer); + + if (m_buffer != NULL) + delete[] m_buffer; + + m_bufferLen = size; + m_buffer = new unsigned char[m_bufferLen]; + if (m_buffer == NULL) + m_bufferLen = 0; + + return m_buffer; + } + void *ptr() { return m_buffer; } + size_t len() { return m_bufferLen; } +private: + unsigned char *m_buffer; + size_t m_bufferLen; +}; + +#endif diff --git a/emulator/opengl/shared/OpenglCodecCommon/GLClientState.cpp b/emulator/opengl/shared/OpenglCodecCommon/GLClientState.cpp new file mode 100644 index 0000000..9795490 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/GLClientState.cpp @@ -0,0 +1,417 @@ +/* +* 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 "GLClientState.h" +#include "ErrorLog.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "glUtils.h" +#include <cutils/log.h> + +#ifndef MAX +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#endif + +GLClientState::GLClientState(int nLocations) +{ + if (nLocations < LAST_LOCATION) { + nLocations = LAST_LOCATION; + } + m_nLocations = nLocations; + m_states = new VertexAttribState[m_nLocations]; + for (int i = 0; i < m_nLocations; i++) { + m_states[i].enabled = 0; + m_states[i].enableDirty = false; + } + m_currentArrayVbo = 0; + m_currentIndexVbo = 0; + // init gl constans; + m_states[VERTEX_LOCATION].glConst = GL_VERTEX_ARRAY; + m_states[NORMAL_LOCATION].glConst = GL_NORMAL_ARRAY; + m_states[COLOR_LOCATION].glConst = GL_COLOR_ARRAY; + m_states[POINTSIZE_LOCATION].glConst = GL_POINT_SIZE_ARRAY_OES; + m_states[TEXCOORD0_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY; + m_states[TEXCOORD1_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY; + m_states[TEXCOORD2_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY; + m_states[TEXCOORD3_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY; + m_states[TEXCOORD4_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY; + m_states[TEXCOORD5_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY; + m_states[TEXCOORD6_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY; + m_states[TEXCOORD7_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY; + m_states[MATRIXINDEX_LOCATION].glConst = GL_MATRIX_INDEX_ARRAY_OES; + m_states[WEIGHT_LOCATION].glConst = GL_WEIGHT_ARRAY_OES; + m_activeTexture = 0; + m_currentProgram = 0; + + m_pixelStore.unpack_alignment = 4; + m_pixelStore.pack_alignment = 4; + + memset(m_tex.unit, 0, sizeof(m_tex.unit)); + m_tex.activeUnit = &m_tex.unit[0]; + m_tex.textures = NULL; + m_tex.numTextures = 0; + m_tex.allocTextures = 0; +} + +GLClientState::~GLClientState() +{ + delete m_states; +} + +void GLClientState::enable(int location, int state) +{ + if (!validLocation(location)) { + return; + } + + m_states[location].enableDirty |= (state != m_states[location].enabled); + m_states[location].enabled = state; +} + +void GLClientState::setState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data) +{ + if (!validLocation(location)) { + return; + } + m_states[location].size = size; + m_states[location].type = type; + m_states[location].stride = stride; + m_states[location].data = (void*)data; + m_states[location].bufferObject = m_currentArrayVbo; + m_states[location].elementSize = glSizeof(type) * size; + m_states[location].normalized = normalized; +} + +void GLClientState::setBufferObject(int location, GLuint id) +{ + if (!validLocation(location)) { + return; + } + + m_states[location].bufferObject = id; +} + +const GLClientState::VertexAttribState * GLClientState::getState(int location) +{ + if (!validLocation(location)) { + return NULL; + } + return & m_states[location]; +} + +const GLClientState::VertexAttribState * GLClientState::getStateAndEnableDirty(int location, bool *enableChanged) +{ + if (!validLocation(location)) { + return NULL; + } + + if (enableChanged) { + *enableChanged = m_states[location].enableDirty; + } + + m_states[location].enableDirty = false; + return & m_states[location]; +} + +int GLClientState::getLocation(GLenum loc) +{ + int retval; + + switch(loc) { + case GL_VERTEX_ARRAY: + retval = int(VERTEX_LOCATION); + break; + case GL_NORMAL_ARRAY: + retval = int(NORMAL_LOCATION); + break; + case GL_COLOR_ARRAY: + retval = int(COLOR_LOCATION); + break; + case GL_POINT_SIZE_ARRAY_OES: + retval = int(POINTSIZE_LOCATION); + break; + case GL_TEXTURE_COORD_ARRAY: + retval = int (TEXCOORD0_LOCATION + m_activeTexture); + break; + case GL_MATRIX_INDEX_ARRAY_OES: + retval = int (MATRIXINDEX_LOCATION); + break; + case GL_WEIGHT_ARRAY_OES: + retval = int (WEIGHT_LOCATION); + break; + default: + retval = loc; + } + return retval; +} + +void GLClientState::getClientStatePointer(GLenum pname, GLvoid** params) +{ + const GLClientState::VertexAttribState *state = NULL; + switch (pname) { + case GL_VERTEX_ARRAY_POINTER: { + state = getState(GLClientState::VERTEX_LOCATION); + break; + } + case GL_NORMAL_ARRAY_POINTER: { + state = getState(GLClientState::NORMAL_LOCATION); + break; + } + case GL_COLOR_ARRAY_POINTER: { + state = getState(GLClientState::COLOR_LOCATION); + break; + } + case GL_TEXTURE_COORD_ARRAY_POINTER: { + state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION); + break; + } + case GL_POINT_SIZE_ARRAY_POINTER_OES: { + state = getState(GLClientState::POINTSIZE_LOCATION); + break; + } + case GL_MATRIX_INDEX_ARRAY_POINTER_OES: { + state = getState(GLClientState::MATRIXINDEX_LOCATION); + break; + } + case GL_WEIGHT_ARRAY_POINTER_OES: { + state = getState(GLClientState::WEIGHT_LOCATION); + break; + } + } + if (state && params) + *params = state->data; +} + +int GLClientState::setPixelStore(GLenum param, GLint value) +{ + int retval = 0; + switch(param) { + case GL_UNPACK_ALIGNMENT: + if (value == 1 || value == 2 || value == 4 || value == 8) { + m_pixelStore.unpack_alignment = value; + } else { + retval = GL_INVALID_VALUE; + } + break; + case GL_PACK_ALIGNMENT: + if (value == 1 || value == 2 || value == 4 || value == 8) { + m_pixelStore.pack_alignment = value; + } else { + retval = GL_INVALID_VALUE; + } + break; + default: + retval = GL_INVALID_ENUM; + } + return retval; +} + + + + +size_t GLClientState::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack) const +{ + int pixelsize = glUtilsPixelBitSize(format, type) >> 3; + + int alignment = pack ? m_pixelStore.pack_alignment : m_pixelStore.unpack_alignment; + + if (pixelsize == 0 ) { + ERR("unknown pixel size: width: %d height: %d format: %d type: %d pack: %d align: %d\n", + width, height, format, type, pack, alignment); + } + size_t linesize = pixelsize * width; + size_t aligned_linesize = int(linesize / alignment) * alignment; + if (aligned_linesize < linesize) { + aligned_linesize += alignment; + } + return aligned_linesize * height; +} + +GLenum GLClientState::setActiveTextureUnit(GLenum texture) +{ + GLuint unit = texture - GL_TEXTURE0; + if (unit >= MAX_TEXTURE_UNITS) { + return GL_INVALID_OPERATION; + } + m_tex.activeUnit = &m_tex.unit[unit]; + return GL_NO_ERROR; +} + +GLenum GLClientState::getActiveTextureUnit() const +{ + return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]); +} + +void GLClientState::enableTextureTarget(GLenum target) +{ + switch (target) { + case GL_TEXTURE_2D: + m_tex.activeUnit->enables |= (1u << TEXTURE_2D); + break; + case GL_TEXTURE_EXTERNAL_OES: + m_tex.activeUnit->enables |= (1u << TEXTURE_EXTERNAL); + break; + } +} + +void GLClientState::disableTextureTarget(GLenum target) +{ + switch (target) { + case GL_TEXTURE_2D: + m_tex.activeUnit->enables &= ~(1u << TEXTURE_2D); + break; + case GL_TEXTURE_EXTERNAL_OES: + m_tex.activeUnit->enables &= ~(1u << TEXTURE_EXTERNAL); + break; + } +} + +GLenum GLClientState::getPriorityEnabledTarget(GLenum allDisabled) const +{ + unsigned int enables = m_tex.activeUnit->enables; + if (enables & (1u << TEXTURE_EXTERNAL)) { + return GL_TEXTURE_EXTERNAL_OES; + } else if (enables & (1u << TEXTURE_2D)) { + return GL_TEXTURE_2D; + } else { + return allDisabled; + } +} + +int GLClientState::compareTexId(const void* pid, const void* prec) +{ + const GLuint* id = (const GLuint*)pid; + const TextureRec* rec = (const TextureRec*)prec; + return (GLint)(*id) - (GLint)rec->id; +} + +GLenum GLClientState::bindTexture(GLenum target, GLuint texture, + GLboolean* firstUse) +{ + GLboolean first = GL_FALSE; + TextureRec* texrec = NULL; + if (texture != 0) { + if (m_tex.textures) { + texrec = (TextureRec*)bsearch(&texture, m_tex.textures, + m_tex.numTextures, sizeof(TextureRec), compareTexId); + } + if (!texrec) { + if (!(texrec = addTextureRec(texture, target))) { + return GL_OUT_OF_MEMORY; + } + first = GL_TRUE; + } + if (target != texrec->target) { + return GL_INVALID_OPERATION; + } + } + + switch (target) { + case GL_TEXTURE_2D: + m_tex.activeUnit->texture[TEXTURE_2D] = texture; + break; + case GL_TEXTURE_EXTERNAL_OES: + m_tex.activeUnit->texture[TEXTURE_EXTERNAL] = texture; + break; + } + + if (firstUse) { + *firstUse = first; + } + + return GL_NO_ERROR; +} + +GLClientState::TextureRec* GLClientState::addTextureRec(GLuint id, + GLenum target) +{ + if (m_tex.numTextures == m_tex.allocTextures) { + const GLuint MAX_TEXTURES = 0xFFFFFFFFu; + + GLuint newAlloc; + if (MAX_TEXTURES - m_tex.allocTextures >= m_tex.allocTextures) { + newAlloc = MAX(4, 2 * m_tex.allocTextures); + } else { + if (m_tex.allocTextures == MAX_TEXTURES) { + return NULL; + } + newAlloc = MAX_TEXTURES; + } + + TextureRec* newTextures = (TextureRec*)realloc(m_tex.textures, + newAlloc * sizeof(TextureRec)); + if (!newTextures) { + return NULL; + } + + m_tex.textures = newTextures; + m_tex.allocTextures = newAlloc; + } + + TextureRec* tex = m_tex.textures + m_tex.numTextures; + TextureRec* prev = tex - 1; + while (tex != m_tex.textures && id < prev->id) { + *tex-- = *prev--; + } + tex->id = id; + tex->target = target; + m_tex.numTextures++; + + return tex; +} + +GLuint GLClientState::getBoundTexture(GLenum target) const +{ + switch (target) { + case GL_TEXTURE_2D: + return m_tex.activeUnit->texture[TEXTURE_2D]; + case GL_TEXTURE_EXTERNAL_OES: + return m_tex.activeUnit->texture[TEXTURE_EXTERNAL]; + default: + return 0; + } +} + +void GLClientState::deleteTextures(GLsizei n, const GLuint* textures) +{ + // Updating the textures array could be made more efficient when deleting + // several textures: + // - compacting the array could be done in a single pass once the deleted + // textures are marked, or + // - could swap deleted textures to the end and re-sort. + TextureRec* texrec; + for (const GLuint* texture = textures; texture != textures + n; texture++) { + texrec = (TextureRec*)bsearch(texture, m_tex.textures, + m_tex.numTextures, sizeof(TextureRec), compareTexId); + if (texrec) { + const TextureRec* end = m_tex.textures + m_tex.numTextures; + memmove(texrec, texrec + 1, + (end - texrec - 1) * sizeof(TextureRec)); + m_tex.numTextures--; + + for (TextureUnit* unit = m_tex.unit; + unit != m_tex.unit + MAX_TEXTURE_UNITS; + unit++) + { + if (unit->texture[TEXTURE_2D] == *texture) { + unit->texture[TEXTURE_2D] = 0; + } else if (unit->texture[TEXTURE_EXTERNAL] == *texture) { + unit->texture[TEXTURE_EXTERNAL] = 0; + } + } + } + } +} diff --git a/emulator/opengl/shared/OpenglCodecCommon/GLClientState.h b/emulator/opengl/shared/OpenglCodecCommon/GLClientState.h new file mode 100644 index 0000000..c86329b --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/GLClientState.h @@ -0,0 +1,441 @@ +/* +* 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 _GL_CLIENT_STATE_H_ +#define _GL_CLIENT_STATE_H_ + +#define GL_API +#ifndef ANDROID +#define GL_APIENTRY +#define GL_APIENTRYP +#endif + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <stdio.h> +#include <stdlib.h> +#include "ErrorLog.h" +#include "codec_defs.h" + +class GLClientState { +public: + typedef enum { + VERTEX_LOCATION = 0, + NORMAL_LOCATION = 1, + COLOR_LOCATION = 2, + POINTSIZE_LOCATION = 3, + TEXCOORD0_LOCATION = 4, + TEXCOORD1_LOCATION = 5, + TEXCOORD2_LOCATION = 6, + TEXCOORD3_LOCATION = 7, + TEXCOORD4_LOCATION = 8, + TEXCOORD5_LOCATION = 9, + TEXCOORD6_LOCATION = 10, + TEXCOORD7_LOCATION = 11, + MATRIXINDEX_LOCATION = 12, + WEIGHT_LOCATION = 13, + LAST_LOCATION = 14 + } StateLocation; + + typedef struct { + GLint enabled; + GLint size; + GLenum type; + GLsizei stride; + void *data; + GLuint bufferObject; + GLenum glConst; + unsigned int elementSize; + bool enableDirty; // true if any enable state has changed since last draw + bool normalized; + } VertexAttribState; + + typedef struct { + int unpack_alignment; + int pack_alignment; + } PixelStoreState; + + enum { + MAX_TEXTURE_UNITS = 32, + }; + +public: + GLClientState(int nLocations = CODEC_MAX_VERTEX_ATTRIBUTES); + ~GLClientState(); + int nLocations() { return m_nLocations; } + const PixelStoreState *pixelStoreState() { return &m_pixelStore; } + int setPixelStore(GLenum param, GLint value); + GLuint currentArrayVbo() { return m_currentArrayVbo; } + GLuint currentIndexVbo() { return m_currentIndexVbo; } + void enable(int location, int state); + void setState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data); + void setBufferObject(int location, GLuint id); + const VertexAttribState *getState(int location); + const VertexAttribState *getStateAndEnableDirty(int location, bool *enableChanged); + int getLocation(GLenum loc); + void setActiveTexture(int texUnit) {m_activeTexture = texUnit; }; + int getActiveTexture() const { return m_activeTexture; } + + int bindBuffer(GLenum target, GLuint id) + { + int err = 0; + switch(target) { + case GL_ARRAY_BUFFER: + m_currentArrayVbo = id; + break; + case GL_ELEMENT_ARRAY_BUFFER: + m_currentIndexVbo = id; + break; + default: + err = -1; + } + return err; + } + + int getBuffer(GLenum target) + { + int ret=0; + switch (target) { + case GL_ARRAY_BUFFER: + ret = m_currentArrayVbo; + break; + case GL_ELEMENT_ARRAY_BUFFER: + ret = m_currentIndexVbo; + break; + default: + ret = -1; + } + return ret; + } + size_t pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack) const; + + void setCurrentProgram(GLint program) { m_currentProgram = program; } + GLint currentProgram() const { return m_currentProgram; } + + /* OES_EGL_image_external + * + * These functions manipulate GL state which interacts with the + * OES_EGL_image_external extension, to support client-side emulation on + * top of host implementations that don't have it. + * + * Most of these calls should only be used with TEXTURE_2D or + * TEXTURE_EXTERNAL_OES texture targets; TEXTURE_CUBE_MAP or other extension + * targets should bypass this. An exception is bindTexture(), which should + * see all glBindTexture() calls for any target. + */ + + // glActiveTexture(GL_TEXTURE0 + i) + // Sets the active texture unit. Up to MAX_TEXTURE_UNITS are supported. + GLenum setActiveTextureUnit(GLenum texture); + GLenum getActiveTextureUnit() const; + + // glEnable(GL_TEXTURE_(2D|EXTERNAL_OES)) + void enableTextureTarget(GLenum target); + + // glDisable(GL_TEXTURE_(2D|EXTERNAL_OES)) + void disableTextureTarget(GLenum target); + + // Implements the target priority logic: + // * Return GL_TEXTURE_EXTERNAL_OES if enabled, else + // * Return GL_TEXTURE_2D if enabled, else + // * Return the allDisabled value. + // For some cases passing GL_TEXTURE_2D for allDisabled makes callee code + // simpler; for other cases passing a recognizable enum like GL_ZERO or + // GL_INVALID_ENUM is appropriate. + GLenum getPriorityEnabledTarget(GLenum allDisabled) const; + + // glBindTexture(GL_TEXTURE_*, ...) + // Set the target binding of the active texture unit to texture. Returns + // GL_NO_ERROR on success or GL_INVALID_OPERATION if the texture has + // previously been bound to a different target. If firstUse is not NULL, + // it is set to indicate whether this is the first use of the texture. + // For accurate error detection, bindTexture should be called for *all* + // targets, not just 2D and EXTERNAL_OES. + GLenum bindTexture(GLenum target, GLuint texture, GLboolean* firstUse); + + // Return the texture currently bound to GL_TEXTURE_(2D|EXTERNAL_OES). + GLuint getBoundTexture(GLenum target) const; + + // glDeleteTextures(...) + // Remove references to the to-be-deleted textures. + void deleteTextures(GLsizei n, const GLuint* textures); + +private: + PixelStoreState m_pixelStore; + VertexAttribState *m_states; + int m_nLocations; + GLuint m_currentArrayVbo; + GLuint m_currentIndexVbo; + int m_activeTexture; + GLint m_currentProgram; + + bool validLocation(int location) { return (location >= 0 && location < m_nLocations); } + + enum TextureTarget { + TEXTURE_2D = 0, + TEXTURE_EXTERNAL = 1, + TEXTURE_TARGET_COUNT + }; + struct TextureUnit { + unsigned int enables; + GLuint texture[TEXTURE_TARGET_COUNT]; + }; + struct TextureRec { + GLuint id; + GLenum target; + }; + struct TextureState { + TextureUnit unit[MAX_TEXTURE_UNITS]; + TextureUnit* activeUnit; + TextureRec* textures; + GLuint numTextures; + GLuint allocTextures; + }; + TextureState m_tex; + + static int compareTexId(const void* pid, const void* prec); + TextureRec* addTextureRec(GLuint id, GLenum target); + +public: + void getClientStatePointer(GLenum pname, GLvoid** params); + + template <class T> + int getVertexAttribParameter(GLuint index, GLenum param, T *ptr) + { + bool handled = true; + const VertexAttribState *vertexAttrib = getState(index); + if (vertexAttrib == NULL) { + ERR("getVeterxAttriParameter for non existant index %d\n", index); + // set gl error; + return handled; + } + + switch(param) { + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + *ptr = (T)(vertexAttrib->bufferObject); + break; + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + *ptr = (T)(vertexAttrib->enabled); + break; + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + *ptr = (T)(vertexAttrib->size); + break; + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + *ptr = (T)(vertexAttrib->stride); + break; + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + *ptr = (T)(vertexAttrib->type); + break; + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + *ptr = (T)(vertexAttrib->normalized); + break; + case GL_CURRENT_VERTEX_ATTRIB: + handled = false; + break; + default: + handled = false; + ERR("unknown vertex-attrib parameter param %d\n", param); + } + return handled; + } + + template <class T> + bool getClientStateParameter(GLenum param, T* ptr) + { + bool isClientStateParam = false; + switch (param) { + case GL_CLIENT_ACTIVE_TEXTURE: { + GLint tex = getActiveTexture() + GL_TEXTURE0; + *ptr = tex; + isClientStateParam = true; + break; + } + case GL_VERTEX_ARRAY_SIZE: { + const GLClientState::VertexAttribState *state = getState(GLClientState::VERTEX_LOCATION); + *ptr = state->size; + isClientStateParam = true; + break; + } + case GL_VERTEX_ARRAY_TYPE: { + const GLClientState::VertexAttribState *state = getState(GLClientState::VERTEX_LOCATION); + *ptr = state->type; + isClientStateParam = true; + break; + } + case GL_VERTEX_ARRAY_STRIDE: { + const GLClientState::VertexAttribState *state = getState(GLClientState::VERTEX_LOCATION); + *ptr = state->stride; + isClientStateParam = true; + break; + } + case GL_COLOR_ARRAY_SIZE: { + const GLClientState::VertexAttribState *state = getState(GLClientState::COLOR_LOCATION); + *ptr = state->size; + isClientStateParam = true; + break; + } + case GL_COLOR_ARRAY_TYPE: { + const GLClientState::VertexAttribState *state = getState(GLClientState::COLOR_LOCATION); + *ptr = state->type; + isClientStateParam = true; + break; + } + case GL_COLOR_ARRAY_STRIDE: { + const GLClientState::VertexAttribState *state = getState(GLClientState::COLOR_LOCATION); + *ptr = state->stride; + isClientStateParam = true; + break; + } + case GL_NORMAL_ARRAY_TYPE: { + const GLClientState::VertexAttribState *state = getState(GLClientState::NORMAL_LOCATION); + *ptr = state->type; + isClientStateParam = true; + break; + } + case GL_NORMAL_ARRAY_STRIDE: { + const GLClientState::VertexAttribState *state = getState(GLClientState::NORMAL_LOCATION); + *ptr = state->stride; + isClientStateParam = true; + break; + } + case GL_TEXTURE_COORD_ARRAY_SIZE: { + const GLClientState::VertexAttribState *state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION); + *ptr = state->size; + isClientStateParam = true; + break; + } + case GL_TEXTURE_COORD_ARRAY_TYPE: { + const GLClientState::VertexAttribState *state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION); + *ptr = state->type; + isClientStateParam = true; + break; + } + case GL_TEXTURE_COORD_ARRAY_STRIDE: { + const GLClientState::VertexAttribState *state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION); + *ptr = state->stride; + isClientStateParam = true; + break; + } + case GL_POINT_SIZE_ARRAY_TYPE_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::POINTSIZE_LOCATION); + *ptr = state->type; + isClientStateParam = true; + break; + } + case GL_POINT_SIZE_ARRAY_STRIDE_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::POINTSIZE_LOCATION); + *ptr = state->stride; + isClientStateParam = true; + break; + } + case GL_MATRIX_INDEX_ARRAY_SIZE_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::MATRIXINDEX_LOCATION); + *ptr = state->size; + isClientStateParam = true; + break; + } + case GL_MATRIX_INDEX_ARRAY_TYPE_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::MATRIXINDEX_LOCATION); + *ptr = state->type; + isClientStateParam = true; + break; + } + case GL_MATRIX_INDEX_ARRAY_STRIDE_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::MATRIXINDEX_LOCATION); + *ptr = state->stride; + isClientStateParam = true; + break; + } + case GL_WEIGHT_ARRAY_SIZE_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::WEIGHT_LOCATION); + *ptr = state->size; + isClientStateParam = true; + break; + } + case GL_WEIGHT_ARRAY_TYPE_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::WEIGHT_LOCATION); + *ptr = state->type; + isClientStateParam = true; + break; + } + case GL_WEIGHT_ARRAY_STRIDE_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::WEIGHT_LOCATION); + *ptr = state->stride; + isClientStateParam = true; + break; + } + case GL_VERTEX_ARRAY_BUFFER_BINDING: { + const GLClientState::VertexAttribState *state = getState(GLClientState::VERTEX_LOCATION); + *ptr = state->bufferObject; + isClientStateParam = true; + break; + } + case GL_NORMAL_ARRAY_BUFFER_BINDING: { + const GLClientState::VertexAttribState *state = getState(GLClientState::NORMAL_LOCATION); + *ptr = state->bufferObject; + isClientStateParam = true; + break; + } + case GL_COLOR_ARRAY_BUFFER_BINDING: { + const GLClientState::VertexAttribState *state = getState(GLClientState::COLOR_LOCATION); + *ptr = state->bufferObject; + isClientStateParam = true; + break; + } + case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: { + const GLClientState::VertexAttribState *state = getState(getActiveTexture()+GLClientState::TEXCOORD0_LOCATION); + *ptr = state->bufferObject; + isClientStateParam = true; + break; + } + case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::POINTSIZE_LOCATION); + *ptr = state->bufferObject; + isClientStateParam = true; + break; + } + case GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::MATRIXINDEX_LOCATION); + *ptr = state->bufferObject; + isClientStateParam = true; + break; + } + case GL_WEIGHT_ARRAY_BUFFER_BINDING_OES: { + const GLClientState::VertexAttribState *state = getState(GLClientState::WEIGHT_LOCATION); + *ptr = state->bufferObject; + isClientStateParam = true; + break; + } + case GL_ARRAY_BUFFER_BINDING: { + int buffer = getBuffer(GL_ARRAY_BUFFER); + *ptr = buffer; + isClientStateParam = true; + break; + } + case GL_ELEMENT_ARRAY_BUFFER_BINDING: { + int buffer = getBuffer(GL_ELEMENT_ARRAY_BUFFER); + *ptr = buffer; + isClientStateParam = true; + break; + } + } + return isClientStateParam; + } + +}; +#endif diff --git a/emulator/opengl/shared/OpenglCodecCommon/GLDecoderContextData.h b/emulator/opengl/shared/OpenglCodecCommon/GLDecoderContextData.h new file mode 100644 index 0000000..23785ae --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/GLDecoderContextData.h @@ -0,0 +1,69 @@ +/* +* 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 _GL_DECODER_CONTEXT_DATA_H_ +#define _GL_DECODER_CONTEXT_DATA_H_ + +#include <assert.h> +#include <string.h> +#include "FixedBuffer.h" +#include "codec_defs.h" + +class GLDecoderContextData { +public: + typedef enum { + VERTEX_LOCATION = 0, + NORMAL_LOCATION = 1, + COLOR_LOCATION = 2, + POINTSIZE_LOCATION = 3, + TEXCOORD0_LOCATION = 4, + TEXCOORD1_LOCATION = 5, + TEXCOORD2_LOCATION = 6, + TEXCOORD3_LOCATION = 7, + TEXCOORD4_LOCATION = 8, + TEXCOORD5_LOCATION = 9, + TEXCOORD6_LOCATION = 10, + TEXCOORD7_LOCATION = 11, + MATRIXINDEX_LOCATION = 12, + WEIGHT_LOCATION = 13, + LAST_LOCATION = 14 + } PointerDataLocation; + + GLDecoderContextData(int nLocations = CODEC_MAX_VERTEX_ATTRIBUTES) : + m_nLocations(nLocations) + { + m_pointerData = new FixedBuffer[m_nLocations]; + } + + ~GLDecoderContextData() { + delete [] m_pointerData; + } + + void storePointerData(unsigned int loc, void *data, size_t len) { + + assert(loc < m_nLocations); + m_pointerData[loc].alloc(len); + memcpy(m_pointerData[loc].ptr(), data, len); + } + void *pointerData(unsigned int loc) { + assert(loc < m_nLocations); + return m_pointerData[loc].ptr(); + } +private: + FixedBuffer *m_pointerData; + int m_nLocations; +}; + +#endif diff --git a/emulator/opengl/shared/OpenglCodecCommon/GLErrorLog.h b/emulator/opengl/shared/OpenglCodecCommon/GLErrorLog.h new file mode 100644 index 0000000..5654aea --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/GLErrorLog.h @@ -0,0 +1,34 @@ +/* +* Copyright 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 __GL_ERROR_LOG_H__ +#define __GL_ERROR_LOG_H__ + +#include "ErrorLog.h" + +#ifdef CHECK_GL_ERROR +void dbg(){} +#define GET_GL_ERROR(gl) \ + { \ + int err = gl.glGetError(); \ + if (err) { dbg(); ERR("Error: 0x%X in %s (%s:%d)\n", err, __FUNCTION__, __FILE__, __LINE__); } \ + } + +#else +#define GET_GL_ERROR(gl) +#endif + +#endif //__GL_ERROR_LOG_H__ diff --git a/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp new file mode 100644 index 0000000..8504f7f --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp @@ -0,0 +1,469 @@ +/* +* 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 "GLSharedGroup.h" + +/**** BufferData ****/ + +BufferData::BufferData() : m_size(0) {}; +BufferData::BufferData(GLsizeiptr size, void * data) : m_size(size) +{ + void * buffer = NULL; + if (size>0) buffer = m_fixedBuffer.alloc(size); + if (data) memcpy(buffer, data, size); +} + +/**** ProgramData ****/ +ProgramData::ProgramData() : m_numIndexes(0), + m_initialized(false), + m_locShiftWAR(false) +{ + m_Indexes = NULL; +} + +void ProgramData::initProgramData(GLuint numIndexes) +{ + m_initialized = true; + m_numIndexes = numIndexes; + delete[] m_Indexes; + m_Indexes = new IndexInfo[numIndexes]; + m_locShiftWAR = false; +} + +bool ProgramData::isInitialized() +{ + return m_initialized; +} + +ProgramData::~ProgramData() +{ + delete[] m_Indexes; + m_Indexes = NULL; +} + +void ProgramData::setIndexInfo(GLuint index, GLint base, GLint size, GLenum type) +{ + if (index>=m_numIndexes) + return; + m_Indexes[index].base = base; + m_Indexes[index].size = size; + m_Indexes[index].type = type; + if (index > 0) { + m_Indexes[index].appBase = m_Indexes[index-1].appBase + + m_Indexes[index-1].size; + } + else { + m_Indexes[index].appBase = 0; + } + m_Indexes[index].hostLocsPerElement = 1; + m_Indexes[index].flags = 0; + m_Indexes[index].samplerValue = 0; +} + +void ProgramData::setIndexFlags(GLuint index, GLuint flags) +{ + if (index >= m_numIndexes) + return; + m_Indexes[index].flags |= flags; +} + +GLuint ProgramData::getIndexForLocation(GLint location) +{ + GLuint index = m_numIndexes; + GLint minDist = -1; + for (GLuint i=0;i<m_numIndexes;++i) + { + GLint dist = location - m_Indexes[i].base; + if (dist >= 0 && + (minDist < 0 || dist < minDist)) { + index = i; + minDist = dist; + } + } + return index; +} + +GLenum ProgramData::getTypeForLocation(GLint location) +{ + GLuint index = getIndexForLocation(location); + if (index<m_numIndexes) { + return m_Indexes[index].type; + } + return 0; +} + +void ProgramData::setupLocationShiftWAR() +{ + m_locShiftWAR = false; + for (GLuint i=0; i<m_numIndexes; i++) { + if (0 != (m_Indexes[i].base & 0xffff)) { + return; + } + } + // if we have one uniform at location 0, we do not need the WAR. + if (m_numIndexes > 1) { + m_locShiftWAR = true; + } +} + +GLint ProgramData::locationWARHostToApp(GLint hostLoc, GLint arrIndex) +{ + if (!m_locShiftWAR) return hostLoc; + + GLuint index = getIndexForLocation(hostLoc); + if (index<m_numIndexes) { + if (arrIndex > 0) { + m_Indexes[index].hostLocsPerElement = + (hostLoc - m_Indexes[index].base) / arrIndex; + } + return m_Indexes[index].appBase + arrIndex; + } + return -1; +} + +GLint ProgramData::locationWARAppToHost(GLint appLoc) +{ + if (!m_locShiftWAR) return appLoc; + + for(GLuint i=0; i<m_numIndexes; i++) { + GLint elemIndex = appLoc - m_Indexes[i].appBase; + if (elemIndex >= 0 && elemIndex < m_Indexes[i].size) { + return m_Indexes[i].base + + elemIndex * m_Indexes[i].hostLocsPerElement; + } + } + return -1; +} + +GLint ProgramData::getNextSamplerUniform(GLint index, GLint* val, GLenum* target) +{ + for (GLint i = index + 1; i >= 0 && i < (GLint)m_numIndexes; i++) { + if (m_Indexes[i].type == GL_SAMPLER_2D) { + if (val) *val = m_Indexes[i].samplerValue; + if (target) { + if (m_Indexes[i].flags & INDEX_FLAG_SAMPLER_EXTERNAL) { + *target = GL_TEXTURE_EXTERNAL_OES; + } else { + *target = GL_TEXTURE_2D; + } + } + return i; + } + } + return -1; +} + +bool ProgramData::setSamplerUniform(GLint appLoc, GLint val, GLenum* target) +{ + for (GLuint i = 0; i < m_numIndexes; i++) { + GLint elemIndex = appLoc - m_Indexes[i].appBase; + if (elemIndex >= 0 && elemIndex < m_Indexes[i].size) { + if (m_Indexes[i].type == GL_TEXTURE_2D) { + m_Indexes[i].samplerValue = val; + if (target) { + if (m_Indexes[i].flags & INDEX_FLAG_SAMPLER_EXTERNAL) { + *target = GL_TEXTURE_EXTERNAL_OES; + } else { + *target = GL_TEXTURE_2D; + } + } + return true; + } + } + } + return false; +} + +bool ProgramData::attachShader(GLuint shader) +{ + size_t n = m_shaders.size(); + for (size_t i = 0; i < n; i++) { + if (m_shaders[i] == shader) { + return false; + } + } + // AKA m_shaders.push_back(), but that has an ambiguous call to insertAt() + // due to the default parameters. This is the desired insertAt() overload. + m_shaders.insertAt(shader, m_shaders.size(), 1); + return true; +} + +bool ProgramData::detachShader(GLuint shader) +{ + size_t n = m_shaders.size(); + for (size_t i = 0; i < n; i++) { + if (m_shaders[i] == shader) { + m_shaders.removeAt(i); + return true; + } + } + return false; +} + +/***** GLSharedGroup ****/ + +GLSharedGroup::GLSharedGroup() : + m_buffers(android::DefaultKeyedVector<GLuint, BufferData*>(NULL)), + m_programs(android::DefaultKeyedVector<GLuint, ProgramData*>(NULL)), + m_shaders(android::DefaultKeyedVector<GLuint, ShaderData*>(NULL)) +{ +} + +GLSharedGroup::~GLSharedGroup() +{ + m_buffers.clear(); + m_programs.clear(); +} + +BufferData * GLSharedGroup::getBufferData(GLuint bufferId) +{ + android::AutoMutex _lock(m_lock); + return m_buffers.valueFor(bufferId); +} + +void GLSharedGroup::addBufferData(GLuint bufferId, GLsizeiptr size, void * data) +{ + android::AutoMutex _lock(m_lock); + m_buffers.add(bufferId, new BufferData(size, data)); +} + +void GLSharedGroup::updateBufferData(GLuint bufferId, GLsizeiptr size, void * data) +{ + android::AutoMutex _lock(m_lock); + m_buffers.replaceValueFor(bufferId, new BufferData(size, data)); +} + +GLenum GLSharedGroup::subUpdateBufferData(GLuint bufferId, GLintptr offset, GLsizeiptr size, void * data) +{ + android::AutoMutex _lock(m_lock); + BufferData * buf = m_buffers.valueFor(bufferId); + if ((!buf) || (buf->m_size < offset+size) || (offset < 0) || (size<0)) return GL_INVALID_VALUE; + + //it's safe to update now + memcpy((char*)buf->m_fixedBuffer.ptr() + offset, data, size); + return GL_NO_ERROR; +} + +void GLSharedGroup::deleteBufferData(GLuint bufferId) +{ + android::AutoMutex _lock(m_lock); + m_buffers.removeItem(bufferId); +} + +void GLSharedGroup::addProgramData(GLuint program) +{ + android::AutoMutex _lock(m_lock); + ProgramData *pData = m_programs.valueFor(program); + if (pData) + { + m_programs.removeItem(program); + delete pData; + } + + m_programs.add(program,new ProgramData()); +} + +void GLSharedGroup::initProgramData(GLuint program, GLuint numIndexes) +{ + android::AutoMutex _lock(m_lock); + ProgramData *pData = m_programs.valueFor(program); + if (pData) + { + pData->initProgramData(numIndexes); + } +} + +bool GLSharedGroup::isProgramInitialized(GLuint program) +{ + android::AutoMutex _lock(m_lock); + ProgramData* pData = m_programs.valueFor(program); + if (pData) + { + return pData->isInitialized(); + } + return false; +} + +void GLSharedGroup::deleteProgramData(GLuint program) +{ + android::AutoMutex _lock(m_lock); + ProgramData *pData = m_programs.valueFor(program); + if (pData) + delete pData; + m_programs.removeItem(program); +} + +void GLSharedGroup::attachShader(GLuint program, GLuint shader) +{ + android::AutoMutex _lock(m_lock); + ProgramData* programData = m_programs.valueFor(program); + ssize_t idx = m_shaders.indexOfKey(shader); + if (programData && idx >= 0) { + if (programData->attachShader(shader)) { + refShaderDataLocked(idx); + } + } +} + +void GLSharedGroup::detachShader(GLuint program, GLuint shader) +{ + android::AutoMutex _lock(m_lock); + ProgramData* programData = m_programs.valueFor(program); + ssize_t idx = m_shaders.indexOfKey(shader); + if (programData && idx >= 0) { + if (programData->detachShader(shader)) { + unrefShaderDataLocked(idx); + } + } +} + +void GLSharedGroup::setProgramIndexInfo(GLuint program, GLuint index, GLint base, GLint size, GLenum type, const char* name) +{ + android::AutoMutex _lock(m_lock); + ProgramData* pData = m_programs.valueFor(program); + if (pData) + { + pData->setIndexInfo(index,base,size,type); + + if (type == GL_SAMPLER_2D) { + size_t n = pData->getNumShaders(); + for (size_t i = 0; i < n; i++) { + GLuint shaderId = pData->getShader(i); + ShaderData* shader = m_shaders.valueFor(shaderId); + if (!shader) continue; + ShaderData::StringList::iterator nameIter = shader->samplerExternalNames.begin(); + ShaderData::StringList::iterator nameEnd = shader->samplerExternalNames.end(); + while (nameIter != nameEnd) { + if (*nameIter == name) { + pData->setIndexFlags(index, ProgramData::INDEX_FLAG_SAMPLER_EXTERNAL); + break; + } + ++nameIter; + } + } + } + } +} + +GLenum GLSharedGroup::getProgramUniformType(GLuint program, GLint location) +{ + android::AutoMutex _lock(m_lock); + ProgramData* pData = m_programs.valueFor(program); + GLenum type=0; + if (pData) + { + type = pData->getTypeForLocation(location); + } + return type; +} + +bool GLSharedGroup::isProgram(GLuint program) +{ + android::AutoMutex _lock(m_lock); + ProgramData* pData = m_programs.valueFor(program); + return (pData!=NULL); +} + +void GLSharedGroup::setupLocationShiftWAR(GLuint program) +{ + android::AutoMutex _lock(m_lock); + ProgramData* pData = m_programs.valueFor(program); + if (pData) pData->setupLocationShiftWAR(); +} + +GLint GLSharedGroup::locationWARHostToApp(GLuint program, GLint hostLoc, GLint arrIndex) +{ + android::AutoMutex _lock(m_lock); + ProgramData* pData = m_programs.valueFor(program); + if (pData) return pData->locationWARHostToApp(hostLoc, arrIndex); + else return hostLoc; +} + +GLint GLSharedGroup::locationWARAppToHost(GLuint program, GLint appLoc) +{ + android::AutoMutex _lock(m_lock); + ProgramData* pData = m_programs.valueFor(program); + if (pData) return pData->locationWARAppToHost(appLoc); + else return appLoc; +} + +bool GLSharedGroup::needUniformLocationWAR(GLuint program) +{ + android::AutoMutex _lock(m_lock); + ProgramData* pData = m_programs.valueFor(program); + if (pData) return pData->needUniformLocationWAR(); + return false; +} + +GLint GLSharedGroup::getNextSamplerUniform(GLuint program, GLint index, GLint* val, GLenum* target) const +{ + android::AutoMutex _lock(m_lock); + ProgramData* pData = m_programs.valueFor(program); + return pData ? pData->getNextSamplerUniform(index, val, target) : -1; +} + +bool GLSharedGroup::setSamplerUniform(GLuint program, GLint appLoc, GLint val, GLenum* target) +{ + android::AutoMutex _lock(m_lock); + ProgramData* pData = m_programs.valueFor(program); + return pData ? pData->setSamplerUniform(appLoc, val, target) : false; +} + +bool GLSharedGroup::addShaderData(GLuint shader) +{ + android::AutoMutex _lock(m_lock); + ShaderData* data = new ShaderData; + if (data) { + if (m_shaders.add(shader, data) < 0) { + delete data; + data = NULL; + } + data->refcount = 1; + } + return data != NULL; +} + +ShaderData* GLSharedGroup::getShaderData(GLuint shader) +{ + android::AutoMutex _lock(m_lock); + return m_shaders.valueFor(shader); +} + +void GLSharedGroup::unrefShaderData(GLuint shader) +{ + android::AutoMutex _lock(m_lock); + ssize_t idx = m_shaders.indexOfKey(shader); + if (idx >= 0) { + unrefShaderDataLocked(idx); + } +} + +void GLSharedGroup::refShaderDataLocked(ssize_t shaderIdx) +{ + assert(shaderIdx >= 0 && shaderIdx <= m_shaders.size()); + ShaderData* data = m_shaders.valueAt(shaderIdx); + data->refcount++; +} + +void GLSharedGroup::unrefShaderDataLocked(ssize_t shaderIdx) +{ + assert(shaderIdx >= 0 && shaderIdx <= m_shaders.size()); + ShaderData* data = m_shaders.valueAt(shaderIdx); + if (--data->refcount == 0) { + delete data; + m_shaders.removeItemsAt(shaderIdx); + } +} diff --git a/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h new file mode 100644 index 0000000..61b8f00 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h @@ -0,0 +1,143 @@ +/* +* 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 _GL_SHARED_GROUP_H_ +#define _GL_SHARED_GROUP_H_ + +#define GL_API +#ifndef ANDROID +#define GL_APIENTRY +#define GL_APIENTRYP +#endif + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <stdio.h> +#include <stdlib.h> +#include "ErrorLog.h" +#include <utils/KeyedVector.h> +#include <utils/List.h> +#include <utils/String8.h> +#include <utils/threads.h> +#include "FixedBuffer.h" +#include "SmartPtr.h" + +struct BufferData { + BufferData(); + BufferData(GLsizeiptr size, void * data); + GLsizeiptr m_size; + FixedBuffer m_fixedBuffer; +}; + +class ProgramData { +private: + typedef struct _IndexInfo { + GLint base; + GLint size; + GLenum type; + GLint appBase; + GLint hostLocsPerElement; + GLuint flags; + GLint samplerValue; // only set for sampler uniforms + } IndexInfo; + + GLuint m_numIndexes; + IndexInfo* m_Indexes; + bool m_initialized; + bool m_locShiftWAR; + + android::Vector<GLuint> m_shaders; + +public: + enum { + INDEX_FLAG_SAMPLER_EXTERNAL = 0x00000001, + }; + + ProgramData(); + void initProgramData(GLuint numIndexes); + bool isInitialized(); + virtual ~ProgramData(); + void setIndexInfo(GLuint index, GLint base, GLint size, GLenum type); + void setIndexFlags(GLuint index, GLuint flags); + GLuint getIndexForLocation(GLint location); + GLenum getTypeForLocation(GLint location); + + bool needUniformLocationWAR() const { return m_locShiftWAR; } + void setupLocationShiftWAR(); + GLint locationWARHostToApp(GLint hostLoc, GLint arrIndex); + GLint locationWARAppToHost(GLint appLoc); + + GLint getNextSamplerUniform(GLint index, GLint* val, GLenum* target); + bool setSamplerUniform(GLint appLoc, GLint val, GLenum* target); + + bool attachShader(GLuint shader); + bool detachShader(GLuint shader); + size_t getNumShaders() const { return m_shaders.size(); } + GLuint getShader(size_t i) const { return m_shaders[i]; } +}; + +struct ShaderData { + typedef android::List<android::String8> StringList; + StringList samplerExternalNames; + int refcount; +}; + +class GLSharedGroup { +private: + android::DefaultKeyedVector<GLuint, BufferData*> m_buffers; + android::DefaultKeyedVector<GLuint, ProgramData*> m_programs; + android::DefaultKeyedVector<GLuint, ShaderData*> m_shaders; + mutable android::Mutex m_lock; + + void refShaderDataLocked(ssize_t shaderIdx); + void unrefShaderDataLocked(ssize_t shaderIdx); + +public: + GLSharedGroup(); + ~GLSharedGroup(); + BufferData * getBufferData(GLuint bufferId); + void addBufferData(GLuint bufferId, GLsizeiptr size, void * data); + void updateBufferData(GLuint bufferId, GLsizeiptr size, void * data); + GLenum subUpdateBufferData(GLuint bufferId, GLintptr offset, GLsizeiptr size, void * data); + void deleteBufferData(GLuint); + + bool isProgram(GLuint program); + bool isProgramInitialized(GLuint program); + void addProgramData(GLuint program); + void initProgramData(GLuint program, GLuint numIndexes); + void attachShader(GLuint program, GLuint shader); + void detachShader(GLuint program, GLuint shader); + void deleteProgramData(GLuint program); + void setProgramIndexInfo(GLuint program, GLuint index, GLint base, GLint size, GLenum type, const char* name); + GLenum getProgramUniformType(GLuint program, GLint location); + void setupLocationShiftWAR(GLuint program); + GLint locationWARHostToApp(GLuint program, GLint hostLoc, GLint arrIndex); + GLint locationWARAppToHost(GLuint program, GLint appLoc); + bool needUniformLocationWAR(GLuint program); + GLint getNextSamplerUniform(GLuint program, GLint index, GLint* val, GLenum* target) const; + bool setSamplerUniform(GLuint program, GLint appLoc, GLint val, GLenum* target); + + bool addShaderData(GLuint shader); + // caller must hold a reference to the shader as long as it holds the pointer + ShaderData* getShaderData(GLuint shader); + void unrefShaderData(GLuint shader); +}; + +typedef SmartPtr<GLSharedGroup> GLSharedGroupPtr; + +#endif //_GL_SHARED_GROUP_H_ diff --git a/emulator/opengl/shared/OpenglCodecCommon/Makefile b/emulator/opengl/shared/OpenglCodecCommon/Makefile new file mode 100644 index 0000000..e8bf431 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/Makefile @@ -0,0 +1,13 @@ + +ROOT=../.. + +include $(ROOT)/make/commondefs + +CXXFILES = TcpStream.cpp GLClientState.cpp glUtils.cpp +CXXINCS += -I$(ROOT)/libs/GLESv1 -I$(ROOT)/include + +LIBRARY_NAME = libcodecCommon.a + +include $(COMMONRULES) + + diff --git a/emulator/opengl/shared/OpenglCodecCommon/SmartPtr.h b/emulator/opengl/shared/OpenglCodecCommon/SmartPtr.h new file mode 100644 index 0000000..4bdfbe4 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/SmartPtr.h @@ -0,0 +1,167 @@ +/* +* 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 __SMART_PTR_H +#define __SMART_PTR_H + +#include <cutils/threads.h> +#include <cutils/atomic.h> + +template <class T, bool threadSafe = false> +class SmartPtr +{ +public: + explicit SmartPtr(T* ptr = (T*)NULL) { + if (threadSafe) { + m_lock = new mutex_t; + mutex_init(m_lock); + } + else m_lock = NULL; + + m_ptr = ptr; + if (ptr) + m_pRefCount = new int32_t(1); + else + m_pRefCount = NULL; + } + + SmartPtr<T,threadSafe>(const SmartPtr<T,false>& rhs) { + if (threadSafe) { + m_lock = new mutex_t; + mutex_init(m_lock); + } + else m_lock = NULL; + + m_pRefCount = rhs.m_pRefCount; + m_ptr = rhs.m_ptr; + use(); + } + + SmartPtr<T,threadSafe>(SmartPtr<T,true>& rhs) { + if (threadSafe) { + m_lock = new mutex_t; + mutex_init(m_lock); + } + else m_lock = NULL; + + if (rhs.m_lock) mutex_lock(rhs.m_lock); + m_pRefCount = rhs.m_pRefCount; + m_ptr = rhs.m_ptr; + use(); + if (rhs.m_lock) mutex_unlock(rhs.m_lock); + } + + ~SmartPtr() { + if (m_lock) mutex_lock(m_lock); + release(); + if (m_lock) + { + mutex_unlock(m_lock); + mutex_destroy(m_lock); + delete m_lock; + } + } + + T* Ptr() const { + return m_ptr; + } + + const T* constPtr() const + { + return m_ptr; + } + + T* operator->() const { + return m_ptr; + } + + T& operator*() const { + return *m_ptr; + } + + operator void*() const { + return (void *)m_ptr; + } + + // This gives STL lists something to compare. + bool operator <(const SmartPtr<T>& t1) const { + return m_ptr < t1.m_ptr; + } + + SmartPtr<T,threadSafe>& operator=(const SmartPtr<T,false>& rhs) + { + if (m_ptr == rhs.m_ptr) + return *this; + + if (m_lock) mutex_lock(m_lock); + release(); + m_pRefCount = rhs.m_pRefCount; + m_ptr = rhs.m_ptr; + use(); + if (m_lock) mutex_unlock(m_lock); + + return *this; + } + + SmartPtr<T,threadSafe>& operator=(SmartPtr<T,true>& rhs) + { + if (m_ptr == rhs.m_ptr) + return *this; + + if (m_lock) mutex_lock(m_lock); + release(); + if (rhs.m_lock) mutex_lock(rhs.m_lock); + m_pRefCount = rhs.m_pRefCount; + m_ptr = rhs.m_ptr; + use(); + if (rhs.m_lock) mutex_unlock(rhs.m_lock); + if (m_lock) mutex_unlock(m_lock); + + return *this; + } + +private: + int32_t *m_pRefCount; + mutex_t *m_lock; + T* m_ptr; + + // Increment the reference count on this pointer by 1. + int use() { + if (!m_pRefCount) return 0; + return android_atomic_inc(m_pRefCount) + 1; + } + + // Decrement the reference count on the pointer by 1. + // If the reference count goes to (or below) 0, the pointer is deleted. + int release() { + if (!m_pRefCount) return 0; + + int iVal = android_atomic_dec(m_pRefCount); + if (iVal > 1) + return iVal - 1; + + delete m_pRefCount; + m_pRefCount = NULL; + + if (m_ptr) { + delete m_ptr; + m_ptr = NULL; + } + return 0; + } + +}; + +#endif // of __SMART_PTR_H diff --git a/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp b/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp new file mode 100644 index 0000000..f7a2314 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp @@ -0,0 +1,168 @@ +/* +* 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 "SocketStream.h" +#include <cutils/sockets.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#ifndef _WIN32 +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/un.h> +#else +#include <ws2tcpip.h> +#endif + +SocketStream::SocketStream(size_t bufSize) : + IOStream(bufSize), + m_sock(-1), + m_bufsize(bufSize), + m_buf(NULL) +{ +} + +SocketStream::SocketStream(int sock, size_t bufSize) : + IOStream(bufSize), + m_sock(sock), + m_bufsize(bufSize), + m_buf(NULL) +{ +} + +SocketStream::~SocketStream() +{ + if (m_sock >= 0) { +#ifdef _WIN32 + closesocket(m_sock); +#else + ::close(m_sock); +#endif + } + if (m_buf != NULL) { + free(m_buf); + m_buf = NULL; + } +} + + +void *SocketStream::allocBuffer(size_t minSize) +{ + size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize); + if (!m_buf) { + m_buf = (unsigned char *)malloc(allocSize); + } + else if (m_bufsize < allocSize) { + unsigned char *p = (unsigned char *)realloc(m_buf, allocSize); + if (p != NULL) { + m_buf = p; + m_bufsize = allocSize; + } else { + ERR("%s: realloc (%zu) failed\n", __FUNCTION__, allocSize); + free(m_buf); + m_buf = NULL; + m_bufsize = 0; + } + } + + return m_buf; +}; + +int SocketStream::commitBuffer(size_t size) +{ + return writeFully(m_buf, size); +} + +int SocketStream::writeFully(const void* buffer, size_t size) +{ + if (!valid()) return -1; + + size_t res = size; + int retval = 0; + + while (res > 0) { + ssize_t stat = ::send(m_sock, (const char *)buffer + (size - res), res, 0); + if (stat < 0) { + if (errno != EINTR) { + retval = stat; + ERR("%s: failed: %s\n", __FUNCTION__, strerror(errno)); + break; + } + } else { + res -= stat; + } + } + return retval; +} + +const unsigned char *SocketStream::readFully(void *buf, size_t len) +{ + const unsigned char* ret = NULL; + if (!valid()) return NULL; + if (!buf) { + return NULL; // do not allow NULL buf in that implementation + } + size_t res = len; + while (res > 0) { + ssize_t stat = ::recv(m_sock, (char *)(buf) + len - res, res, 0); + if (stat > 0) { + res -= stat; + continue; + } + if (stat == 0 || errno != EINTR) { // client shutdown or error + return NULL; + } + } + return (const unsigned char *)buf; +} + +const unsigned char *SocketStream::read( void *buf, size_t *inout_len) +{ + if (!valid()) return NULL; + if (!buf) { + return NULL; // do not allow NULL buf in that implementation + } + + int n; + do { + n = recv(buf, *inout_len); + } while( n < 0 && errno == EINTR ); + + if (n > 0) { + *inout_len = n; + return (const unsigned char *)buf; + } + + return NULL; +} + +int SocketStream::recv(void *buf, size_t len) +{ + if (!valid()) return int(ERR_INVALID_SOCKET); + int res = 0; + while(true) { + res = ::recv(m_sock, (char *)buf, len, 0); + if (res < 0) { + if (errno == EINTR) { + continue; + } + } + break; + } + return res; +} diff --git a/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h b/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h new file mode 100644 index 0000000..3a501b4 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h @@ -0,0 +1,50 @@ +/* +* 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 __SOCKET_STREAM_H +#define __SOCKET_STREAM_H + +#include <stdlib.h> +#include "IOStream.h" + +class SocketStream : public IOStream { +public: + typedef enum { ERR_INVALID_SOCKET = -1000 } SocketStreamError; + + explicit SocketStream(size_t bufsize = 10000); + virtual ~SocketStream(); + + virtual int listen(unsigned short port) = 0; + virtual SocketStream *accept() = 0; + virtual int connect(unsigned short port) = 0; + + virtual void *allocBuffer(size_t minSize); + virtual int commitBuffer(size_t size); + virtual const unsigned char *readFully(void *buf, size_t len); + virtual const unsigned char *read(void *buf, size_t *inout_len); + + bool valid() { return m_sock >= 0; } + virtual int recv(void *buf, size_t len); + virtual int writeFully(const void *buf, size_t len); + +protected: + int m_sock; + size_t m_bufsize; + unsigned char *m_buf; + + SocketStream(int sock, size_t bufSize); +}; + +#endif /* __SOCKET_STREAM_H */ diff --git a/emulator/opengl/shared/OpenglCodecCommon/TcpStream.cpp b/emulator/opengl/shared/OpenglCodecCommon/TcpStream.cpp new file mode 100644 index 0000000..4da2cec --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/TcpStream.cpp @@ -0,0 +1,91 @@ +/* +* 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 "TcpStream.h" +#include <cutils/sockets.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#ifndef _WIN32 +#include <netinet/in.h> +#include <netinet/tcp.h> +#else +#include <ws2tcpip.h> +#endif + +TcpStream::TcpStream(size_t bufSize) : + SocketStream(bufSize) +{ +} + +TcpStream::TcpStream(int sock, size_t bufSize) : + SocketStream(sock, bufSize) +{ + // disable Nagle algorithm to improve bandwidth of small + // packets which are quite common in our implementation. +#ifdef _WIN32 + DWORD flag; +#else + int flag; +#endif + flag = 1; + setsockopt( sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&flag, sizeof(flag) ); +} + +int TcpStream::listen(unsigned short port) +{ + m_sock = socket_loopback_server(port, SOCK_STREAM); + if (!valid()) return int(ERR_INVALID_SOCKET); + + return 0; +} + +SocketStream * TcpStream::accept() +{ + int clientSock = -1; + + while (true) { + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + clientSock = ::accept(m_sock, (sockaddr *)&addr, &len); + + if (clientSock < 0 && errno == EINTR) { + continue; + } + break; + } + + TcpStream *clientStream = NULL; + + if (clientSock >= 0) { + clientStream = new TcpStream(clientSock, m_bufsize); + } + return clientStream; +} + +int TcpStream::connect(unsigned short port) +{ + return connect("127.0.0.1",port); +} + +int TcpStream::connect(const char* hostname, unsigned short port) +{ + m_sock = socket_network_client(hostname, port, SOCK_STREAM); + if (!valid()) return -1; + return 0; +} diff --git a/emulator/opengl/shared/OpenglCodecCommon/TcpStream.h b/emulator/opengl/shared/OpenglCodecCommon/TcpStream.h new file mode 100644 index 0000000..811a871 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/TcpStream.h @@ -0,0 +1,32 @@ +/* +* 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 __TCP_STREAM_H +#define __TCP_STREAM_H + +#include "SocketStream.h" + +class TcpStream : public SocketStream { +public: + explicit TcpStream(size_t bufsize = 10000); + virtual int listen(unsigned short port); + virtual SocketStream *accept(); + virtual int connect(unsigned short port); + int connect(const char* hostname, unsigned short port); +private: + TcpStream(int sock, size_t bufSize); +}; + +#endif diff --git a/emulator/opengl/shared/OpenglCodecCommon/TimeUtils.cpp b/emulator/opengl/shared/OpenglCodecCommon/TimeUtils.cpp new file mode 100644 index 0000000..50aeb03 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/TimeUtils.cpp @@ -0,0 +1,69 @@ +/* +* 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 "TimeUtils.h" + +#ifdef _WIN32 +#include <windows.h> +#include <time.h> +#include <stdio.h> +#elif defined(__linux__) +#include <stdlib.h> +#include <sys/time.h> +#include <time.h> +#include <unistd.h> +#else +#include <sys/time.h> +#include <unistd.h> +#endif + +long long GetCurrentTimeMS() +{ +#ifdef _WIN32 + static LARGE_INTEGER freq; + static bool bNotInit = true; + if ( bNotInit ) { + bNotInit = (QueryPerformanceFrequency( &freq ) == FALSE); + } + LARGE_INTEGER currVal; + QueryPerformanceCounter( &currVal ); + + return currVal.QuadPart / (freq.QuadPart / 1000); + +#elif defined(__linux__) + + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + long long iDiff = (now.tv_sec * 1000LL) + now.tv_nsec/1000000LL; + return iDiff; + +#else /* Others, e.g. OS X */ + + struct timeval now; + gettimeofday(&now, NULL); + long long iDiff = (now.tv_sec * 1000LL) + now.tv_usec/1000LL; + return iDiff; + +#endif +} + +void TimeSleepMS(int p_mili) +{ +#ifdef _WIN32 + Sleep(p_mili); +#else + usleep(p_mili * 1000); +#endif +} diff --git a/emulator/opengl/shared/OpenglCodecCommon/TimeUtils.h b/emulator/opengl/shared/OpenglCodecCommon/TimeUtils.h new file mode 100644 index 0000000..bc4fd1c --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/TimeUtils.h @@ -0,0 +1,22 @@ +/* +* 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 _TIME_UTILS_H +#define _TIME_UTILS_H + +long long GetCurrentTimeMS(); +void TimeSleepMS(int p_mili); + +#endif diff --git a/emulator/opengl/shared/OpenglCodecCommon/UnixStream.cpp b/emulator/opengl/shared/OpenglCodecCommon/UnixStream.cpp new file mode 100644 index 0000000..8e463a3 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/UnixStream.cpp @@ -0,0 +1,137 @@ +/* +* 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 "UnixStream.h" +#include <cutils/sockets.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/un.h> +#include <sys/stat.h> + +/* Not all systems define PATH_MAX, those who don't generally don't + * have a limit on the maximum path size, so use a value that is + * large enough for our very limited needs. + */ +#ifndef PATH_MAX +#define PATH_MAX 128 +#endif + +UnixStream::UnixStream(size_t bufSize) : + SocketStream(bufSize) +{ +} + +UnixStream::UnixStream(int sock, size_t bufSize) : + SocketStream(sock, bufSize) +{ +} + +/* Initialize a sockaddr_un with the appropriate values corresponding + * to a given 'virtual port'. Returns 0 on success, -1 on error. + */ +static int +make_unix_path(char *path, size_t pathlen, int port_number) +{ + char tmp[PATH_MAX]; // temp directory + int ret = 0; + + // First, create user-specific temp directory if needed + const char* user = getenv("USER"); + if (user != NULL) { + struct stat st; + snprintf(tmp, sizeof(tmp), "/tmp/android-%s", user); + do { + ret = ::lstat(tmp, &st); + } while (ret < 0 && errno == EINTR); + + if (ret < 0 && errno == ENOENT) { + do { + ret = ::mkdir(tmp, 0766); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + ERR("Could not create temp directory: %s", tmp); + user = NULL; // will fall-back to /tmp + } + } + else if (ret < 0) { + user = NULL; // will fallback to /tmp + } + } + + if (user == NULL) { // fallback to /tmp in case of error + snprintf(tmp, sizeof(tmp), "/tmp"); + } + + // Now, initialize it properly + snprintf(path, pathlen, "%s/qemu-gles-%d", tmp, port_number); + return 0; +} + + +int UnixStream::listen(unsigned short port) +{ + char path[PATH_MAX]; + + if (make_unix_path(path, sizeof(path), port) < 0) { + return -1; + } + + m_sock = socket_local_server(path, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); + if (!valid()) return int(ERR_INVALID_SOCKET); + + return 0; +} + +SocketStream * UnixStream::accept() +{ + int clientSock = -1; + + while (true) { + struct sockaddr_un addr; + socklen_t len = sizeof(addr); + clientSock = ::accept(m_sock, (sockaddr *)&addr, &len); + + if (clientSock < 0 && errno == EINTR) { + continue; + } + break; + } + + UnixStream *clientStream = NULL; + + if (clientSock >= 0) { + clientStream = new UnixStream(clientSock, m_bufsize); + } + return clientStream; +} + +int UnixStream::connect(unsigned short port) +{ + char path[PATH_MAX]; + + if (make_unix_path(path, sizeof(path), port) < 0) + return -1; + + m_sock = socket_local_client(path, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); + if (!valid()) return -1; + + return 0; +} diff --git a/emulator/opengl/shared/OpenglCodecCommon/UnixStream.h b/emulator/opengl/shared/OpenglCodecCommon/UnixStream.h new file mode 100644 index 0000000..c184b19 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/UnixStream.h @@ -0,0 +1,31 @@ +/* +* 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 __UNIX_STREAM_H +#define __UNIX_STREAM_H + +#include "SocketStream.h" + +class UnixStream : public SocketStream { +public: + explicit UnixStream(size_t bufsize = 10000); + virtual int listen(unsigned short port); + virtual SocketStream *accept(); + virtual int connect(unsigned short port); +private: + UnixStream(int sock, size_t bufSize); +}; + +#endif diff --git a/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp b/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp new file mode 100644 index 0000000..e1a0b9b --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp @@ -0,0 +1,239 @@ +/* +* 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 "Win32PipeStream.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <windows.h> + +#ifndef _WIN32 +#error ONLY BUILD THIS SOURCE FILE FOR WINDOWS! +#endif + +/* The official documentation states that the name of a given named + * pipe cannot be more than 256 characters long. + */ +#define NAMED_PIPE_MAX 256 + +Win32PipeStream::Win32PipeStream(size_t bufSize) : + SocketStream(bufSize), + m_pipe(INVALID_HANDLE_VALUE) +{ +} + +Win32PipeStream::Win32PipeStream(HANDLE pipe, size_t bufSize) : + SocketStream(-1, bufSize), + m_pipe(pipe) +{ +} + +Win32PipeStream::~Win32PipeStream() +{ + if (m_pipe != INVALID_HANDLE_VALUE) { + CloseHandle(m_pipe); + m_pipe = INVALID_HANDLE_VALUE; + } +} + +/* Initialize the pipe name corresponding to a given port + */ +static void +make_pipe_name(char *path, size_t pathlen, int port_number) +{ + snprintf(path, pathlen, "\\\\.\\pipe\\qemu-gles-%d", port_number); +} + + +/* Technical note: Named pipes work differently from BSD Sockets. + * One does not create/bind a pipe, and collect a new handle each + * time a client connects with accept(). + * + * Instead, the server creates a new pipe instance each time it wants + * to get a new client connection, then calls ConnectNamedPipe() to + * wait for a connection. + * + * So listen() is a no-op, and accept() really creates the pipe handle. + * + * Also, connect() must create a pipe handle with CreateFile() and + * wait for a server instance with WaitNamedPipe() + */ +int Win32PipeStream::listen(unsigned short port) +{ + // just save the port number for accept() + m_port = port; + return 0; +} + +SocketStream * Win32PipeStream::accept() +{ + char path[NAMED_PIPE_MAX+1]; + SocketStream* clientStream; + HANDLE pipe; + + make_pipe_name(path, sizeof(path), m_port); + + pipe = ::CreateNamedPipe( + path, // pipe name + PIPE_ACCESS_DUPLEX, // read-write access + PIPE_TYPE_BYTE | // byte-oriented writes + PIPE_READMODE_BYTE | // byte-oriented reads + PIPE_WAIT, // blocking operations + PIPE_UNLIMITED_INSTANCES, // no limit on clients + 4096, // input buffer size + 4096, // output buffer size + 0, // client time-out + NULL); // default security attributes + + if (pipe == INVALID_HANDLE_VALUE) { + ERR("%s: CreateNamedPipe failed %d\n", __FUNCTION__, (int)GetLastError()); + return NULL; + } + + // Stupid Win32 API design: If a client is already connected, then + // ConnectNamedPipe will return 0, and GetLastError() will return + // ERROR_PIPE_CONNECTED. This is not an error! It just means that the + // function didn't have to wait. + // + if (::ConnectNamedPipe(pipe, NULL) == 0 && GetLastError() != ERROR_PIPE_CONNECTED) { + ERR("%s: ConnectNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError()); + CloseHandle(pipe); + return NULL; + } + + clientStream = new Win32PipeStream(pipe, m_bufsize); + return clientStream; +} + +int Win32PipeStream::connect(unsigned short port) +{ + char path[NAMED_PIPE_MAX+1]; + HANDLE pipe; + int tries = 10; + + make_pipe_name(path, sizeof(path), port); + + /* We're going to loop in order to wait for the pipe server to + * be setup properly. + */ + for (; tries > 0; tries--) { + pipe = ::CreateFile( + path, // pipe name + GENERIC_READ | GENERIC_WRITE, // read & write + 0, // no sharing + NULL, // default security attrs + OPEN_EXISTING, // open existing pipe + 0, // default attributes + NULL); // no template file + + /* If we have a valid pipe handle, break from the loop */ + if (pipe != INVALID_HANDLE_VALUE) { + break; + } + + /* We can get here if the pipe is busy, i.e. if the server hasn't + * create a new pipe instance to service our request. In which case + * GetLastError() will return ERROR_PIPE_BUSY. + * + * If so, then use WaitNamedPipe() to wait for a decent time + * to try again. + */ + if (GetLastError() != ERROR_PIPE_BUSY) { + /* Not ERROR_PIPE_BUSY */ + ERR("%s: CreateFile failed: %d\n", __FUNCTION__, (int)GetLastError()); + errno = EINVAL; + return -1; + } + + /* Wait for 5 seconds */ + if ( !WaitNamedPipe(path, 5000) ) { + ERR("%s: WaitNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError()); + errno = EINVAL; + return -1; + } + } + + m_pipe = pipe; + return 0; +} + +/* Special buffer methods, since we can't use socket functions here */ + +int Win32PipeStream::commitBuffer(size_t size) +{ + if (m_pipe == INVALID_HANDLE_VALUE) + return -1; + + size_t res = size; + int retval = 0; + + while (res > 0) { + DWORD written; + if (! ::WriteFile(m_pipe, (const char *)m_buf + (size - res), res, &written, NULL)) { + retval = -1; + ERR("%s: failed: %d\n", __FUNCTION__, (int)GetLastError()); + break; + } + res -= written; + } + return retval; +} + +const unsigned char *Win32PipeStream::readFully(void *buf, size_t len) +{ + const unsigned char* ret = NULL; + + if (m_pipe == INVALID_HANDLE_VALUE) + return NULL; + + if (!buf) { + return NULL; // do not allow NULL buf in that implementation + } + + size_t res = len; + while (res > 0) { + DWORD readcount = 0; + if (! ::ReadFile(m_pipe, (char *)buf + (len - res), res, &readcount, NULL) || readcount == 0) { + errno = (int)GetLastError(); + return NULL; + } + res -= readcount; + } + return (const unsigned char *)buf; +} + +const unsigned char *Win32PipeStream::read( void *buf, size_t *inout_len) +{ + size_t len = *inout_len; + DWORD readcount; + + if (m_pipe == INVALID_HANDLE_VALUE) + return NULL; + + if (!buf) { + return NULL; // do not allow NULL buf in that implementation + } + + if (!::ReadFile(m_pipe, (char *)buf, len, &readcount, NULL)) { + errno = (int)GetLastError(); + return NULL; + } + + *inout_len = (size_t)readcount; + return (const unsigned char *)buf; +} diff --git a/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.h b/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.h new file mode 100644 index 0000000..4114545 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.h @@ -0,0 +1,41 @@ +/* +* 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 __WIN32_PIPE_STREAM_H +#define __WIN32_PIPE_STREAM_H + +#include "SocketStream.h" +#include <windows.h> + +class Win32PipeStream : public SocketStream { +public: + explicit Win32PipeStream(size_t bufsize = 10000); + virtual ~Win32PipeStream(); + virtual int listen(unsigned short port); + virtual SocketStream *accept(); + virtual int connect(unsigned short port); + + virtual int commitBuffer(size_t size); + virtual const unsigned char *readFully(void *buf, size_t len); + virtual const unsigned char *read(void *buf, size_t *inout_len); + +private: + Win32PipeStream(HANDLE pipe, size_t bufSize); + HANDLE m_pipe; + int m_port; +}; + + +#endif diff --git a/emulator/opengl/shared/OpenglCodecCommon/codec_defs.h b/emulator/opengl/shared/OpenglCodecCommon/codec_defs.h new file mode 100644 index 0000000..f19f514 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/codec_defs.h @@ -0,0 +1,23 @@ +/* +* 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 _CODEC_DEFS_H +#define _CODEC_DEFS_H + +#define CODEC_SERVER_PORT 22468 + +#define CODEC_MAX_VERTEX_ATTRIBUTES 64 + +#endif diff --git a/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp b/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp new file mode 100644 index 0000000..4b7fc89 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp @@ -0,0 +1,471 @@ +/* +* 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 "glUtils.h" +#include <string.h> +#include "ErrorLog.h" +#include <IOStream.h> + +size_t glSizeof(GLenum type) +{ + size_t retval = 0; + switch(type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + retval = 1; + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_HALF_FLOAT_OES: + retval = 2; + break; + case GL_INT: + case GL_FLOAT: + case GL_FIXED: + case GL_BOOL: + retval = 4; + break; +#ifdef GL_DOUBLE + case GL_DOUBLE: + retval = 8; + break; +#endif + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_BOOL_VEC2: + retval = 8; + break; + case GL_INT_VEC3: + case GL_BOOL_VEC3: + case GL_FLOAT_VEC3: + retval = 12; + break; + case GL_FLOAT_VEC4: + case GL_BOOL_VEC4: + case GL_INT_VEC4: + case GL_FLOAT_MAT2: + retval = 16; + break; + case GL_FLOAT_MAT3: + retval = 36; + break; + case GL_FLOAT_MAT4: + retval = 64; + break; + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + retval = 4; + break; + default: + ERR("**** ERROR unknown type 0x%x (%s,%d)\n", type, __FUNCTION__,__LINE__); + } + return retval; + +} + +size_t glUtilsParamSize(GLenum param) +{ + size_t s = 0; + + switch(param) + { + case GL_DEPTH_TEST: + case GL_DEPTH_FUNC: + case GL_DEPTH_BITS: + case GL_MAX_CLIP_PLANES: + case GL_GREEN_BITS: + case GL_MAX_MODELVIEW_STACK_DEPTH: + case GL_MAX_PROJECTION_STACK_DEPTH: + case GL_MAX_TEXTURE_STACK_DEPTH: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: + case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + case GL_MAX_TEXTURE_SIZE: + case GL_TEXTURE_GEN_MODE_OES: + case GL_TEXTURE_ENV_MODE: + case GL_FOG_MODE: + case GL_FOG_DENSITY: + case GL_FOG_START: + case GL_FOG_END: + case GL_SPOT_EXPONENT: + case GL_CONSTANT_ATTENUATION: + case GL_LINEAR_ATTENUATION: + case GL_QUADRATIC_ATTENUATION: + case GL_SHININESS: + case GL_LIGHT_MODEL_TWO_SIDE: + case GL_POINT_SIZE: + case GL_POINT_SIZE_MIN: + case GL_POINT_SIZE_MAX: + case GL_POINT_FADE_THRESHOLD_SIZE: + case GL_CULL_FACE_MODE: + case GL_FRONT_FACE: + case GL_SHADE_MODEL: + case GL_DEPTH_WRITEMASK: + case GL_DEPTH_CLEAR_VALUE: + case GL_STENCIL_FAIL: + case GL_STENCIL_PASS_DEPTH_FAIL: + case GL_STENCIL_PASS_DEPTH_PASS: + case GL_STENCIL_REF: + case GL_STENCIL_WRITEMASK: + case GL_MATRIX_MODE: + case GL_MODELVIEW_STACK_DEPTH: + case GL_PROJECTION_STACK_DEPTH: + case GL_TEXTURE_STACK_DEPTH: + case GL_ALPHA_TEST_FUNC: + case GL_ALPHA_TEST_REF: + case GL_ALPHA_TEST: + case GL_BLEND_DST: + case GL_BLEND_SRC: + case GL_BLEND: + case GL_LOGIC_OP_MODE: + case GL_SCISSOR_TEST: + case GL_MAX_TEXTURE_UNITS: + case GL_ACTIVE_TEXTURE: + case GL_ALPHA_BITS: + case GL_ARRAY_BUFFER_BINDING: + case GL_BLUE_BITS: + case GL_CLIENT_ACTIVE_TEXTURE: + case GL_CLIP_PLANE0: + case GL_CLIP_PLANE1: + case GL_CLIP_PLANE2: + case GL_CLIP_PLANE3: + case GL_CLIP_PLANE4: + case GL_CLIP_PLANE5: + case GL_COLOR_ARRAY: + case GL_COLOR_ARRAY_BUFFER_BINDING: + case GL_COLOR_ARRAY_SIZE: + case GL_COLOR_ARRAY_STRIDE: + case GL_COLOR_ARRAY_TYPE: + case GL_COLOR_LOGIC_OP: + case GL_COLOR_MATERIAL: + case GL_PACK_ALIGNMENT: + case GL_PERSPECTIVE_CORRECTION_HINT: + case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: + case GL_POINT_SIZE_ARRAY_STRIDE_OES: + case GL_POINT_SIZE_ARRAY_TYPE_OES: + case GL_POINT_SMOOTH: + case GL_POINT_SMOOTH_HINT: + case GL_POINT_SPRITE_OES: + case GL_COORD_REPLACE_OES: + case GL_COMBINE_ALPHA: + case GL_SRC0_RGB: + case GL_SRC1_RGB: + case GL_SRC2_RGB: + case GL_OPERAND0_RGB: + case GL_OPERAND1_RGB: + case GL_OPERAND2_RGB: + case GL_SRC0_ALPHA: + case GL_SRC1_ALPHA: + case GL_SRC2_ALPHA: + case GL_OPERAND0_ALPHA: + case GL_OPERAND1_ALPHA: + case GL_OPERAND2_ALPHA: + case GL_RGB_SCALE: + case GL_ALPHA_SCALE: + case GL_COMBINE_RGB: + case GL_POLYGON_OFFSET_FACTOR: + case GL_POLYGON_OFFSET_FILL: + case GL_POLYGON_OFFSET_UNITS: + case GL_RED_BITS: + case GL_RESCALE_NORMAL: + case GL_SAMPLE_ALPHA_TO_COVERAGE: + case GL_SAMPLE_ALPHA_TO_ONE: + case GL_SAMPLE_BUFFERS: + case GL_SAMPLE_COVERAGE: + case GL_SAMPLE_COVERAGE_INVERT: + case GL_SAMPLE_COVERAGE_VALUE: + case GL_SAMPLES: + case GL_STENCIL_BITS: + case GL_STENCIL_CLEAR_VALUE: + case GL_STENCIL_FUNC: + case GL_STENCIL_TEST: + case GL_STENCIL_VALUE_MASK: + case GL_STENCIL_BACK_FUNC: + case GL_STENCIL_BACK_VALUE_MASK: + case GL_STENCIL_BACK_REF: + case GL_STENCIL_BACK_FAIL: + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: + case GL_STENCIL_BACK_PASS_DEPTH_PASS: + case GL_STENCIL_BACK_WRITEMASK: + case GL_TEXTURE_2D: + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_TEXTURE_BINDING_EXTERNAL_OES: + case GL_TEXTURE_COORD_ARRAY: + case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: + case GL_TEXTURE_COORD_ARRAY_SIZE: + case GL_TEXTURE_COORD_ARRAY_STRIDE: + case GL_TEXTURE_COORD_ARRAY_TYPE: + case GL_UNPACK_ALIGNMENT: + case GL_VERTEX_ARRAY: + case GL_VERTEX_ARRAY_BUFFER_BINDING: + case GL_VERTEX_ARRAY_SIZE: + case GL_VERTEX_ARRAY_STRIDE: + case GL_VERTEX_ARRAY_TYPE: + case GL_SPOT_CUTOFF: + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_GENERATE_MIPMAP: + case GL_GENERATE_MIPMAP_HINT: + case GL_RENDERBUFFER_WIDTH_OES: + case GL_RENDERBUFFER_HEIGHT_OES: + case GL_RENDERBUFFER_INTERNAL_FORMAT_OES: + case GL_RENDERBUFFER_RED_SIZE_OES: + case GL_RENDERBUFFER_GREEN_SIZE_OES: + case GL_RENDERBUFFER_BLUE_SIZE_OES: + case GL_RENDERBUFFER_ALPHA_SIZE_OES: + case GL_RENDERBUFFER_DEPTH_SIZE_OES: + case GL_RENDERBUFFER_STENCIL_SIZE_OES: + case GL_RENDERBUFFER_BINDING: + case GL_FRAMEBUFFER_BINDING: + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES: + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES: + case GL_FENCE_STATUS_NV: + case GL_FENCE_CONDITION_NV: + case GL_TEXTURE_WIDTH_QCOM: + case GL_TEXTURE_HEIGHT_QCOM: + case GL_TEXTURE_DEPTH_QCOM: + case GL_TEXTURE_INTERNAL_FORMAT_QCOM: + case GL_TEXTURE_FORMAT_QCOM: + case GL_TEXTURE_TYPE_QCOM: + case GL_TEXTURE_IMAGE_VALID_QCOM: + case GL_TEXTURE_NUM_LEVELS_QCOM: + case GL_TEXTURE_TARGET_QCOM: + case GL_TEXTURE_OBJECT_VALID_QCOM: + case GL_BLEND_EQUATION_RGB_OES: + case GL_BLEND_EQUATION_ALPHA_OES: + case GL_BLEND_DST_RGB_OES: + case GL_BLEND_SRC_RGB_OES: + case GL_BLEND_DST_ALPHA_OES: + case GL_BLEND_SRC_ALPHA_OES: + case GL_MAX_LIGHTS: + case GL_SHADER_TYPE: + case GL_DELETE_STATUS: + case GL_COMPILE_STATUS: + case GL_INFO_LOG_LENGTH: + case GL_SHADER_SOURCE_LENGTH: + case GL_CURRENT_PROGRAM: + case GL_LINK_STATUS: + case GL_VALIDATE_STATUS: + case GL_ATTACHED_SHADERS: + case GL_ACTIVE_UNIFORMS: + case GL_ACTIVE_ATTRIBUTES: + case GL_SUBPIXEL_BITS: + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: + case GL_NUM_SHADER_BINARY_FORMATS: + case GL_SHADER_COMPILER: + case GL_MAX_VERTEX_ATTRIBS: + case GL_MAX_VERTEX_UNIFORM_VECTORS: + case GL_MAX_VARYING_VECTORS: + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: + case GL_MAX_RENDERBUFFER_SIZE: + case GL_MAX_TEXTURE_IMAGE_UNITS: + case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES: + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: + case GL_LINE_WIDTH: + s = 1; + break; + case GL_ALIASED_LINE_WIDTH_RANGE: + case GL_ALIASED_POINT_SIZE_RANGE: + case GL_DEPTH_RANGE: + case GL_MAX_VIEWPORT_DIMS: + case GL_SMOOTH_POINT_SIZE_RANGE: + case GL_SMOOTH_LINE_WIDTH_RANGE: + s= 2; + break; + case GL_SPOT_DIRECTION: + case GL_POINT_DISTANCE_ATTENUATION: + case GL_CURRENT_NORMAL: + s = 3; + break; + case GL_CURRENT_VERTEX_ATTRIB: + case GL_CURRENT_TEXTURE_COORDS: + case GL_CURRENT_COLOR: + case GL_FOG_COLOR: + case GL_AMBIENT: + case GL_DIFFUSE: + case GL_SPECULAR: + case GL_EMISSION: + case GL_POSITION: + case GL_LIGHT_MODEL_AMBIENT: + case GL_TEXTURE_ENV_COLOR: + case GL_SCISSOR_BOX: + case GL_VIEWPORT: + case GL_TEXTURE_CROP_RECT_OES: + case GL_COLOR_CLEAR_VALUE: + case GL_COLOR_WRITEMASK: + case GL_AMBIENT_AND_DIFFUSE: + case GL_BLEND_COLOR: + s = 4; + break; + case GL_MODELVIEW_MATRIX: + case GL_PROJECTION_MATRIX: + case GL_TEXTURE_MATRIX: + s = 16; + break; + default: + ERR("glUtilsParamSize: unknow param 0x%08x\n", param); + s = 1; // assume 1 + } + return s; +} + +void glUtilsPackPointerData(unsigned char *dst, unsigned char *src, + int size, GLenum type, unsigned int stride, + unsigned int datalen) +{ + unsigned int vsize = size * glSizeof(type); + if (stride == 0) stride = vsize; + + if (stride == vsize) { + memcpy(dst, src, datalen); + } else { + for (unsigned int i = 0; i < datalen; i += vsize) { + memcpy(dst, src, vsize); + dst += vsize; + src += stride; + } + } +} + +void glUtilsWritePackPointerData(void* _stream, unsigned char *src, + int size, GLenum type, unsigned int stride, + unsigned int datalen) +{ + IOStream* stream = reinterpret_cast<IOStream*>(_stream); + + unsigned int vsize = size * glSizeof(type); + if (stride == 0) stride = vsize; + + if (stride == vsize) { + stream->writeFully(src, datalen); + } else { + for (unsigned int i = 0; i < datalen; i += vsize) { + stream->writeFully(src, (size_t)vsize); + src += stride; + } + } +} + +int glUtilsPixelBitSize(GLenum format, GLenum type) +{ + int components = 0; + int componentsize = 0; + int pixelsize = 0; + switch(type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + componentsize = 8; + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_RGB565_OES: + case GL_RGB5_A1_OES: + case GL_RGBA4_OES: + pixelsize = 16; + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + case GL_FIXED: + case GL_UNSIGNED_INT_24_8_OES: + pixelsize = 32; + break; + default: + ERR("glUtilsPixelBitSize: unknown pixel type - assuming pixel data 0\n"); + componentsize = 0; + } + + if (pixelsize == 0) { + switch(format) { +#if 0 + case GL_RED: + case GL_GREEN: + case GL_BLUE: +#endif + case GL_ALPHA: + case GL_LUMINANCE: + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + components = 1; + break; + case GL_LUMINANCE_ALPHA: + components = 2; + break; + case GL_RGB: +#if 0 + case GL_BGR: +#endif + components = 3; + break; + case GL_RGBA: + case GL_BGRA_EXT: + components = 4; + break; + default: + ERR("glUtilsPixelBitSize: unknown pixel format...\n"); + components = 0; + } + pixelsize = components * componentsize; + } + + return pixelsize; +} + +// pack a list of strings into one. +void glUtilsPackStrings(char *ptr, char **strings, GLint *length, GLsizei count) +{ + char *p = ptr; + *p = '\0'; + for (int i = 0; i < count; i++) { + int l=0; + if (strings[i]!=NULL) { + if (length == NULL || length[i] < 0) { + l = strlen(strings[i]); + strcat(p, strings[i]); + } else { + l = length[i]; + strncat(p, strings[i], l); + } + } + p += l; + } +} + +// claculate the length of a list of strings +int glUtilsCalcShaderSourceLen( char **strings, GLint *length, GLsizei count) +{ + int len = 0; + for (int i = 0; i < count; i++) { + int l; + if (length == NULL || length[i] < 0) { + l = strings[i]!=NULL ? strlen(strings[i]) : 0; + } else { + l = length[i]; + } + len += l; + } + return len; + +} diff --git a/emulator/opengl/shared/OpenglCodecCommon/glUtils.h b/emulator/opengl/shared/OpenglCodecCommon/glUtils.h new file mode 100644 index 0000000..f8857f1 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/glUtils.h @@ -0,0 +1,95 @@ +/* +* 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 __GL_UTILS_H__ +#define __GL_UTILS_H__ + +#include <stdio.h> +#include <stdlib.h> + +#ifdef GL_API + #undef GL_API +#endif +#define GL_API + +#ifdef GL_APIENTRY + #undef GL_APIENTRY +#endif + +#ifdef GL_APIENTRYP + #undef GL_APIENTRYP +#endif +#define GL_APIENTRYP + +#ifndef ANDROID +#define GL_APIENTRY +#endif + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#ifdef __cplusplus +extern "C" { +#endif + + size_t glSizeof(GLenum type); + size_t glUtilsParamSize(GLenum param); + void glUtilsPackPointerData(unsigned char *dst, unsigned char *str, + int size, GLenum type, unsigned int stride, + unsigned int datalen); + void glUtilsWritePackPointerData(void* stream, unsigned char *src, + int size, GLenum type, unsigned int stride, + unsigned int datalen); + int glUtilsPixelBitSize(GLenum format, GLenum type); + void glUtilsPackStrings(char *ptr, char **strings, GLint *length, GLsizei count); + int glUtilsCalcShaderSourceLen(char **strings, GLint *length, GLsizei count); +#ifdef __cplusplus +}; +#endif + +namespace GLUtils { + + template <class T> void minmax(T *indices, int count, int *min, int *max) { + *min = -1; + *max = -1; + T *ptr = indices; + for (int i = 0; i < count; i++) { + if (*min == -1 || *ptr < *min) *min = *ptr; + if (*max == -1 || *ptr > *max) *max = *ptr; + ptr++; + } + } + + template <class T> void shiftIndices(T *indices, int count, int offset) { + T *ptr = indices; + for (int i = 0; i < count; i++) { + *ptr += offset; + ptr++; + } + } + + + template <class T> void shiftIndices(T *src, T *dst, int count, int offset) + { + for (int i = 0; i < count; i++) { + *dst = *src + offset; + dst++; + src++; + } + } +}; // namespace GLUtils +#endif diff --git a/emulator/opengl/shared/OpenglCodecCommon/gl_base_types.h b/emulator/opengl/shared/OpenglCodecCommon/gl_base_types.h new file mode 100644 index 0000000..d7bdef8 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/gl_base_types.h @@ -0,0 +1,62 @@ +/* +* 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 __GL_BASE_TYPES__H +#define __GL_BASE_TYPES__H + +#include <KHR/khrplatform.h> + +#ifndef gl_APIENTRY +#define gl_APIENTRY KHRONOS_APIENTRY +#endif + +#ifndef gl2_APIENTRY +#define gl2_APIENTRY KHRONOS_APIENTRY +#endif + +typedef void GLvoid; +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef char GLchar; +typedef khronos_int8_t GLbyte; +typedef short GLshort; +typedef int GLint; +typedef int GLsizei; +typedef khronos_uint8_t GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef khronos_int32_t GLfixed; +typedef khronos_int32_t GLclampx; +typedef khronos_intptr_t GLintptr; +typedef khronos_ssize_t GLsizeiptr; +typedef char *GLstr; +/* JR XXX Treating this as an in handle - is this correct? */ +typedef void * GLeglImageOES; + +/* ErrorCode */ +#ifndef GL_INVALID_ENUM +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_OUT_OF_MEMORY 0x0505 +#endif + +#endif diff --git a/emulator/opengl/shared/OpenglOsUtils/Android.mk b/emulator/opengl/shared/OpenglOsUtils/Android.mk new file mode 100644 index 0000000..82391cd --- /dev/null +++ b/emulator/opengl/shared/OpenglOsUtils/Android.mk @@ -0,0 +1,57 @@ +# This build script corresponds to a small library containing +# OS-specific support functions for: +# - thread-local storage +# - dynamic library loading +# - child process creation and wait (probably not needed in guest) +# +LOCAL_PATH := $(call my-dir) + +### Guest library ############################################## +$(call emugl-begin-static-library,libOpenglOsUtils) + + $(call emugl-export,C_INCLUDES,$(LOCAL_PATH)) + $(call emugl-export,LDLIBS,-ldl) + + LOCAL_SRC_FILES := \ + osProcessUnix.cpp \ + osThreadUnix.cpp \ + osDynLibrary.cpp + +$(call emugl-end-module) + + +### Host library ############################################## + +host_common_SRC_FILES := osDynLibrary.cpp +host_common_LDLIBS := + +ifeq ($(HOST_OS),windows) + host_common_SRC_FILES += \ + osProcessWin.cpp \ + osThreadWin.cpp + host_common_LDLIBS += -lws2_32 -lpsapi +else + host_common_SRC_FILES += \ + osProcessUnix.cpp \ + osThreadUnix.cpp + host_common_LDLIBS += -ldl +endif + +ifeq ($(HOST_OS),linux) + host_common_LDLIBS += -lpthread -lrt +endif + +### 32-bit host library #### +$(call emugl-begin-host-static-library,libOpenglOsUtils) + $(call emugl-export,C_INCLUDES,$(LOCAL_PATH)) + LOCAL_SRC_FILES = $(host_common_SRC_FILES) + $(call emugl-export,LDLIBS,$(host_common_LDLIBS)) +$(call emugl-end-module) + +### 64-bit host library #### +$(call emugl-begin-host-static-library,lib64OpenglOsUtils) + $(call emugl-export,C_INCLUDES,$(LOCAL_PATH)) + LOCAL_SRC_FILES = $(host_common_SRC_FILES) + $(call emugl-export,LDLIBS,$(host_common_LDLIBS)) + $(call emugl-export,CFLAGS,-m64) +$(call emugl-end-module) diff --git a/emulator/opengl/shared/OpenglOsUtils/osDynLibrary.cpp b/emulator/opengl/shared/OpenglOsUtils/osDynLibrary.cpp new file mode 100644 index 0000000..e8e6ab7 --- /dev/null +++ b/emulator/opengl/shared/OpenglOsUtils/osDynLibrary.cpp @@ -0,0 +1,79 @@ +/* +* 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 "osDynLibrary.h" + +#ifndef _WIN32 +#include <dlfcn.h> +#endif +#include <stdio.h> + +namespace osUtils { + +dynLibrary *dynLibrary::open(const char *p_libName) +{ + dynLibrary *lib = new dynLibrary(); + if (!lib) { + return NULL; + } + +#ifdef _WIN32 + lib->m_lib = LoadLibrary(p_libName); +#else // !WIN32 + lib->m_lib = dlopen(p_libName, RTLD_NOW); +#endif + + if (lib->m_lib == NULL) { + printf("Failed to load %s\n", p_libName); +#ifndef _WIN32 + printf("error %s\n", dlerror()); //only on linux +#endif + delete lib; + return NULL; + } + + return lib; +} + +dynLibrary::dynLibrary() : + m_lib(NULL) +{ +} + +dynLibrary::~dynLibrary() +{ + if (NULL != m_lib) { +#ifdef _WIN32 + FreeLibrary(m_lib); +#else // !WIN32 + dlclose(m_lib); +#endif + } +} + +dynFuncPtr dynLibrary::findSymbol(const char *p_symName) +{ + if (NULL == m_lib) { + return NULL; + } + +#ifdef _WIN32 + return (dynFuncPtr) GetProcAddress(m_lib, p_symName); +#else // !WIN32 + return (dynFuncPtr) dlsym(m_lib, p_symName); +#endif +} + +} // of namespace osUtils diff --git a/emulator/opengl/shared/OpenglOsUtils/osDynLibrary.h b/emulator/opengl/shared/OpenglOsUtils/osDynLibrary.h new file mode 100644 index 0000000..c83fbf3 --- /dev/null +++ b/emulator/opengl/shared/OpenglOsUtils/osDynLibrary.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 _OSUTILS_DYN_LIBRARY_H +#define _OSUTILS_DYN_LIBRARY_H + +#ifdef _WIN32 +#include <windows.h> +#endif + +namespace osUtils { + +typedef void (*dynFuncPtr)(void); + +class dynLibrary +{ +public: + static dynLibrary *open(const char *p_libName); + ~dynLibrary(); + + dynFuncPtr findSymbol(const char *p_symName); + +private: + dynLibrary(); + +private: +#ifdef _WIN32 + HMODULE m_lib; +#else + void *m_lib; +#endif +}; + +} // of namespace osUtils + + + +// Macro to compose emugl shared library name under various OS and bitness +// eg. +// on x86_64, EMUGL_LIBNAME("foo") --> "lib64foo.so" + +#ifdef _WIN32 +# define DLL_EXTENSION "" // _WIN32 LoadLibrary only accept name w/o .dll extension +#elif defined(__APPLE__) +# define DLL_EXTENSION ".dylib" +#else +# define DLL_EXTENSION ".so" +#endif + +#if defined(__x86_64__) +# define EMUGL_LIBNAME(name) "lib64" name DLL_EXTENSION +#elif defined(__i386__) +# define EMUGL_LIBNAME(name) "lib" name DLL_EXTENSION +#else +/* This header is included by target w/o using EMUGL_LIBNAME(). Don't #error, leave it undefined */ +#endif + + +#endif diff --git a/emulator/opengl/shared/OpenglOsUtils/osProcess.h b/emulator/opengl/shared/OpenglOsUtils/osProcess.h new file mode 100644 index 0000000..82b31b3 --- /dev/null +++ b/emulator/opengl/shared/OpenglOsUtils/osProcess.h @@ -0,0 +1,62 @@ +/* +* 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 _OSUTILS_PROCESS_H +#define _OSUTILS_PROCESS_H + +#ifdef _WIN32 +#include <windows.h> +#endif + +namespace osUtils { + +class childProcess +{ +public: + static childProcess *create(const char *p_cmdLine, const char *p_startdir); + ~childProcess(); + + int getPID() + { +#ifdef _WIN32 + return m_proc.dwProcessId; +#else + return(m_pid); +#endif + } + + int tryWait(bool& isAlive); + bool wait(int *exitStatus); + +private: + childProcess() {}; + +private: +#ifdef _WIN32 + PROCESS_INFORMATION m_proc; +#else + int m_pid; +#endif +}; + +int ProcessGetPID(); +int ProcessGetTID(); +bool ProcessGetName(char *p_outName, int p_outNameLen); +int KillProcess(int pid, bool wait); +bool isProcessRunning(int pid); + +} // of namespace osUtils + +#endif diff --git a/emulator/opengl/shared/OpenglOsUtils/osProcessUnix.cpp b/emulator/opengl/shared/OpenglOsUtils/osProcessUnix.cpp new file mode 100644 index 0000000..c97ff58 --- /dev/null +++ b/emulator/opengl/shared/OpenglOsUtils/osProcessUnix.cpp @@ -0,0 +1,210 @@ +/* +* 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 "osProcess.h" +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <poll.h> +#include <pthread.h> +#include <string.h> +#include <pwd.h> +#include <paths.h> +#include <errno.h> +#include <signal.h> +#include <unistd.h> +#include <assert.h> + +namespace osUtils { + +// +// buildArgList converts a command line into null terminated argument list. +// to be used with execv or execvp. +// each argument is seperated by space or tab, to specify multiple words +// at the same argument place it inside single-quoted or double-quoted string. +// +static char **buildArgList(const char *command) +{ + char **argv = NULL; + int argvSize = 0; + int nArgs = 0; + char *tmpcmd = strdup(command); + char *t = tmpcmd; + char *strStart = NULL; + int i = 0; + + #define ADD_ARG \ + { \ + nArgs++; \ + if (!argv) { \ + argvSize = 12; \ + argv = (char **)malloc(argvSize * sizeof(char *)); \ + } \ + else if (nArgs > argvSize) { \ + argvSize += 12; \ + argv = (char **)realloc(argv, argvSize * sizeof(char *)); \ + } \ + argv[nArgs-1] = t; \ + t = NULL; \ + } + + while( tmpcmd[i] != '\0' ) { + if (!strStart) { + if (tmpcmd[i] == '"' || tmpcmd[i] == '\'') { + strStart = &tmpcmd[i]; + } + else if (tmpcmd[i] == ' ' || tmpcmd[i] == '\t') { + tmpcmd[i] = '\0'; + if (t) ADD_ARG; + } + else if (!t) { + t = &tmpcmd[i]; + } + } + else if (tmpcmd[i] == *strStart) { + t = strStart; + strStart = NULL; + } + + i++; + } + if (t) { + ADD_ARG; + } + if (nArgs > 0) { + ADD_ARG; // for NULL terminating list + } + + return argv; +} + +static pid_t start_process(const char *command,const char *startDir) +{ + pid_t pid; + + pid = fork(); + + if (pid < 0) { + return pid; + } + else if (pid == 0) { + // + // Close all opened file descriptors + // + for (int i=3; i<256; i++) { + close(i); + } + + if (startDir) { + chdir(startDir); + } + + char **argv = buildArgList(command); + if (!argv) { + return -1; + } + execvp(argv[0], argv); + + perror("execl"); + exit(-101); + } + + return pid; +} + +childProcess * +childProcess::create(const char *p_cmdLine, const char *p_startdir) +{ + childProcess *child = new childProcess(); + if (!child) { + return NULL; + } + + child->m_pid = start_process(p_cmdLine, p_startdir); + if (child->m_pid < 0) { + delete child; + return NULL; + } + + return child; +} + +childProcess::~childProcess() +{ +} + +bool +childProcess::wait(int *exitStatus) +{ + int ret=0; + if (m_pid>0) { + pid_t pid = waitpid(m_pid,&ret,0); + if (pid != -1) { + m_pid=-1; + if (exitStatus) { + *exitStatus = ret; + } + return true; + } + } + return false; +} + +int +childProcess::tryWait(bool &isAlive) +{ + int ret=0; + isAlive = false; + if (m_pid>0) { + pid_t pid = waitpid(m_pid,&ret,WNOHANG); + if (pid == 0) { + isAlive = true; + } + } + + return ((char)WEXITSTATUS(ret)); +} + +int ProcessGetPID() +{ + return getpid(); +} + +int KillProcess(int pid, bool wait) +{ + if (pid<1) { + return false; + } + + if (0!=kill(pid,SIGTERM)) { + return false; + } + + if (wait) { + if (waitpid(pid,NULL,0)<0) { + return false; + } + } + + return true; +} + +bool isProcessRunning(int pid) +{ + return (kill(pid,0) == 0); +} + +} // of namespace osUtils diff --git a/emulator/opengl/shared/OpenglOsUtils/osProcessWin.cpp b/emulator/opengl/shared/OpenglOsUtils/osProcessWin.cpp new file mode 100644 index 0000000..6ff0fdf --- /dev/null +++ b/emulator/opengl/shared/OpenglOsUtils/osProcessWin.cpp @@ -0,0 +1,171 @@ +/* +* 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 "osProcess.h" +#include <windows.h> +#include <string> +#include <stdlib.h> +#include <psapi.h> + +namespace osUtils { + +childProcess * +childProcess::create(const char *p_cmdLine, const char *p_startdir) +{ + childProcess *child = new childProcess(); + if (!child) { + return NULL; + } + + STARTUPINFOA si; + ZeroMemory(&si, sizeof(si)); + + ZeroMemory(&child->m_proc, sizeof(child->m_proc)); + BOOL ret = CreateProcessA( + NULL , + (LPSTR)p_cmdLine, + NULL, + NULL, + FALSE, + CREATE_DEFAULT_ERROR_MODE, + NULL, + (p_startdir != NULL ? p_startdir : ".\\"), + &si, + &child->m_proc); + if (ret == 0) { + delete child; + return NULL; + } + + // close the thread handle we do not need it, + // keep the process handle for wait/trywait operations, will + // be closed on destruction + CloseHandle(child->m_proc.hThread); + + return child; +} + +childProcess::~childProcess() +{ + if (m_proc.hProcess) { + CloseHandle(m_proc.hProcess); + } +} + +bool +childProcess::wait(int *exitStatus) +{ +DWORD _exitStatus; + + if (WaitForSingleObject(m_proc.hProcess, INFINITE) == WAIT_FAILED) { + return false; + } + + if (!GetExitCodeProcess(m_proc.hProcess, &_exitStatus)) + { + return false; + } + + if (exitStatus) { + *exitStatus = _exitStatus; + } + + return true; +} + +int +childProcess::tryWait(bool& isAlive) +{ + DWORD status = WaitForSingleObject(m_proc.hProcess, 0); + + if(status == WAIT_OBJECT_0) + { + // process has exited + isAlive = false; + GetExitCodeProcess(m_proc.hProcess, &status); + } + else if (status == WAIT_TIMEOUT) + { + isAlive = true; + status = 0; + } + + return status; + +} + +int ProcessGetPID() +{ + return GetCurrentProcessId(); +} + +int ProcessGetTID() +{ + return GetCurrentThreadId(); +} + +bool ProcessGetName(char *p_outName, int p_outNameLen) +{ + return 0 != GetModuleFileNameEx( GetCurrentProcess(), NULL, p_outName, p_outNameLen); +} + +int KillProcess(int pid, bool wait) +{ + DWORD exitStatus = 1; + HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + + if (NULL == hProc) { + return 0; + } + + // + // Terminate the process + // + TerminateProcess(hProc, 0x55); + + if (wait) { + // + // Wait for it to be terminated + // + if(WaitForSingleObject(hProc, INFINITE) == WAIT_FAILED) { + CloseHandle(hProc); + return 0; + } + + if (!GetExitCodeProcess(hProc, &exitStatus)) { + CloseHandle(hProc); + return 0; + } + } + + CloseHandle(hProc); + + return exitStatus; +} + +bool isProcessRunning(int pid) +{ + bool isRunning = false; + + HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid); + if (NULL != process) { + DWORD ret = WaitForSingleObject(process, 0); + CloseHandle(process); + isRunning = (ret == WAIT_TIMEOUT); + } + return isRunning; +} + +} // of namespace osUtils diff --git a/emulator/opengl/shared/OpenglOsUtils/osThread.h b/emulator/opengl/shared/OpenglOsUtils/osThread.h new file mode 100644 index 0000000..970396d --- /dev/null +++ b/emulator/opengl/shared/OpenglOsUtils/osThread.h @@ -0,0 +1,60 @@ +/* +* 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 _OSUTILS_THREAD_H +#define _OSUTILS_THREAD_H + +#ifdef _WIN32 +#include <windows.h> +#else // !WIN32 +#include <pthread.h> +#endif + +namespace osUtils { + +class Thread +{ +public: + Thread(); + virtual ~Thread(); + + virtual int Main() = 0; + + bool start(); + bool wait(int *exitStatus); + bool trywait(int *exitStatus); + +private: +#ifdef _WIN32 + static DWORD WINAPI thread_main(void *p_arg); +#else // !WIN32 + static void* thread_main(void *p_arg); +#endif + +private: +#ifdef _WIN32 + HANDLE m_thread; + DWORD m_threadId; +#else // !WIN32 + pthread_t m_thread; + int m_exitStatus; + pthread_mutex_t m_lock; +#endif + bool m_isRunning; +}; + +} // of namespace osUtils + +#endif diff --git a/emulator/opengl/shared/OpenglOsUtils/osThreadUnix.cpp b/emulator/opengl/shared/OpenglOsUtils/osThreadUnix.cpp new file mode 100644 index 0000000..d8879eb --- /dev/null +++ b/emulator/opengl/shared/OpenglOsUtils/osThreadUnix.cpp @@ -0,0 +1,94 @@ +/* +* 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 "osThread.h" + +namespace osUtils { + +Thread::Thread() : + m_thread((pthread_t)NULL), + m_exitStatus(0), + m_isRunning(false) +{ + pthread_mutex_init(&m_lock, NULL); +} + +Thread::~Thread() +{ + pthread_mutex_destroy(&m_lock); +} + +bool +Thread::start() +{ + pthread_mutex_lock(&m_lock); + m_isRunning = true; + int ret = pthread_create(&m_thread, NULL, Thread::thread_main, this); + if(ret) { + m_isRunning = false; + } + pthread_mutex_unlock(&m_lock); + return m_isRunning; +} + +bool +Thread::wait(int *exitStatus) +{ + if (!m_isRunning) { + return false; + } + + void *retval; + if (pthread_join(m_thread,&retval)) { + return false; + } + + long long int ret=(long long int)retval; + if (exitStatus) { + *exitStatus = (int)ret; + } + return true; +} + +bool +Thread::trywait(int *exitStatus) +{ + bool ret = false; + + pthread_mutex_lock(&m_lock); + if (!m_isRunning) { + *exitStatus = m_exitStatus; + ret = true; + } + pthread_mutex_unlock(&m_lock); + return ret; +} + +void * +Thread::thread_main(void *p_arg) +{ + Thread *self = (Thread *)p_arg; + int ret = self->Main(); + + pthread_mutex_lock(&self->m_lock); + self->m_isRunning = false; + self->m_exitStatus = ret; + pthread_mutex_unlock(&self->m_lock); + + return (void*)ret; +} + +} // of namespace osUtils + diff --git a/emulator/opengl/shared/OpenglOsUtils/osThreadWin.cpp b/emulator/opengl/shared/OpenglOsUtils/osThreadWin.cpp new file mode 100644 index 0000000..2d563f8 --- /dev/null +++ b/emulator/opengl/shared/OpenglOsUtils/osThreadWin.cpp @@ -0,0 +1,101 @@ +/* +* 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 "osThread.h" + +namespace osUtils { + +Thread::Thread() : + m_thread(NULL), + m_threadId(0), + m_isRunning(false) +{ +} + +Thread::~Thread() +{ + if(m_thread) { + CloseHandle(m_thread); + } +} + +bool +Thread::start() +{ + m_isRunning = true; + m_thread = CreateThread(NULL, 0, &Thread::thread_main, this, 0, &m_threadId); + if(!m_thread) { + m_isRunning = false; + } + return m_isRunning; +} + +bool +Thread::wait(int *exitStatus) +{ + if (!m_isRunning) { + return false; + } + + if(WaitForSingleObject(m_thread, INFINITE) == WAIT_FAILED) { + return false; + } + + DWORD retval; + if (!GetExitCodeThread(m_thread,&retval)) { + return false; + } + + m_isRunning = 0; + + if (exitStatus) { + *exitStatus = retval; + } + return true; +} + +bool +Thread::trywait(int *exitStatus) +{ + if (!m_isRunning) { + return false; + } + + if(WaitForSingleObject(m_thread, 0) == WAIT_OBJECT_0) { + + DWORD retval; + if (!GetExitCodeThread(m_thread,&retval)) { + return true; + } + + if (exitStatus) { + *exitStatus = retval; + } + return true; + } + + return false; +} + +DWORD WINAPI +Thread::thread_main(void *p_arg) +{ + Thread *self = (Thread *)p_arg; + int ret = self->Main(); + self->m_isRunning = false; + return ret; +} + +} // of namespace osUtils |