Add support for glGetnUniform*vEXT

Trac #18608

Signed-off-by: Nicolas Capens

git-svn-id: http://angleproject.googlecode.com/svn/trunk@870 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Program.cpp b/src/libGLESv2/Program.cpp
index 75a00f0..d8d3921 100644
--- a/src/libGLESv2/Program.cpp
+++ b/src/libGLESv2/Program.cpp
@@ -911,7 +911,7 @@
     return true;
 }
 
-bool Program::getUniformfv(GLint location, GLfloat *params)
+bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
 {
     if (location < 0 || location >= (int)mUniformIndex.size())
     {
@@ -920,6 +920,16 @@
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
 
+    // sized queries -- ensure the provided buffer is large enough
+    if (bufSize)
+    {
+        int requiredBytes = UniformExternalSize(targetUniform->type);
+        if (*bufSize < requiredBytes)
+        {
+            return false;
+        }
+    }
+
     switch (targetUniform->type)
     {
       case GL_FLOAT_MAT2:
@@ -970,7 +980,7 @@
     return true;
 }
 
-bool Program::getUniformiv(GLint location, GLint *params)
+bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
 {
     if (location < 0 || location >= (int)mUniformIndex.size())
     {
@@ -979,6 +989,16 @@
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
 
+    // sized queries -- ensure the provided buffer is large enough
+    if (bufSize)
+    {
+        int requiredBytes = UniformExternalSize(targetUniform->type);
+        if (*bufSize < requiredBytes)
+        {
+            return false;
+        }
+    }
+
     switch (targetUniform->type)
     {
       case GL_FLOAT_MAT2:
diff --git a/src/libGLESv2/Program.h b/src/libGLESv2/Program.h
index 793bbf7..462f4e1 100644
--- a/src/libGLESv2/Program.h
+++ b/src/libGLESv2/Program.h
@@ -98,8 +98,8 @@
     bool setUniform3iv(GLint location, GLsizei count, const GLint *v);
     bool setUniform4iv(GLint location, GLsizei count, const GLint *v);
 
-    bool getUniformfv(GLint location, GLfloat *params);
-    bool getUniformiv(GLint location, GLint *params);
+    bool getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params);
+    bool getUniformiv(GLint location, GLsizei *bufSize, GLint *params);
 
     GLint getDxDepthRangeLocation() const;
     GLint getDxDepthLocation() const;
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 6283a1e..7ff1a63 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -3470,6 +3470,46 @@
     }
 }
 
+void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
+{
+    EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)",
+          program, location, bufSize, params);
+
+    try
+    {
+        if (bufSize < 0)
+        {
+            return error(GL_INVALID_VALUE);
+        }
+
+        gl::Context *context = gl::getNonLostContext();
+
+        if (context)
+        {
+            if (program == 0)
+            {
+                return error(GL_INVALID_VALUE);
+            }
+
+            gl::Program *programObject = context->getProgram(program);
+
+            if (!programObject || !programObject->isLinked())
+            {
+                return error(GL_INVALID_OPERATION);
+            }
+
+            if (!programObject->getUniformfv(location, &bufSize, params))
+            {
+                return error(GL_INVALID_OPERATION);
+            }
+        }
+    }
+    catch(std::bad_alloc&)
+    {
+        return error(GL_OUT_OF_MEMORY);
+    }
+}
+
 void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params)
 {
     EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params);
@@ -3492,7 +3532,52 @@
                 return error(GL_INVALID_OPERATION);
             }
 
-            if (!programObject->getUniformfv(location, params))
+            if (!programObject->getUniformfv(location, NULL, params))
+            {
+                return error(GL_INVALID_OPERATION);
+            }
+        }
+    }
+    catch(std::bad_alloc&)
+    {
+        return error(GL_OUT_OF_MEMORY);
+    }
+}
+
+void __stdcall glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params)
+{
+    EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", 
+          program, location, bufSize, params);
+
+    try
+    {
+        if (bufSize < 0)
+        {
+            return error(GL_INVALID_VALUE);
+        }
+
+        gl::Context *context = gl::getNonLostContext();
+
+        if (context)
+        {
+            if (program == 0)
+            {
+                return error(GL_INVALID_VALUE);
+            }
+
+            gl::Program *programObject = context->getProgram(program);
+
+            if (!programObject || !programObject->isLinked())
+            {
+                return error(GL_INVALID_OPERATION);
+            }
+
+            if (!programObject)
+            {
+                return error(GL_INVALID_OPERATION);
+            }
+
+            if (!programObject->getUniformiv(location, &bufSize, params))
             {
                 return error(GL_INVALID_OPERATION);
             }
@@ -3531,7 +3616,7 @@
                 return error(GL_INVALID_OPERATION);
             }
 
-            if (!programObject->getUniformiv(location, params))
+            if (!programObject->getUniformiv(location, NULL, params))
             {
                 return error(GL_INVALID_OPERATION);
             }