ES31: Add glGetProgramInterfaceiv API

Add API entry and validation checks(GLES 3.1 section 7.3).
Add the first 4 interfaces(PROGRAM_INPUT, PROGRAM_OUTPUT,
UNIFORM and UNIFORM_BLOCK) implementation.

BUG=angleproject:1920
TEST=angle_end2end_tests:ProgramInterfaceTestES31.*

Change-Id: Iab80ba332e2a5e2b3e677039359e60a420e3d6b0
Reviewed-on: https://chromium-review.googlesource.com/642729
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/queryutils.cpp b/src/libANGLE/queryutils.cpp
index 46bc656..9d8b2c8 100644
--- a/src/libANGLE/queryutils.cpp
+++ b/src/libANGLE/queryutils.cpp
@@ -445,19 +445,19 @@
     switch (prop)
     {
         case GL_TYPE:
-            return var.type;
+            return ConvertToGLint(var.type);
 
         case GL_ARRAY_SIZE:
             // TODO(jie.a.chen@intel.com): check array of array.
             if (var.isArray() && !var.isStruct())
             {
-                return static_cast<GLint>(var.elementCount());
+                return ConvertToGLint(var.elementCount());
             }
             return 1;
 
         case GL_NAME_LENGTH:
         {
-            GLint length = static_cast<GLint>(var.name.size());
+            size_t length = var.name.size();
             if (var.isArray())
             {
                 // Counts "[0]".
@@ -465,7 +465,7 @@
             }
             // ES31 spec p84: This counts the terminating null char.
             ++length;
-            return length;
+            return ConvertToGLint(length);
         }
 
         case GL_LOCATION:
@@ -527,6 +527,105 @@
     }
 }
 
+GLint QueryProgramInterfaceActiveResources(const Program *program, GLenum programInterface)
+{
+    switch (programInterface)
+    {
+        case GL_PROGRAM_INPUT:
+            return ConvertToGLint(program->getAttributes().size());
+
+        case GL_PROGRAM_OUTPUT:
+            return ConvertToGLint(program->getState().getOutputVariables().size());
+
+        case GL_UNIFORM:
+            return ConvertToGLint(program->getState().getUniforms().size());
+
+        case GL_UNIFORM_BLOCK:
+            return ConvertToGLint(program->getState().getUniformBlocks().size());
+
+        // TODO(jie.a.chen@intel.com): more interfaces.
+        case GL_TRANSFORM_FEEDBACK_VARYING:
+        case GL_BUFFER_VARIABLE:
+        case GL_SHADER_STORAGE_BLOCK:
+        case GL_ATOMIC_COUNTER_BUFFER:
+            UNIMPLEMENTED();
+            return 0;
+
+        default:
+            UNREACHABLE();
+            return 0;
+    }
+}
+
+template <typename T, typename M>
+GLint FindMaxSize(const std::vector<T> &resources, M member)
+{
+    GLint max = 0;
+    for (const T &resource : resources)
+    {
+        max = std::max(max, ConvertToGLint((resource.*member).size()));
+    }
+    return max;
+}
+
+GLint QueryProgramInterfaceMaxNameLength(const Program *program, GLenum programInterface)
+{
+    GLint maxNameLength = 0;
+    switch (programInterface)
+    {
+        case GL_PROGRAM_INPUT:
+            maxNameLength = FindMaxSize(program->getAttributes(), &sh::Attribute::name);
+            break;
+
+        case GL_PROGRAM_OUTPUT:
+            maxNameLength =
+                FindMaxSize(program->getState().getOutputVariables(), &sh::OutputVariable::name);
+            break;
+
+        case GL_UNIFORM:
+            maxNameLength = FindMaxSize(program->getState().getUniforms(), &LinkedUniform::name);
+            break;
+
+        case GL_UNIFORM_BLOCK:
+            maxNameLength =
+                FindMaxSize(program->getState().getUniformBlocks(), &UniformBlock::name);
+            break;
+
+        // TODO(jie.a.chen@intel.com): more interfaces.
+        case GL_TRANSFORM_FEEDBACK_VARYING:
+        case GL_BUFFER_VARIABLE:
+        case GL_SHADER_STORAGE_BLOCK:
+            UNIMPLEMENTED();
+            return 0;
+
+        default:
+            UNREACHABLE();
+            return 0;
+    }
+    // This length includes an extra character for the null terminator.
+    return (maxNameLength == 0 ? 0 : maxNameLength + 1);
+}
+
+GLint QueryProgramInterfaceMaxNumActiveVariables(const Program *program, GLenum programInterface)
+{
+    switch (programInterface)
+    {
+        case GL_UNIFORM_BLOCK:
+            return FindMaxSize(program->getState().getUniformBlocks(),
+                               &UniformBlock::memberIndexes);
+
+        // TODO(jie.a.chen@intel.com): more interfaces.
+        case GL_SHADER_STORAGE_BLOCK:
+        case GL_ATOMIC_COUNTER_BUFFER:
+            UNIMPLEMENTED();
+            return 0;
+
+        default:
+            UNREACHABLE();
+            return 0;
+    }
+}
+
 }  // anonymous namespace
 
 void QueryFramebufferAttachmentParameteriv(const Framebuffer *framebuffer,
@@ -1261,6 +1360,30 @@
     }
 }
 
+void QueryProgramInterfaceiv(const Program *program,
+                             GLenum programInterface,
+                             GLenum pname,
+                             GLint *params)
+{
+    switch (pname)
+    {
+        case GL_ACTIVE_RESOURCES:
+            *params = QueryProgramInterfaceActiveResources(program, programInterface);
+            break;
+
+        case GL_MAX_NAME_LENGTH:
+            *params = QueryProgramInterfaceMaxNameLength(program, programInterface);
+            break;
+
+        case GL_MAX_NUM_ACTIVE_VARIABLES:
+            *params = QueryProgramInterfaceMaxNumActiveVariables(program, programInterface);
+            break;
+
+        default:
+            UNREACHABLE();
+    }
+}
+
 }  // namespace gl
 
 namespace egl