opengles emulator: fix glGetUnifrom

added state tracking for uniforms in program objects
for each active uniform in index i we will save its starting location
,size and type, so when calling glGetUniform on its location,
we can tell how many bytes we should read from the stream according to
the uniform's type

add some type and size definitions to functions
that calculate size from enum

some other fixes to the codec

Change-Id: I4ecdf41e752454a908d131e76bab113a616f2bc8
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/GLClientState.h b/tools/emulator/opengl/shared/OpenglCodecCommon/GLClientState.h
index b7fcff5..bc895d7 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/GLClientState.h
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/GLClientState.h
@@ -167,6 +167,7 @@
             handled = false;
             break;
         default:
+            handled = false;
             ERR("unknown vertex-attrib parameter param %d\n", param);
         }
         return handled;
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp b/tools/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp
index 84a73ef..768e3c9 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp
@@ -10,16 +10,75 @@
     if (data) memcpy(buffer, data, size);
 }
 
+/**** ProgramData ****/
+ProgramData::ProgramData() : m_numIndexes(0), m_initialized(false)
+{
+    m_Indexes = NULL;
+}
+
+void ProgramData::initProgramData(GLuint numIndexes)
+{
+    m_initialized = true;
+    m_numIndexes = numIndexes;
+    delete[] m_Indexes;
+    m_Indexes = new IndexInfo[numIndexes];
+}
+
+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;
+}
+
+GLuint ProgramData::getIndexForLocation(GLint location)
+{
+    GLuint i=0;
+    for (i=0;i<m_numIndexes;++i)
+    {
+        GLint low = m_Indexes[i].base;;
+        GLint high = low + m_Indexes[i].size;
+        if (location >= low && location < high)
+            break;
+    }
+    return i;
+}
+
+GLenum ProgramData::getTypeForLocation(GLint location)
+{
+    GLuint index = getIndexForLocation(location);
+    if (index<m_numIndexes) {
+        return m_Indexes[index].type;
+    }
+    return 0;
+}
+
 /***** GLSharedGroup ****/
 
 GLSharedGroup::GLSharedGroup() :
-    m_buffers(android::DefaultKeyedVector<GLuint, BufferData*>(NULL))
+    m_buffers(android::DefaultKeyedVector<GLuint, BufferData*>(NULL)),
+    m_programs(android::DefaultKeyedVector<GLuint, ProgramData*>(NULL)),
+    m_shaders(android::List<GLuint>())
 {
 }
 
 GLSharedGroup::~GLSharedGroup()
 {
     m_buffers.clear();
+    m_programs.clear();
 }
 
 BufferData * GLSharedGroup::getBufferData(GLuint bufferId)
@@ -56,3 +115,111 @@
     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::setProgramIndexInfo(GLuint program, GLuint index, GLint base, GLint size, GLenum type)
+{
+    android::AutoMutex _lock(m_lock);
+    ProgramData* pData = m_programs.valueFor(program);
+    if (pData)
+    {
+        pData->setIndexInfo(index,base,size,type);
+    }
+}
+
+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::addShaderData(GLuint shader)
+{
+    android::AutoMutex _lock(m_lock);
+    m_shaders.push_front(shader);
+    
+}
+bool  GLSharedGroup::isShader(GLuint shader)
+{
+    android::AutoMutex _lock(m_lock);
+    android::List<GLuint>::iterator iter;
+    iter = m_shaders.begin();
+    while (iter!=m_shaders.end())
+    {
+        if (*iter==shader)
+            return true;
+        iter++;
+    }
+    return false;
+}
+void  GLSharedGroup::deleteShaderData(GLuint shader)
+{
+    android::AutoMutex _lock(m_lock);
+    android::List<GLuint>::iterator iter;
+    iter = m_shaders.begin();
+    while (iter!=m_shaders.end())
+    {
+        if (*iter==shader)
+        {
+            m_shaders.erase(iter);
+            return;
+        }
+        iter++;
+    }
+}
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h b/tools/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h
index 0f07f47..46e91f8 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h
@@ -32,6 +32,7 @@
 #include "ErrorLog.h"
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
+#include <utils/List.h>
 #include "FixedBuffer.h"
 #include "SmartPtr.h"
 
@@ -42,10 +43,32 @@
     FixedBuffer m_fixedBuffer;    
 };
 
+class ProgramData {
+private:
+    typedef struct _IndexInfo {
+        GLint base;
+        GLint size;
+        GLenum type;
+    }IndexInfo;
+
+    GLuint m_numIndexes;
+    IndexInfo* m_Indexes;
+    bool m_initialized;
+public:
+    ProgramData();
+    void initProgramData(GLuint numIndexes);
+    bool isInitialized();
+    virtual ~ProgramData();
+    void setIndexInfo(GLuint index, GLint base, GLint size, GLenum type);
+    GLuint getIndexForLocation(GLint location);
+    GLenum getTypeForLocation(GLint location);
+};
 
 class GLSharedGroup {
 private:
     android::DefaultKeyedVector<GLuint, BufferData*>    m_buffers;
+    android::DefaultKeyedVector<GLuint, ProgramData*>    m_programs;
+    android::List<GLuint> m_shaders;
     mutable android::Mutex       m_lock;
 public:
     GLSharedGroup();
@@ -55,6 +78,19 @@
     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    deleteProgramData(GLuint program);
+    void    setProgramIndexInfo(GLuint program, GLuint index, GLint base, GLint size, GLenum type);
+    GLenum  getProgramUniformType(GLuint program, GLint location);
+
+    void    addShaderData(GLuint shader);
+    bool    isShader(GLuint shader);
+    void    deleteShaderData(GLuint shader);
+
 };
 
 typedef SmartPtr<GLSharedGroup> GLSharedGroupPtr; 
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
index 4376b6a..b0702a7 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
@@ -30,8 +30,10 @@
     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
@@ -39,6 +41,32 @@
         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__);
     }
@@ -250,6 +278,7 @@
     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:
@@ -282,6 +311,7 @@
     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:
@@ -320,9 +350,12 @@
     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:
@@ -331,6 +364,13 @@
     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;
@@ -345,6 +385,8 @@
 #endif
         case GL_ALPHA:
         case GL_LUMINANCE:
+        case GL_DEPTH_COMPONENT:
+        case GL_DEPTH_STENCIL_OES:
             components = 1;
             break;
         case GL_LUMINANCE_ALPHA:
diff --git a/tools/emulator/opengl/system/GLESv2_enc/GL2Encoder.cpp b/tools/emulator/opengl/system/GLESv2_enc/GL2Encoder.cpp
index eda8f98..225d4ff 100644
--- a/tools/emulator/opengl/system/GLESv2_enc/GL2Encoder.cpp
+++ b/tools/emulator/opengl/system/GLESv2_enc/GL2Encoder.cpp
@@ -47,6 +47,13 @@
     set_glShaderSource(s_glShaderSource);
     set_glFinish(s_glFinish);
     m_glGetError_enc = set_glGetError(s_glGetError);
+    m_glLinkProgram_enc = set_glLinkProgram(s_glLinkProgram);
+    m_glDeleteProgram_enc = set_glDeleteProgram(s_glDeleteProgram);
+    m_glGetUniformiv_enc = set_glGetUniformiv(s_glGetUniformiv);
+    m_glGetUniformfv_enc = set_glGetUniformfv(s_glGetUniformfv);
+    m_glCreateProgram_enc = set_glCreateProgram(s_glCreateProgram);
+    m_glCreateShader_enc = set_glCreateShader(s_glCreateShader);
+    m_glDeleteShader_enc = set_glDeleteShader(s_glDeleteShader);
 }
 
 GL2Encoder::~GL2Encoder()
@@ -416,3 +423,86 @@
     ctx->glFinishRoundTrip(self);
 }
 
+void GL2Encoder::s_glLinkProgram(void * self, GLuint program)
+{
+    GL2Encoder *ctx = (GL2Encoder *)self;
+    ctx->m_glLinkProgram_enc(self, program);
+
+    GLint linkStatus = 0;
+    ctx->glGetProgramiv(self,program,GL_LINK_STATUS,&linkStatus);
+    if (!linkStatus)
+        return;
+
+    //get number of active uniforms in the program
+    GLint numUniforms=0;
+    ctx->glGetProgramiv(self, program, GL_ACTIVE_UNIFORMS, &numUniforms);
+    ctx->m_shared->initProgramData(program,numUniforms);
+
+    //get the length of the longest uniform name
+    GLint maxLength=0;
+    ctx->glGetProgramiv(self, program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+
+    GLint size;
+    GLenum type;
+    GLchar *name = new GLchar[maxLength+1];
+    GLint location;
+    //for each active uniform, get its size and starting location.
+    for (GLint i=0 ; i<numUniforms ; ++i) 
+    {
+        ctx->glGetActiveUniform(self, program, i, maxLength, NULL, &size, &type, name);
+        location = ctx->glGetUniformLocation(self, program, name);
+        ctx->m_shared->setProgramIndexInfo(program, i, location, size, type);
+    }
+
+    delete[] name;
+}
+
+void GL2Encoder::s_glDeleteProgram(void *self, GLuint program)
+{
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    ctx->m_glDeleteProgram_enc(self, program);
+
+    ctx->m_shared->deleteProgramData(program);
+}
+
+void GL2Encoder::s_glGetUniformiv(void *self, GLuint program, GLint location, GLint* params)
+{
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    SET_ERROR_IF(!(ctx->m_shared->isProgram(program) || ctx->m_shared->isShader(program)), GL_INVALID_VALUE);
+    SET_ERROR_IF(!ctx->m_shared->isProgramInitialized(program), GL_INVALID_OPERATION);
+    SET_ERROR_IF(ctx->m_shared->getProgramUniformType(program,location)==0, GL_INVALID_OPERATION);
+    ctx->m_glGetUniformiv_enc(self, program, location, params);
+}
+void GL2Encoder::s_glGetUniformfv(void *self, GLuint program, GLint location, GLfloat* params)
+{
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    SET_ERROR_IF(!(ctx->m_shared->isProgram(program) || ctx->m_shared->isShader(program)), GL_INVALID_VALUE);
+    SET_ERROR_IF(!ctx->m_shared->isProgramInitialized(program), GL_INVALID_OPERATION);
+    SET_ERROR_IF(ctx->m_shared->getProgramUniformType(program,location)==0, GL_INVALID_OPERATION);
+    ctx->m_glGetUniformfv_enc(self, program, location, params);
+}
+
+GLuint GL2Encoder::s_glCreateProgram(void * self)
+{
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    GLuint program = ctx->m_glCreateProgram_enc(self);
+    if (program!=0)
+        ctx->m_shared->addProgramData(program);
+    return program;
+}
+
+GLuint GL2Encoder::s_glCreateShader(void *self, GLenum shaderType)
+{
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    GLuint shader = ctx->m_glCreateShader_enc(self, shaderType);
+    if (shader!=0)
+        ctx->m_shared->addShaderData(shader);
+    return shader;
+}
+
+void GL2Encoder::s_glDeleteShader(void *self, GLenum shader)
+{
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    ctx->m_glDeleteShader_enc(self,shader);
+    ctx->m_shared->deleteShaderData(shader);
+}
diff --git a/tools/emulator/opengl/system/GLESv2_enc/GL2Encoder.h b/tools/emulator/opengl/system/GLESv2_enc/GL2Encoder.h
index d47ddca..3e2dccf 100644
--- a/tools/emulator/opengl/system/GLESv2_enc/GL2Encoder.h
+++ b/tools/emulator/opengl/system/GLESv2_enc/GL2Encoder.h
@@ -32,6 +32,7 @@
     }
     void setSharedGroup(GLSharedGroupPtr shared){ m_shared = shared; }
     const GLClientState *state() { return m_state; }
+    const GLSharedGroupPtr shared() { return m_shared; }
     void flush() {
         gl2_encoder_context_t::m_stream->flush();
     }
@@ -118,5 +119,27 @@
     static void s_glShaderSource(void *self, GLuint shader, GLsizei count, const GLchar **string, const GLint *length);
 
     static void s_glFinish(void *self);
+
+    glLinkProgram_client_proc_t m_glLinkProgram_enc;
+    static void s_glLinkProgram(void *self, GLuint program);
+
+    glDeleteProgram_client_proc_t m_glDeleteProgram_enc;
+    static void s_glDeleteProgram(void * self, GLuint program);
+
+    glGetUniformiv_client_proc_t m_glGetUniformiv_enc;
+    static void s_glGetUniformiv(void *self, GLuint program, GLint location , GLint *params);
+
+    glGetUniformfv_client_proc_t m_glGetUniformfv_enc;
+    static void s_glGetUniformfv(void *self, GLuint program, GLint location , GLfloat *params);
+
+    glCreateProgram_client_proc_t m_glCreateProgram_enc;
+    static GLuint s_glCreateProgram(void *self);
+
+    glCreateShader_client_proc_t m_glCreateShader_enc;
+    static GLuint s_glCreateShader(void *self, GLenum shaderType);
+
+    glDeleteShader_client_proc_t m_glDeleteShader_enc;
+    static void s_glDeleteShader(void *self, GLuint shader);
+
 };
 #endif
diff --git a/tools/emulator/opengl/system/GLESv2_enc/GL2EncoderUtils.cpp b/tools/emulator/opengl/system/GLESv2_enc/GL2EncoderUtils.cpp
index 1984401..57d65c0 100644
--- a/tools/emulator/opengl/system/GLESv2_enc/GL2EncoderUtils.cpp
+++ b/tools/emulator/opengl/system/GLESv2_enc/GL2EncoderUtils.cpp
@@ -30,3 +30,10 @@
     size_t layerSize = pixelDataSize(self, width, height, format, type, pack);
     return layerSize * depth;
 }
+
+GLenum uniformType(void * self, GLuint program, GLint location)
+{
+    GL2Encoder * ctx = (GL2Encoder *) self;
+    assert (ctx->shared() != NULL);
+    return ctx->shared()->getProgramUniformType(program, location);
+}
diff --git a/tools/emulator/opengl/system/GLESv2_enc/GL2EncoderUtils.h b/tools/emulator/opengl/system/GLESv2_enc/GL2EncoderUtils.h
index 7f7f5c4..8e91aeb 100644
--- a/tools/emulator/opengl/system/GLESv2_enc/GL2EncoderUtils.h
+++ b/tools/emulator/opengl/system/GLESv2_enc/GL2EncoderUtils.h
@@ -19,5 +19,6 @@
 extern "C" {
     size_t pixelDataSize(void *self, GLsizei width, GLsizei height, GLenum format, GLenum type, int pack);
     size_t pixelDataSize3D(void *self, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, int pack);
+    GLenum uniformType(void * self, GLuint program, GLint location);
 };
 #endif
diff --git a/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib b/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib
index 10e2987..a90eadf 100644
--- a/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib
+++ b/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib
@@ -76,8 +76,10 @@
 glGetActiveAttrib
 	len name bufsize
 	dir name out
+	var_flag name nullAllowed
 	dir length out
 	len length (sizeof(GLsizei))
+	var_flag length nullAllowed
 	dir size out
 	len size (sizeof(GLint))
 	dir type out
@@ -87,8 +89,10 @@
 glGetActiveUniform
 	len name bufsize
 	dir name out
+	  var_flag name nullAllowed
 	dir length out
 	len length (sizeof(GLsizei))
+	var_flag length nullAllowed
 	dir size out
 	len size (sizeof(GLint))
 	dir type out
@@ -168,7 +172,9 @@
 
 #void glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision)
 glGetShaderPrecisionFormat
-	len range (sizeof(GLint))
+	dir range out
+	len range (2 * sizeof(GLint))
+	dir precision out
 	len precision (sizeof(GLint))
 
 #void glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source)
@@ -195,11 +201,13 @@
 
 #void glGetUniformfv(GLuint program, GLint location, GLfloat *params)
 glGetUniformfv
-	flag unsupported
+	dir params out
+	len params glSizeof(uniformType(self, program, location))
 
 #void glGetUniformiv(GLuint program, GLint location, GLint *params)
 glGetUniformiv
-	flag unsupported
+	dir params out
+	len params glSizeof(uniformType(self, program, location))
 
 #int glGetUniformLocation(GLuint program, GLchar *name)
 glGetUniformLocation
@@ -210,11 +218,13 @@
 # thus we still need to implement it. 
 #void glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params)
 glGetVertexAttribfv
+	dir params out
 	len params (glUtilsParamSize(pname) * sizeof(GLfloat))
 
 #see glGetVertexAttribfv for comments
 #void glGetVertexAttribiv(GLuint index, GLenum pname, GLint *params)
 glGetVertexAttribiv
+	dir params out
 	len params (glUtilsParamSize(pname) * sizeof(GLint))