Implements ValidateProgram
TRAC #11654
Signed-off-by: Andrew Lewycky
Signed-off-by: Daniel Koch

Author:    Shannon Woods

git-svn-id: https://angleproject.googlecode.com/svn/trunk@196 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index f21f8b6..a60d7d9 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -1861,6 +1861,11 @@
         return;
     }
 
+    if (!getCurrentProgram()->validateSamplers())
+    {
+        return error(GL_INVALID_OPERATION);
+    }
+
     if (!applyRenderTarget(false))
     {
         return error(GL_INVALID_FRAMEBUFFER_OPERATION);
@@ -1903,6 +1908,11 @@
         return;
     }
 
+    if (!getCurrentProgram()->validateSamplers())
+    {
+        return error(GL_INVALID_OPERATION);
+    }
+
     if (!applyRenderTarget(false))
     {
         return error(GL_INVALID_FRAMEBUFFER_OPERATION);
diff --git a/src/libGLESv2/Program.cpp b/src/libGLESv2/Program.cpp
index 52d4016..10ab4a1 100644
--- a/src/libGLESv2/Program.cpp
+++ b/src/libGLESv2/Program.cpp
@@ -48,6 +48,7 @@
     mPixelHLSL = NULL;
     mVertexHLSL = NULL;
     mInfoLog = NULL;
+    mValidated = false;
 
     unlink();
 
@@ -1882,6 +1883,14 @@
     }
 }
 
+void Program::resetInfoLog()
+{
+    if (mInfoLog)
+    {
+        delete [] mInfoLog;
+    }
+}
+
 // Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
 void Program::unlink(bool destroy)
 {
@@ -1960,6 +1969,11 @@
     return mLinked;
 }
 
+bool Program::isValidated() const 
+{
+    return mValidated;
+}
+
 int Program::getInfoLogLength() const
 {
     if (!mInfoLog)
@@ -2164,4 +2178,49 @@
 {
     return mDeleteStatus;
 }
+
+void Program::validate()
+{
+    resetInfoLog();
+
+    if (!isLinked()) 
+    {
+        appendToInfoLog("Program has not been successfully linked.");
+        mValidated = false;
+    }
+    else if (!validateSamplers())
+    {
+        appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
+        mValidated = false;
+    }
+    else
+    {
+        mValidated = true;
+    }
+}
+
+bool Program::validateSamplers() const
+{
+    // if any two active samplers in a program are of different types, but refer to the same
+    // texture image unit, and this is the current program, then ValidateProgram will fail, and
+    // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
+    std::map<int, SamplerType> samplerMap; 
+    for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
+    {
+        if (mSamplers[i].active)
+        {
+            if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
+            {
+                if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
+                    return false;
+            }
+            else
+            {
+                samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
+            }
+        }
+    }
+
+    return true;
+}
 }
diff --git a/src/libGLESv2/Program.h b/src/libGLESv2/Program.h
index dad3355..6188df9 100644
--- a/src/libGLESv2/Program.h
+++ b/src/libGLESv2/Program.h
@@ -102,6 +102,10 @@
     void flagForDeletion();
     bool isFlaggedForDeletion() const;
 
+    void validate();
+    bool validateSamplers() const;
+    bool isValidated() const;
+
   private:
     DISALLOW_COPY_AND_ASSIGN(Program);
 
@@ -150,6 +154,7 @@
     bool applyUniform4iv(GLint location, GLsizei count, const GLint *v);
 
     void appendToInfoLog(const char *info, ...);
+    void resetInfoLog();
 
     FragmentShader *mFragmentShader;
     VertexShader *mVertexShader;
@@ -183,6 +188,7 @@
     bool mLinked;
     bool mDeleteStatus;   // Flag to indicate that the program can be deleted when no longer in use
     char *mInfoLog;
+    bool mValidated;
 };
 }
 
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index bda72ea..5bf0d14 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -2424,8 +2424,7 @@
                 *params = programObject->isLinked();
                 return;
               case GL_VALIDATE_STATUS:
-                UNIMPLEMENTED();   // FIXME
-                *params = GL_TRUE;
+                *params = programObject->isValidated();
                 return;
               case GL_INFO_LOG_LENGTH:
                 *params = programObject->getInfoLogLength();
@@ -4723,7 +4722,26 @@
 
     try
     {
-        UNIMPLEMENTED();   // FIXME
+        gl::Context *context = gl::getContext();
+
+        if (context)
+        {
+            gl::Program *programObject = context->getProgram(program);
+
+            if (!programObject)
+            {
+                if (context->getShader(program))
+                {
+                    return error(GL_INVALID_OPERATION);
+                }
+                else
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+            }
+
+            programObject->validate();
+        }
     }
     catch(std::bad_alloc&)
     {