Implement the robust GetActiveUniformBlockiv entry point.

BUG=angleproject:1354

Change-Id: I2e8051910f50dc040f6be4922142364d36788c4e
Reviewed-on: https://chromium-review.googlesource.com/399041
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 961ff3c..3629f05 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -1619,44 +1619,6 @@
     }
 }
 
-void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
-{
-    ASSERT(
-        uniformBlockIndex <
-        mState.mUniformBlocks.size());  // index must be smaller than getActiveUniformBlockCount()
-
-    const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
-
-    switch (pname)
-    {
-      case GL_UNIFORM_BLOCK_DATA_SIZE:
-        *params = static_cast<GLint>(uniformBlock.dataSize);
-        break;
-      case GL_UNIFORM_BLOCK_NAME_LENGTH:
-          *params =
-              static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArray ? 3 : 0));
-        break;
-      case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
-        *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
-        break;
-      case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
-        {
-            for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
-            {
-                params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
-            }
-        }
-        break;
-      case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
-          *params = static_cast<GLint>(uniformBlock.vertexStaticUse);
-        break;
-      case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
-          *params = static_cast<GLint>(uniformBlock.fragmentStaticUse);
-        break;
-      default: UNREACHABLE();
-    }
-}
-
 GLint Program::getActiveUniformBlockMaxLength() const
 {
     int maxLength = 0;
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
index 93573ea..5a17e92 100644
--- a/src/libANGLE/Program.h
+++ b/src/libANGLE/Program.h
@@ -327,7 +327,6 @@
     void getUniformuiv(GLint location, GLuint *params) const;
 
     void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const;
-    void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const;
     GLuint getActiveUniformBlockCount() const;
     GLint getActiveUniformBlockMaxLength() const;
 
diff --git a/src/libANGLE/queryutils.cpp b/src/libANGLE/queryutils.cpp
index 9914029..904c22f 100644
--- a/src/libANGLE/queryutils.cpp
+++ b/src/libANGLE/queryutils.cpp
@@ -17,6 +17,7 @@
 #include "libANGLE/Sampler.h"
 #include "libANGLE/Shader.h"
 #include "libANGLE/Texture.h"
+#include "libANGLE/Uniform.h"
 #include "libANGLE/VertexAttribute.h"
 
 namespace gl
@@ -624,6 +625,46 @@
     QueryVertexAttribBase(attrib, currentValueData.UnsignedIntValues, pname, params);
 }
 
+void QueryActiveUniformBlockiv(const Program *program,
+                               GLuint uniformBlockIndex,
+                               GLenum pname,
+                               GLint *params)
+{
+    const UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
+    switch (pname)
+    {
+        case GL_UNIFORM_BLOCK_BINDING:
+            *params = ConvertToGLint(program->getUniformBlockBinding(uniformBlockIndex));
+            break;
+        case GL_UNIFORM_BLOCK_DATA_SIZE:
+            *params = ConvertToGLint(uniformBlock.dataSize);
+            break;
+        case GL_UNIFORM_BLOCK_NAME_LENGTH:
+            *params = ConvertToGLint(uniformBlock.nameWithArrayIndex().size() + 1);
+            break;
+        case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
+            *params = ConvertToGLint(uniformBlock.memberUniformIndexes.size());
+            break;
+        case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
+            for (size_t blockMemberIndex = 0;
+                 blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
+            {
+                params[blockMemberIndex] =
+                    ConvertToGLint(uniformBlock.memberUniformIndexes[blockMemberIndex]);
+            }
+            break;
+        case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
+            *params = ConvertToGLint(uniformBlock.vertexStaticUse);
+            break;
+        case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
+            *params = ConvertToGLint(uniformBlock.fragmentStaticUse);
+            break;
+        default:
+            UNREACHABLE();
+            break;
+    }
+}
+
 void SetTexParameterf(Texture *texture, GLenum pname, GLfloat param)
 {
     SetTexParameterBase(texture, pname, &param);
diff --git a/src/libANGLE/queryutils.h b/src/libANGLE/queryutils.h
index e2709e9..58c4e13 100644
--- a/src/libANGLE/queryutils.h
+++ b/src/libANGLE/queryutils.h
@@ -21,6 +21,7 @@
 class Sampler;
 class Shader;
 class Texture;
+struct UniformBlock;
 struct VertexAttribute;
 struct VertexAttribCurrentValueData;
 
@@ -54,6 +55,11 @@
                            GLenum pname,
                            GLuint *params);
 
+void QueryActiveUniformBlockiv(const Program *program,
+                               GLuint uniformBlockIndex,
+                               GLenum pname,
+                               GLint *params);
+
 void SetTexParameterf(Texture *texture, GLenum pname, GLfloat param);
 void SetTexParameterfv(Texture *texture, GLenum pname, const GLfloat *params);
 void SetTexParameteri(Texture *texture, GLenum pname, GLint param);
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 9c96f78..76815ee 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -1003,6 +1003,70 @@
     return true;
 }
 
+bool ValidateGetActiveUniformBlockivBase(Context *context,
+                                         GLuint program,
+                                         GLuint uniformBlockIndex,
+                                         GLenum pname,
+                                         GLsizei *length)
+{
+    if (length)
+    {
+        *length = 0;
+    }
+
+    if (context->getClientMajorVersion() < 3)
+    {
+        context->handleError(
+            Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
+        return false;
+    }
+
+    Program *programObject = GetValidProgram(context, program);
+    if (!programObject)
+    {
+        return false;
+    }
+
+    if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
+    {
+        context->handleError(
+            Error(GL_INVALID_VALUE, "uniformBlockIndex exceeds active uniform block count."));
+        return false;
+    }
+
+    switch (pname)
+    {
+        case GL_UNIFORM_BLOCK_BINDING:
+        case GL_UNIFORM_BLOCK_DATA_SIZE:
+        case GL_UNIFORM_BLOCK_NAME_LENGTH:
+        case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
+        case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
+        case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
+        case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
+            break;
+
+        default:
+            context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
+            return false;
+    }
+
+    if (length)
+    {
+        if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
+        {
+            const UniformBlock &uniformBlock =
+                programObject->getUniformBlockByIndex(uniformBlockIndex);
+            *length = static_cast<GLsizei>(uniformBlock.memberUniformIndexes.size());
+        }
+        else
+        {
+            *length = 1;
+        }
+    }
+
+    return true;
+}
+
 }  // anonymous namespace
 
 bool ValidTextureTarget(const ValidationContext *context, GLenum target)
@@ -4934,4 +4998,39 @@
     return true;
 }
 
+bool ValidateGetActiveUniformBlockiv(Context *context,
+                                     GLuint program,
+                                     GLuint uniformBlockIndex,
+                                     GLenum pname,
+                                     GLint *params)
+{
+    return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr);
+}
+
+bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
+                                                GLuint program,
+                                                GLuint uniformBlockIndex,
+                                                GLenum pname,
+                                                GLsizei bufSize,
+                                                GLsizei *length,
+                                                GLint *params)
+{
+    if (!ValidateRobustEntryPoint(context, bufSize))
+    {
+        return false;
+    }
+
+    if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length))
+    {
+        return false;
+    }
+
+    if (!ValidateRobustBufferSize(context, bufSize, *length))
+    {
+        return false;
+    }
+
+    return true;
+}
+
 }  // namespace gl
diff --git a/src/libANGLE/validationES.h b/src/libANGLE/validationES.h
index de12674..8731870 100644
--- a/src/libANGLE/validationES.h
+++ b/src/libANGLE/validationES.h
@@ -511,6 +511,19 @@
                                             GLsizei *length,
                                             GLuint *params);
 
+bool ValidateGetActiveUniformBlockiv(Context *context,
+                                     GLuint program,
+                                     GLuint uniformBlockIndex,
+                                     GLenum pname,
+                                     GLint *params);
+bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
+                                                GLuint program,
+                                                GLuint uniformBlockIndex,
+                                                GLenum pname,
+                                                GLsizei bufSize,
+                                                GLsizei *length,
+                                                GLint *params);
+
 // Error messages shared here for use in testing.
 extern const char *g_ExceedsMaxElementErrorMessage;
 }  // namespace gl
diff --git a/src/libGLESv2/entry_points_gles_2_0_ext.cpp b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
index b4b5083..b38973c 100644
--- a/src/libGLESv2/entry_points_gles_2_0_ext.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
@@ -2770,7 +2770,21 @@
         "(GLuint program = %u, GLuint uniformBlockIndex = %u, GLenum pname = 0x%X, GLsizei bufsize "
         "= %d, GLsizei* length = 0x%0.8p, GLint* params = 0x%0.8p)",
         program, uniformBlockIndex, pname, bufSize, length, params);
-    UNIMPLEMENTED();
+
+    Context *context = GetValidGlobalContext();
+    if (context)
+    {
+        GLsizei writeLength = 0;
+        if (!ValidateGetActiveUniformBlockivRobustANGLE(context, program, uniformBlockIndex, pname,
+                                                        bufSize, &writeLength, params))
+        {
+            return;
+        }
+
+        const Program *programObject = context->getProgram(program);
+        QueryActiveUniformBlockiv(programObject, uniformBlockIndex, pname, params);
+        SetRobustLengthParam(length, writeLength);
+    }
 }
 
 ANGLE_EXPORT void GL_APIENTRY GetInteger64vRobustANGLE(GLenum pname,
diff --git a/src/libGLESv2/entry_points_gles_3_0.cpp b/src/libGLESv2/entry_points_gles_3_0.cpp
index 263f916..9ab9c66 100644
--- a/src/libGLESv2/entry_points_gles_3_0.cpp
+++ b/src/libGLESv2/entry_points_gles_3_0.cpp
@@ -1624,43 +1624,14 @@
     Context *context = GetValidGlobalContext();
     if (context)
     {
-        if (context->getClientMajorVersion() < 3)
-        {
-            context->handleError(Error(GL_INVALID_OPERATION));
-            return;
-        }
-        Program *programObject = GetValidProgram(context, program);
-
-        if (!programObject)
+        if (!context->skipValidation() &&
+            !ValidateGetActiveUniformBlockiv(context, program, uniformBlockIndex, pname, params))
         {
             return;
         }
 
-        if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
-        {
-            context->handleError(Error(GL_INVALID_VALUE));
-            return;
-        }
-
-        switch (pname)
-        {
-          case GL_UNIFORM_BLOCK_BINDING:
-            *params = static_cast<GLint>(programObject->getUniformBlockBinding(uniformBlockIndex));
-            break;
-
-          case GL_UNIFORM_BLOCK_DATA_SIZE:
-          case GL_UNIFORM_BLOCK_NAME_LENGTH:
-          case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
-          case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
-          case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
-          case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
-            programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
-            break;
-
-          default:
-              context->handleError(Error(GL_INVALID_ENUM));
-            return;
-        }
+        const Program *programObject = context->getProgram(program);
+        QueryActiveUniformBlockiv(programObject, uniformBlockIndex, pname, params);
     }
 }