GLES2 translaotr: fix glLinkProgram and object names

Do not allow glLinkProgram to succeed if only one shader type has been
attached to the program, GL allows this, but GLES2 does not.
added state tracking for program objects to check which shaders are
attached to the program object.

add a way to define object data type being held for each object in objectNameManager
ProgramData and ShaderParser are both valid objectData for objects in SHADER namespace
we need a way to determine object type to generate correct errors

Change-Id: Ic232549df0bb6daf6ec528cb039482cd68e896bb
diff --git a/tools/emulator/opengl/host/libs/Translator/GLES_CM/GLEScmImp.cpp b/tools/emulator/opengl/host/libs/Translator/GLES_CM/GLEScmImp.cpp
index 5922652..68aa2a8 100644
--- a/tools/emulator/opengl/host/libs/Translator/GLES_CM/GLEScmImp.cpp
+++ b/tools/emulator/opengl/host/libs/Translator/GLES_CM/GLEScmImp.cpp
@@ -793,7 +793,7 @@
                 for (int i=0; i<nparams; i++) params[i] = I2X(iparams[i]);
                 delete [] iparams;
             }
-			return;
+            return;
         }
     break;
     default:
@@ -872,8 +872,8 @@
         }
         break;
     case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
-        *params = getCompressedFormats(NULL); 
-        break;    
+        *params = getCompressedFormats(NULL);
+        break;
     case GL_COMPRESSED_TEXTURE_FORMATS:
         getCompressedFormats(params);
         break;
diff --git a/tools/emulator/opengl/host/libs/Translator/GLES_V2/Android.mk b/tools/emulator/opengl/host/libs/Translator/GLES_V2/Android.mk
index acae242..a7c68b1 100644
--- a/tools/emulator/opengl/host/libs/Translator/GLES_V2/Android.mk
+++ b/tools/emulator/opengl/host/libs/Translator/GLES_V2/Android.mk
@@ -9,5 +9,6 @@
      GLESv2Context.cpp                \
      GLESv2Validate.cpp               \
      ShaderParser.cpp                 \
+     ProgramData.cpp
 
 $(call emugl-end-module)
diff --git a/tools/emulator/opengl/host/libs/Translator/GLES_V2/GLESv2Imp.cpp b/tools/emulator/opengl/host/libs/Translator/GLES_V2/GLESv2Imp.cpp
index 099504b..76348ef 100644
--- a/tools/emulator/opengl/host/libs/Translator/GLES_V2/GLESv2Imp.cpp
+++ b/tools/emulator/opengl/host/libs/Translator/GLES_V2/GLESv2Imp.cpp
@@ -30,6 +30,7 @@
 #include "GLESv2Context.h"
 #include "GLESv2Validate.h"
 #include "ShaderParser.h"
+#include "ProgramData.h"
 #include <GLcommon/TextureUtils.h>
 
 extern "C" {
@@ -128,6 +129,17 @@
         SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE);
         const GLuint globalShaderName  = thrd->shareGroup->getGlobalName(SHADER,shader);
         SET_ERROR_IF(globalShaderName==0, GL_INVALID_VALUE);
+
+        ObjectDataPtr programData = thrd->shareGroup->getObjectData(SHADER,program);
+        ObjectDataPtr shaderData = thrd->shareGroup->getObjectData(SHADER,shader);
+        SET_ERROR_IF(!shaderData.Ptr() || !programData.Ptr() ,GL_INVALID_OPERATION);
+        SET_ERROR_IF(!(shaderData.Ptr()->getDataType() ==SHADER_DATA) || 
+                     !(programData.Ptr()->getDataType()==PROGRAM_DATA) ,GL_INVALID_OPERATION);
+
+        GLenum shaderType = ((ShaderParser*)shaderData.Ptr())->getType();
+        ProgramData* pData = (ProgramData*)programData.Ptr();
+        SET_ERROR_IF((pData->getAttachedShader(shaderType)!=0), GL_INVALID_OPERATION);
+        pData->attachShader(shader,shaderType);
         ctx->dispatcher().glAttachShader(globalProgramName,globalShaderName);
     }
 }
@@ -319,8 +331,10 @@
     GET_CTX_RET(0);
     const GLuint globalProgramName = ctx->dispatcher().glCreateProgram();
     if(thrd->shareGroup.Ptr() && globalProgramName) {
+            ProgramData* programInfo = new ProgramData();
             const GLuint localProgramName = thrd->shareGroup->genName(SHADER, 0, true);
             thrd->shareGroup->replaceGlobalName(SHADER,localProgramName,globalProgramName);
+            thrd->shareGroup->setObjectData(SHADER,localProgramName,ObjectDataPtr(programInfo));
             return localProgramName;
     }
     if(globalProgramName){
@@ -400,7 +414,7 @@
     GET_CTX();
     if(program && thrd->shareGroup.Ptr()) {
         const GLuint globalProgramName = thrd->shareGroup->getGlobalName(SHADER,program);
-        SET_ERROR_IF(!globalProgramName,GL_INVALID_VALUE);
+        SET_ERROR_IF(!globalProgramName, GL_INVALID_VALUE);
         thrd->shareGroup->deleteName(SHADER,program);
         ctx->dispatcher().glDeleteProgram(globalProgramName);
     }
@@ -410,7 +424,7 @@
     GET_CTX();
     if(shader && thrd->shareGroup.Ptr()) {
         const GLuint globalShaderName = thrd->shareGroup->getGlobalName(SHADER,shader);
-        SET_ERROR_IF(!globalShaderName,GL_INVALID_VALUE);
+        SET_ERROR_IF(!globalShaderName, GL_INVALID_VALUE);
         thrd->shareGroup->deleteName(SHADER,shader);
         ctx->dispatcher().glDeleteShader(globalShaderName);
     }
@@ -437,6 +451,15 @@
         SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE);
         const GLuint globalShaderName  = thrd->shareGroup->getGlobalName(SHADER,shader);
         SET_ERROR_IF(globalShaderName==0, GL_INVALID_VALUE);
+
+        ObjectDataPtr objData = thrd->shareGroup->getObjectData(SHADER,program);
+        SET_ERROR_IF(!objData.Ptr(),GL_INVALID_OPERATION);
+        SET_ERROR_IF(!(objData.Ptr()->getDataType()==PROGRAM_DATA) ,GL_INVALID_OPERATION);
+
+        ProgramData* programData = (ProgramData*)objData.Ptr();
+        SET_ERROR_IF(!programData->isAttached(shader),GL_INVALID_OPERATION);
+        programData->detachShader(shader);
+
         ctx->dispatcher().glDetachShader(globalProgramName,globalShaderName);
     }
 }
@@ -858,7 +881,19 @@
     if(thrd->shareGroup.Ptr()) {
         const GLuint globalProgramName = thrd->shareGroup->getGlobalName(SHADER,program);
         SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE);
-        ctx->dispatcher().glGetProgramiv(globalProgramName,pname,params);
+        switch(pname) {
+        case GL_LINK_STATUS:
+            {
+                ObjectDataPtr objData = thrd->shareGroup->getObjectData(SHADER,program);
+                SET_ERROR_IF(!objData.Ptr() ,GL_INVALID_OPERATION);
+                SET_ERROR_IF(objData.Ptr()->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION);
+                ProgramData* programData = (ProgramData*)objData.Ptr();
+                params[0] = programData->getLinkStatus();
+            }
+            break;
+        default:
+            ctx->dispatcher().glGetProgramiv(globalProgramName,pname,params);
+        }
     }
 }
 
@@ -925,6 +960,7 @@
        SET_ERROR_IF(globalShaderName == 0,GL_INVALID_VALUE);
        ObjectDataPtr objData = thrd->shareGroup->getObjectData(SHADER,shader);
        SET_ERROR_IF(!objData.Ptr(),GL_INVALID_OPERATION);
+       SET_ERROR_IF(objData.Ptr()->getDataType()!=SHADER_DATA,GL_INVALID_OPERATION);
        const char* src = ((ShaderParser*)objData.Ptr())->getOriginalSrc();
        int srcLength = strlen(src);
 
@@ -1155,10 +1191,20 @@
 
 GL_APICALL void  GL_APIENTRY glLinkProgram(GLuint program){
     GET_CTX();
+    GLint linkStatus = GL_FALSE;
     if(thrd->shareGroup.Ptr()) {
         const GLuint globalProgramName = thrd->shareGroup->getGlobalName(SHADER,program);
         SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE);
-        ctx->dispatcher().glLinkProgram(globalProgramName);
+
+        ObjectDataPtr objData = thrd->shareGroup->getObjectData(SHADER,program);
+        SET_ERROR_IF(!objData.Ptr(), GL_INVALID_OPERATION);
+        SET_ERROR_IF(objData.Ptr()->getDataType()!=PROGRAM_DATA, GL_INVALID_OPERATION);
+        ProgramData* programData = (ProgramData*)objData.Ptr();
+        if (programData->getAttachedVertexShader()!=0 && programData->getAttachedFragmentShader()!=0) {
+            ctx->dispatcher().glLinkProgram(globalProgramName);
+            ctx->dispatcher().glGetProgramiv(globalProgramName,GL_LINK_STATUS,&linkStatus);
+        }
+        programData->setLinkStatus(linkStatus);
     }
 }
 
@@ -1229,6 +1275,7 @@
             SET_ERROR_IF(globalShaderName == 0,GL_INVALID_VALUE);
             ObjectDataPtr objData = thrd->shareGroup->getObjectData(SHADER,shader);
             SET_ERROR_IF(!objData.Ptr(),GL_INVALID_OPERATION);
+            SET_ERROR_IF(objData.Ptr()->getDataType()!=SHADER_DATA,GL_INVALID_OPERATION);
             ShaderParser* sp = (ShaderParser*)objData.Ptr();
             sp->setSrc(ctx->glslVersion(),count,string,length);
             ctx->dispatcher().glShaderSource(globalShaderName,1,sp->parsedLines(),NULL);
diff --git a/tools/emulator/opengl/host/libs/Translator/GLES_V2/ProgramData.cpp b/tools/emulator/opengl/host/libs/Translator/GLES_V2/ProgramData.cpp
new file mode 100644
index 0000000..b3e4a1e
--- /dev/null
+++ b/tools/emulator/opengl/host/libs/Translator/GLES_V2/ProgramData.cpp
@@ -0,0 +1,82 @@
+/*
+* 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 <GLES2/gl2.h>
+#include <GLcommon/objectNameManager.h>
+#include "ProgramData.h"
+
+ProgramData::ProgramData() :  ObjectData(PROGRAM_DATA),
+                              AttachedVertexShader(0),
+                              AttachedFragmentShader(0),
+                              LinkStatus(GL_FALSE) {}
+
+ProgramData::~ProgramData () {};
+
+GLuint ProgramData::getAttachedVertexShader() {
+    return AttachedVertexShader;
+}
+
+GLuint ProgramData::getAttachedFragmentShader() {
+    return AttachedFragmentShader;
+}
+
+GLuint ProgramData::getAttachedShader(GLenum type) {
+    GLuint shader = 0;
+    switch (type) {
+    case GL_VERTEX_SHADER:
+        shader = AttachedVertexShader;
+        break;
+    case GL_FRAGMENT_SHADER:
+        shader = AttachedFragmentShader;
+        break;
+    }
+    return shader;
+}
+
+bool ProgramData::attachShader(GLuint shader,GLenum type) {
+    if (type==GL_VERTEX_SHADER && AttachedVertexShader==0) {
+        AttachedVertexShader=shader;
+        return true;
+    }
+    else if (type==GL_FRAGMENT_SHADER && AttachedFragmentShader==0) {
+        AttachedFragmentShader=shader;
+        return true;
+    }
+    return false;
+}
+
+bool ProgramData::isAttached(GLuint shader) {
+    return (AttachedFragmentShader==shader || AttachedVertexShader==shader);
+}
+
+bool ProgramData::detachShader(GLuint shader) {
+    if (AttachedVertexShader==shader) {
+        AttachedVertexShader = 0;
+        return true;
+    }
+    else if (AttachedFragmentShader==shader) {
+        AttachedFragmentShader = 0;
+        return true;
+    }
+    return false;
+}
+
+void ProgramData::setLinkStatus(GLint status) {
+    LinkStatus = status;
+}
+
+GLint ProgramData::getLinkStatus() {
+    return LinkStatus;
+}
diff --git a/tools/emulator/opengl/host/libs/Translator/GLES_V2/ProgramData.h b/tools/emulator/opengl/host/libs/Translator/GLES_V2/ProgramData.h
new file mode 100644
index 0000000..2bf7524
--- /dev/null
+++ b/tools/emulator/opengl/host/libs/Translator/GLES_V2/ProgramData.h
@@ -0,0 +1,40 @@
+/*
+* 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 PROGRAM_DATA_H
+#define PROGRAM_DATA_H
+
+class ProgramData:public ObjectData{
+public:
+    ProgramData();
+    virtual ~ProgramData();
+
+    GLuint getAttachedVertexShader();
+    GLuint getAttachedFragmentShader();
+    GLuint getAttachedShader(GLenum type);
+
+    bool attachShader(GLuint shader,GLenum type);
+    bool isAttached(GLuint shader);
+    bool detachShader(GLuint shader);
+
+    void setLinkStatus(GLint status);
+    GLint getLinkStatus();
+
+private:
+    GLuint AttachedVertexShader;
+    GLuint AttachedFragmentShader;
+    GLint  LinkStatus;
+};
+#endif
diff --git a/tools/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.cpp b/tools/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.cpp
index fa7bcd5..0a8390f 100644
--- a/tools/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.cpp
+++ b/tools/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.cpp
@@ -1,12 +1,14 @@
 #include "ShaderParser.h"
 #include <string.h>
 
-ShaderParser::ShaderParser():m_type(0),
+ShaderParser::ShaderParser():ObjectData(SHADER_DATA),
+                             m_type(0),
                              m_src(NULL),
                              m_parsedLines(NULL){};
 
-ShaderParser::ShaderParser(GLenum type):m_type(type),
-                                                    m_parsedLines(NULL){};
+ShaderParser::ShaderParser(GLenum type):ObjectData(SHADER_DATA), 
+                                        m_type(type),
+                                        m_parsedLines(NULL){};
 
 void ShaderParser::setSrc(const Version& ver,GLsizei count,const GLchar** strings,const GLint* length){
     for(int i = 0;i<count;i++){
@@ -83,6 +85,10 @@
     }
 }
 
+GLenum ShaderParser::getType() {
+    return m_type;
+}
+
 ShaderParser::~ShaderParser(){
     clearParsedSrc();
 }
diff --git a/tools/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.h b/tools/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.h
index f7c91fc..4f32f90 100644
--- a/tools/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.h
+++ b/tools/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.h
@@ -13,6 +13,7 @@
     void           setSrc(const Version& ver,GLsizei count,const GLchar** strings,const GLint* length);
     const char*    getOriginalSrc();
     const GLchar** parsedLines(){return const_cast<const GLchar**>(&m_parsedLines);};
+    GLenum         getType();
     ~ShaderParser();
 
 private:
diff --git a/tools/emulator/opengl/host/libs/Translator/include/GLcommon/GLESbuffer.h b/tools/emulator/opengl/host/libs/Translator/include/GLcommon/GLESbuffer.h
index f4dcc7a..3353ec1 100644
--- a/tools/emulator/opengl/host/libs/Translator/include/GLcommon/GLESbuffer.h
+++ b/tools/emulator/opengl/host/libs/Translator/include/GLcommon/GLESbuffer.h
@@ -23,7 +23,7 @@
 
 class GLESbuffer: public ObjectData {
 public:
-   GLESbuffer():m_size(0),m_usage(GL_STATIC_DRAW),m_data(NULL),m_wasBound(false){}
+   GLESbuffer():ObjectData(BUFFER_DATA),m_size(0),m_usage(GL_STATIC_DRAW),m_data(NULL),m_wasBound(false){}
    GLuint getSize(){return m_size;};
    GLuint getUsage(){return m_usage;};
    GLvoid* getData(){ return m_data;}
diff --git a/tools/emulator/opengl/host/libs/Translator/include/GLcommon/GLESvalidate.h b/tools/emulator/opengl/host/libs/Translator/include/GLcommon/GLESvalidate.h
index 11a0741..3daaa7c 100644
--- a/tools/emulator/opengl/host/libs/Translator/include/GLcommon/GLESvalidate.h
+++ b/tools/emulator/opengl/host/libs/Translator/include/GLcommon/GLESvalidate.h
@@ -22,7 +22,7 @@
 {
 static bool textureEnum(GLenum e,unsigned int maxTex);
 static bool pixelType(GLEScontext * ctx,GLenum type);
-static bool pixelOp(GLenum format,GLenum type); 
+static bool pixelOp(GLenum format,GLenum type);
 static bool pixelFrmt(GLEScontext* ctx , GLenum format);
 static bool bufferTarget(GLenum target);
 static bool bufferParam(GLenum param);
diff --git a/tools/emulator/opengl/host/libs/Translator/include/GLcommon/TranslatorIfaces.h b/tools/emulator/opengl/host/libs/Translator/include/GLcommon/TranslatorIfaces.h
index b0d0698..1da4573 100644
--- a/tools/emulator/opengl/host/libs/Translator/include/GLcommon/TranslatorIfaces.h
+++ b/tools/emulator/opengl/host/libs/Translator/include/GLcommon/TranslatorIfaces.h
@@ -37,7 +37,14 @@
     ~TextureData() {
         if (sourceEGLImage && eglImageDetach) (*eglImageDetach)(sourceEGLImage);
     }
-    TextureData():width(0),height(0),border(0),internalFormat(GL_RGBA),sourceEGLImage(0),wasBound(false),requiresAutoMipmap(false){
+    TextureData():  ObjectData(TEXTURE_DATA),
+                    width(0),
+                    height(0),
+                    border(0),
+                    internalFormat(GL_RGBA),
+                    sourceEGLImage(0),
+                    wasBound(false),
+                    requiresAutoMipmap(false){
         memset(crop_rect,0,4*sizeof(int));
     };
 
diff --git a/tools/emulator/opengl/host/libs/Translator/include/GLcommon/gldefs.h b/tools/emulator/opengl/host/libs/Translator/include/GLcommon/gldefs.h
index adefffa..24e4a23 100644
--- a/tools/emulator/opengl/host/libs/Translator/include/GLcommon/gldefs.h
+++ b/tools/emulator/opengl/host/libs/Translator/include/GLcommon/gldefs.h
@@ -17,9 +17,9 @@
 typedef double      GLclampd;   /* double precision float in [0,1] */
 typedef double      GLdouble;   /* double precision float */
 
-#define GL_TEXTURE_GEN_S			0x0C60
-#define GL_TEXTURE_GEN_T			0x0C61
-#define GL_TEXTURE_GEN_R			0x0C62
+#define GL_TEXTURE_GEN_S            0x0C60
+#define GL_TEXTURE_GEN_T            0x0C61
+#define GL_TEXTURE_GEN_R            0x0C62
 #define GL_CLIENT_VERTEX_ARRAY_BIT    0x00000002
 #define GL_TRANSFORM_BIT      0x00001000
 #define GL_INT                0x1404
diff --git a/tools/emulator/opengl/host/libs/Translator/include/GLcommon/objectNameManager.h b/tools/emulator/opengl/host/libs/Translator/include/GLcommon/objectNameManager.h
index fdc4666..aeb01f6 100644
--- a/tools/emulator/opengl/host/libs/Translator/include/GLcommon/objectNameManager.h
+++ b/tools/emulator/opengl/host/libs/Translator/include/GLcommon/objectNameManager.h
@@ -28,13 +28,26 @@
     RENDERBUFFER = 2,
     FRAMEBUFFER = 3,
     SHADER = 4,
-    NUM_OBJECT_TYPES = 6  // Must be last
+    NUM_OBJECT_TYPES = 5  // Must be last
+};
+
+enum ObjectDataType {
+    SHADER_DATA,
+    PROGRAM_DATA,
+    TEXTURE_DATA,
+    BUFFER_DATA,
+    UNDEFINED_DATA
 };
 
 class ObjectData
 {
 public:
-    virtual ~ObjectData() {}
+    ObjectData() : m_dataType(UNDEFINED_DATA) {};
+    ObjectData(ObjectDataType type): m_dataType(type) {};
+    ObjectDataType getDataType() { return m_dataType; };
+    virtual ~ObjectData() {};
+private:
+    ObjectDataType m_dataType;
 };
 typedef SmartPtr<ObjectData> ObjectDataPtr;