ES31: Add glGetProgramResourceiv API

Add API entry and validation checks(GLES 3.1 section 7.3).
Add the first 2 interfaces(PROGRAM_INPUT and PROGRAM_OUTPUT) implementation.

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

Change-Id: I50057f7b99f4dc7c23ca87fa9b797ca424f66e3d
Reviewed-on: https://chromium-review.googlesource.com/475075
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/validationES31.cpp b/src/libANGLE/validationES31.cpp
index d367250..54b7351 100644
--- a/src/libANGLE/validationES31.cpp
+++ b/src/libANGLE/validationES31.cpp
@@ -54,6 +54,195 @@
     }
 }
 
+bool ValidateProgramInterface(GLenum programInterface)
+{
+    return (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
+            ValidateNamedProgramInterface(programInterface));
+}
+
+bool ValidateProgramResourceProperty(GLenum prop)
+{
+    switch (prop)
+    {
+        case GL_ACTIVE_VARIABLES:
+        case GL_BUFFER_BINDING:
+        case GL_NUM_ACTIVE_VARIABLES:
+
+        case GL_ARRAY_SIZE:
+
+        case GL_ARRAY_STRIDE:
+        case GL_BLOCK_INDEX:
+        case GL_IS_ROW_MAJOR:
+        case GL_MATRIX_STRIDE:
+
+        case GL_ATOMIC_COUNTER_BUFFER_INDEX:
+
+        case GL_BUFFER_DATA_SIZE:
+
+        case GL_LOCATION:
+
+        case GL_NAME_LENGTH:
+
+        case GL_OFFSET:
+
+        case GL_REFERENCED_BY_VERTEX_SHADER:
+        case GL_REFERENCED_BY_FRAGMENT_SHADER:
+        case GL_REFERENCED_BY_COMPUTE_SHADER:
+
+        case GL_TOP_LEVEL_ARRAY_SIZE:
+        case GL_TOP_LEVEL_ARRAY_STRIDE:
+
+        case GL_TYPE:
+            return true;
+
+        default:
+            return false;
+    }
+}
+
+// GLES 3.10 spec: Page 82 -- Table 7.2
+bool ValidateProgramResourcePropertyByInterface(GLenum prop, GLenum programInterface)
+{
+    switch (prop)
+    {
+        case GL_ACTIVE_VARIABLES:
+        case GL_BUFFER_BINDING:
+        case GL_NUM_ACTIVE_VARIABLES:
+        {
+            switch (programInterface)
+            {
+                case GL_ATOMIC_COUNTER_BUFFER:
+                case GL_SHADER_STORAGE_BLOCK:
+                case GL_UNIFORM_BLOCK:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        case GL_ARRAY_SIZE:
+        {
+            switch (programInterface)
+            {
+                case GL_BUFFER_VARIABLE:
+                case GL_PROGRAM_INPUT:
+                case GL_PROGRAM_OUTPUT:
+                case GL_TRANSFORM_FEEDBACK_VARYING:
+                case GL_UNIFORM:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        case GL_ARRAY_STRIDE:
+        case GL_BLOCK_INDEX:
+        case GL_IS_ROW_MAJOR:
+        case GL_MATRIX_STRIDE:
+        {
+            switch (programInterface)
+            {
+                case GL_BUFFER_VARIABLE:
+                case GL_UNIFORM:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        case GL_ATOMIC_COUNTER_BUFFER_INDEX:
+        {
+            if (programInterface == GL_UNIFORM)
+            {
+                return true;
+            }
+            return false;
+        }
+
+        case GL_BUFFER_DATA_SIZE:
+        {
+            switch (programInterface)
+            {
+                case GL_ATOMIC_COUNTER_BUFFER:
+                case GL_SHADER_STORAGE_BLOCK:
+                case GL_UNIFORM_BLOCK:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        case GL_LOCATION:
+        {
+            return ValidateLocationProgramInterface(programInterface);
+        }
+
+        case GL_NAME_LENGTH:
+        {
+            return ValidateNamedProgramInterface(programInterface);
+        }
+
+        case GL_OFFSET:
+        {
+            switch (programInterface)
+            {
+                case GL_BUFFER_VARIABLE:
+                case GL_UNIFORM:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        case GL_REFERENCED_BY_VERTEX_SHADER:
+        case GL_REFERENCED_BY_FRAGMENT_SHADER:
+        case GL_REFERENCED_BY_COMPUTE_SHADER:
+        {
+            switch (programInterface)
+            {
+                case GL_ATOMIC_COUNTER_BUFFER:
+                case GL_BUFFER_VARIABLE:
+                case GL_PROGRAM_INPUT:
+                case GL_PROGRAM_OUTPUT:
+                case GL_SHADER_STORAGE_BLOCK:
+                case GL_UNIFORM:
+                case GL_UNIFORM_BLOCK:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        case GL_TOP_LEVEL_ARRAY_SIZE:
+        case GL_TOP_LEVEL_ARRAY_STRIDE:
+        {
+            if (programInterface == GL_BUFFER_VARIABLE)
+            {
+                return true;
+            }
+            return false;
+        }
+
+        case GL_TYPE:
+        {
+            switch (programInterface)
+            {
+                case GL_BUFFER_VARIABLE:
+                case GL_PROGRAM_INPUT:
+                case GL_PROGRAM_OUTPUT:
+                case GL_TRANSFORM_FEEDBACK_VARYING:
+                case GL_UNIFORM:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        default:
+            return false;
+    }
+}
+
 bool ValidateProgramResourceIndex(const Program *programObject,
                                   GLenum programInterface,
                                   GLuint index)
@@ -66,12 +255,13 @@
         case GL_PROGRAM_OUTPUT:
             return (index < static_cast<GLuint>(programObject->getOutputResourceCount()));
 
-        // TODO(Jie): more interfaces.
+        // TODO(jie.a.chen@intel.com): more interfaces.
         case GL_UNIFORM:
         case GL_UNIFORM_BLOCK:
         case GL_TRANSFORM_FEEDBACK_VARYING:
         case GL_BUFFER_VARIABLE:
         case GL_SHADER_STORAGE_BLOCK:
+        case GL_ATOMIC_COUNTER_BUFFER:
             UNIMPLEMENTED();
             return false;
 
@@ -953,4 +1143,61 @@
     return true;
 }
 
+bool ValidateGetProgramResourceiv(Context *context,
+                                  GLuint program,
+                                  GLenum programInterface,
+                                  GLuint index,
+                                  GLsizei propCount,
+                                  const GLenum *props,
+                                  GLsizei bufSize,
+                                  GLsizei *length,
+                                  GLint *params)
+{
+    if (context->getClientVersion() < ES_3_1)
+    {
+        context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
+        return false;
+    }
+
+    Program *programObject = GetValidProgram(context, program);
+    if (programObject == nullptr)
+    {
+        return false;
+    }
+    if (!ValidateProgramInterface(programInterface))
+    {
+        context->handleError(InvalidEnum() << "Invalid program interface.");
+        return false;
+    }
+    if (propCount <= 0)
+    {
+        context->handleError(InvalidValue() << "Invalid propCount.");
+        return false;
+    }
+    if (bufSize < 0)
+    {
+        context->handleError(InvalidValue() << "Invalid bufSize.");
+        return false;
+    }
+    if (!ValidateProgramResourceIndex(programObject, programInterface, index))
+    {
+        context->handleError(InvalidValue() << "Invalid index: " << index);
+        return false;
+    }
+    for (GLsizei i = 0; i < propCount; i++)
+    {
+        if (!ValidateProgramResourceProperty(props[i]))
+        {
+            context->handleError(InvalidEnum() << "Invalid prop.");
+            return false;
+        }
+        if (!ValidateProgramResourcePropertyByInterface(props[i], programInterface))
+        {
+            context->handleError(InvalidOperation() << "Not an allowed prop for interface");
+            return false;
+        }
+    }
+    return true;
+}
+
 }  // namespace gl