Compiler - implement shader and program queries
TRAC #11599
Signed-off-by: Shannon Woods
Signed-off-by: Daniel Koch
Author:    Nicolas Capens

git-svn-id: https://angleproject.googlecode.com/svn/trunk@76 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Program.cpp b/src/libGLESv2/Program.cpp
index a9f2f64..5686b16 100644
--- a/src/libGLESv2/Program.cpp
+++ b/src/libGLESv2/Program.cpp
@@ -41,6 +41,8 @@
         mAttributeName[index] = NULL;
     }
 
+    mInfoLog = NULL;
+
     unlink();
 
     mDeleteStatus = false;
@@ -107,6 +109,11 @@
     return true;
 }
 
+int Program::getAttachedShadersCount() const
+{
+    return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
+}
+
 IDirect3DPixelShader9 *Program::getPixelShader()
 {
     return mPixelExecutable;
@@ -385,6 +392,7 @@
     if (errorMessage)
     {
         const char *message = (const char*)errorMessage->GetBufferPointer();
+
         TRACE("\n%s", hlsl);
         TRACE("\n%s", message);
     }
@@ -404,6 +412,9 @@
 
     unlink();
 
+    delete[] mInfoLog;
+    mInfoLog = NULL;
+
     if (!mFragmentShader || !mFragmentShader->isCompiled())
     {
         return;
@@ -910,6 +921,32 @@
     return true;
 }
 
+void Program::appendToInfoLog(const char *info)
+{
+    if (!info)
+    {
+        return;
+    }
+
+    size_t infoLength = strlen(info);
+
+    if (!mInfoLog)
+    {
+        mInfoLog = new char[infoLength + 1];
+        strcpy(mInfoLog, info);
+    }
+    else
+    {
+        size_t logLength = strlen(mInfoLog);
+        char *newLog = new char[logLength + infoLength + 1];
+        strcpy(newLog, mInfoLog);
+        strcpy(newLog + logLength, info);
+
+        delete[] mInfoLog;
+        mInfoLog = newLog;
+    }
+}
+
 // Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
 void Program::unlink(bool destroy)
 {
@@ -932,6 +969,9 @@
             delete[] mAttributeName[index];
             mAttributeName[index] = NULL;
         }
+
+        delete[] mInfoLog;
+        mInfoLog = NULL;
     }
 
     if (mPixelExecutable)
@@ -982,6 +1022,42 @@
     return mLinked;
 }
 
+int Program::getInfoLogLength() const
+{
+    if (!mInfoLog)
+    {
+        return 0;
+    }
+    else
+    {
+       return strlen(mInfoLog) + 1;
+    }
+}
+
+void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+    int index = 0;
+
+    if (mInfoLog)
+    {
+        while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
+        {
+            infoLog[index] = mInfoLog[index];
+            index++;
+        }
+    }
+
+    if (bufSize)
+    {
+        infoLog[index] = '\0';
+    }
+
+    if (length)
+    {
+        *length = index;
+    }
+}
+
 void Program::flagForDeletion()
 {
     mDeleteStatus = true;
diff --git a/src/libGLESv2/Program.h b/src/libGLESv2/Program.h
index 157e36e..0ce0add 100644
--- a/src/libGLESv2/Program.h
+++ b/src/libGLESv2/Program.h
@@ -55,6 +55,7 @@
 
     bool attachShader(Shader *shader);
     bool detachShader(Shader *shader);
+    int getAttachedShadersCount() const;
 
     IDirect3DPixelShader9 *getPixelShader();
     IDirect3DVertexShader9 *getVertexShader();
@@ -81,6 +82,8 @@
 
     void link();
     bool isLinked();
+    int getInfoLogLength() const;
+    void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);
 
     void flagForDeletion();
     bool isFlaggedForDeletion() const;
@@ -105,6 +108,8 @@
     bool applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value);
     bool applyUniform1iv(GLint location, GLsizei count, const GLint *v);
 
+    void appendToInfoLog(const char *info);
+
     FragmentShader *mFragmentShader;
     VertexShader *mVertexShader;
 
@@ -130,6 +135,7 @@
 
     bool mLinked;
     bool mDeleteStatus;   // Flag to indicate that the program can be deleted when no longer in use
+    char *mInfoLog;
 };
 }
 
diff --git a/src/libGLESv2/Shader.cpp b/src/libGLESv2/Shader.cpp
index f95b4c7..b17a6c9 100644
--- a/src/libGLESv2/Shader.cpp
+++ b/src/libGLESv2/Shader.cpp
@@ -24,7 +24,7 @@
 {
     mSource = NULL;
     mHlsl = NULL;
-    mErrors = NULL;
+    mInfoLog = NULL;
 
     // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
     if (!mFragmentCompiler)
@@ -46,7 +46,7 @@
 {
     delete[] mSource;
     delete[] mHlsl;
-    delete[] mErrors;
+    delete[] mInfoLog;
 }
 
 void Shader::setSource(GLsizei count, const char **string, const GLint *length)
@@ -89,6 +89,78 @@
     mSource[totalLength] = '\0';
 }
 
+int Shader::getInfoLogLength() const
+{
+    if (!mInfoLog)
+    {
+        return 0;
+    }
+    else
+    {
+       return strlen(mInfoLog) + 1;
+    }
+}
+
+void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+    int index = 0;
+
+    if (mInfoLog)
+    {
+        while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
+        {
+            infoLog[index] = mInfoLog[index];
+            index++;
+        }
+    }
+
+    if (bufSize)
+    {
+        infoLog[index] = '\0';
+    }
+
+    if (length)
+    {
+        *length = index;
+    }
+}
+
+int Shader::getSourceLength() const
+{
+    if (!mSource)
+    {
+        return 0;
+    }
+    else
+    {
+       return strlen(mSource) + 1;
+    }
+}
+
+void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
+{
+    int index = 0;
+
+    if (mSource)
+    {
+        while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
+        {
+            source[index] = mSource[index];
+            index++;
+        }
+    }
+
+    if (bufSize)
+    {
+        source[index] = '\0';
+    }
+
+    if (length)
+    {
+        *length = index;
+    }
+}
+
 bool Shader::isCompiled()
 {
     return mHlsl != NULL;
@@ -119,6 +191,11 @@
     return mDeleteStatus == true && mAttachCount == 0;
 }
 
+bool Shader::isFlaggedForDeletion() const
+{
+    return mDeleteStatus;
+}
+
 void Shader::flagForDeletion()
 {
     mDeleteStatus = true;
@@ -142,8 +219,8 @@
 
     TRACE("\n%s", mSource);
 
-    delete[] mErrors;
-    mErrors = NULL;
+    delete[] mInfoLog;
+    mInfoLog = NULL;
 
     TBuiltInResource resources;
 
@@ -169,10 +246,10 @@
     }
     else
     {
-        mErrors = new char[strlen(info) + 1];
-        strcpy(mErrors, info);
+        mInfoLog = new char[strlen(info) + 1];
+        strcpy(mInfoLog, info);
 
-        TRACE("\n%s", mErrors);
+        TRACE("\n%s", mInfoLog);
     }
 }
 
diff --git a/src/libGLESv2/Shader.h b/src/libGLESv2/Shader.h
index 3bac7f8..e555064 100644
--- a/src/libGLESv2/Shader.h
+++ b/src/libGLESv2/Shader.h
@@ -31,6 +31,10 @@
 
     void deleteSource();
     void setSource(GLsizei count, const char **string, const GLint *length);
+    int getInfoLogLength() const;
+    void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);
+    int getSourceLength() const;
+    void getSource(GLsizei bufSize, GLsizei *length, char *source);
 
     virtual void compile() = 0;
     bool isCompiled();
@@ -40,6 +44,7 @@
     void detach();
     bool isAttached() const;
     bool isDeletable() const;
+    bool isFlaggedForDeletion() const;
     void flagForDeletion();
 
     static void releaseCompiler();
@@ -54,7 +59,7 @@
 
     char *mSource;
     char *mHlsl;
-    char *mErrors;
+    char *mInfoLog;
 
     static void *mFragmentCompiler;
     static void *mVertexCompiler;
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 6757249..ec4f0fa 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -1928,8 +1928,7 @@
             switch (pname)
             {
               case GL_DELETE_STATUS:
-                UNIMPLEMENTED();   // FIXME
-                *params = GL_FALSE;
+                *params = programObject->isFlaggedForDeletion();
                 return;
               case GL_LINK_STATUS:
                 *params = programObject->isLinked();
@@ -1939,12 +1938,10 @@
                 *params = GL_TRUE;
                 return;
               case GL_INFO_LOG_LENGTH:
-                UNIMPLEMENTED();   // FIXME
-                *params = 0;
+                *params = programObject->getInfoLogLength();
                 return;
               case GL_ATTACHED_SHADERS:
-                UNIMPLEMENTED();   // FIXME
-                *params = 2;
+                *params = programObject->getAttachedShadersCount();
                 return;
               case GL_ACTIVE_ATTRIBUTES:
                 UNIMPLEMENTED();   // FIXME
@@ -1985,7 +1982,19 @@
             return error(GL_INVALID_VALUE);
         }
 
-        UNIMPLEMENTED();   // FIXME
+        gl::Context *context = gl::getContext();
+
+        if (context)
+        {
+            gl::Program *programObject = context->getProgram(program);
+
+            if (!programObject)
+            {
+                return error(GL_INVALID_VALUE);
+            }
+
+            programObject->getInfoLog(bufsize, length, infolog);
+        }
     }
     catch(std::bad_alloc&)
     {
@@ -2030,19 +2039,16 @@
                 *params = shaderObject->getType();
                 return;
               case GL_DELETE_STATUS:
-                UNIMPLEMENTED();   // FIXME
-                *params = GL_FALSE;
+                *params = shaderObject->isFlaggedForDeletion();
                 return;
               case GL_COMPILE_STATUS:
                 *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE;
                 return;
               case GL_INFO_LOG_LENGTH:
-                UNIMPLEMENTED();   // FIXME
-                *params = 0;
+                *params = shaderObject->getInfoLogLength();
                 return;
               case GL_SHADER_SOURCE_LENGTH:
-                UNIMPLEMENTED();   // FIXME
-                *params = 1;
+                *params = shaderObject->getSourceLength();
                 return;
               default:
                 return error(GL_INVALID_ENUM);
@@ -2067,7 +2073,19 @@
             return error(GL_INVALID_VALUE);
         }
 
-        UNIMPLEMENTED();   // FIXME
+        gl::Context *context = gl::getContext();
+
+        if (context)
+        {
+            gl::Shader *shaderObject = context->getShader(shader);
+
+            if (!shaderObject)
+            {
+                return error(GL_INVALID_VALUE);
+            }
+
+            shaderObject->getInfoLog(bufsize, length, infolog);
+        }
     }
     catch(std::bad_alloc&)
     {
@@ -2102,7 +2120,19 @@
             return error(GL_INVALID_VALUE);
         }
 
-        UNIMPLEMENTED();   // FIXME
+        gl::Context *context = gl::getContext();
+
+        if (context)
+        {
+            gl::Shader *shaderObject = context->getShader(shader);
+
+            if (!shaderObject)
+            {
+                return error(GL_INVALID_VALUE);
+            }
+
+            shaderObject->getSource(bufsize, length, source);
+        }
     }
     catch(std::bad_alloc&)
     {