ES31: Add glGetProgramResourceIndex 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

Change-Id: Ib2dedded9fd79b315e9f38de7c27a5e4ec4c6066
Reviewed-on: https://chromium-review.googlesource.com/453085
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 4770a8d..396d8c6 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -132,6 +132,33 @@
     return gl::CompareShaderVar(*x.varying, *y.varying);
 }
 
+template <typename VarT>
+GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
+{
+    size_t subscript     = GL_INVALID_INDEX;
+    std::string baseName = ParseResourceName(name, &subscript);
+
+    // The app is not allowed to specify array indices other than 0 for arrays of basic types
+    if (subscript != 0 && subscript != GL_INVALID_INDEX)
+    {
+        return GL_INVALID_INDEX;
+    }
+
+    for (size_t index = 0; index < list.size(); index++)
+    {
+        const VarT &resource = list[index];
+        if (resource.name == baseName)
+        {
+            if (resource.isArray() || subscript == GL_INVALID_INDEX)
+            {
+                return static_cast<GLuint>(index);
+            }
+        }
+    }
+
+    return GL_INVALID_INDEX;
+}
+
 }  // anonymous namespace
 
 const char *const g_fakepath = "C:\\fakepath";
@@ -255,7 +282,7 @@
 GLint ProgramState::getUniformLocation(const std::string &name) const
 {
     size_t subscript     = GL_INVALID_INDEX;
-    std::string baseName = ParseUniformName(name, &subscript);
+    std::string baseName = ParseResourceName(name, &subscript);
 
     for (size_t location = 0; location < mUniformLocations.size(); ++location)
     {
@@ -292,28 +319,7 @@
 
 GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
 {
-    size_t subscript     = GL_INVALID_INDEX;
-    std::string baseName = ParseUniformName(name, &subscript);
-
-    // The app is not allowed to specify array indices other than 0 for arrays of basic types
-    if (subscript != 0 && subscript != GL_INVALID_INDEX)
-    {
-        return GL_INVALID_INDEX;
-    }
-
-    for (size_t index = 0; index < mUniforms.size(); index++)
-    {
-        const LinkedUniform &uniform = mUniforms[index];
-        if (uniform.name == baseName)
-        {
-            if (uniform.isArray() || subscript == GL_INVALID_INDEX)
-            {
-                return static_cast<GLuint>(index);
-            }
-        }
-    }
-
-    return GL_INVALID_INDEX;
+    return GetResourceIndexFromName(mUniforms, name);
 }
 
 GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
@@ -487,7 +493,7 @@
 void Program::bindUniformLocation(GLuint index, const char *name)
 {
     // Bind the base uniform name only since array indices other than 0 cannot be bound
-    mUniformLocationBindings.bindLocation(index, ParseUniformName(name, nullptr));
+    mUniformLocationBindings.bindLocation(index, ParseResourceName(name, nullptr));
 }
 
 void Program::bindFragmentInputLocation(GLint index, const char *name)
@@ -720,6 +726,7 @@
     mState.mUniformLocations.clear();
     mState.mUniformBlocks.clear();
     mState.mOutputVariables.clear();
+    mState.mOutputLocations.clear();
     mState.mComputeShaderLocalSize.fill(1);
     mState.mSamplerBindings.clear();
 
@@ -865,6 +872,16 @@
 
     stream.readInt(&mState.mTransformFeedbackBufferMode);
 
+    unsigned int outputCount = stream.readInt<unsigned int>();
+    ASSERT(mState.mOutputVariables.empty());
+    for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
+    {
+        sh::OutputVariable output;
+        LoadShaderVar(&stream, &output);
+        output.location = stream.readInt<int>();
+        mState.mOutputVariables.push_back(output);
+    }
+
     unsigned int outputVarCount = stream.readInt<unsigned int>();
     for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
     {
@@ -873,7 +890,7 @@
         stream.readInt(&locationData.element);
         stream.readInt(&locationData.index);
         stream.readString(&locationData.name);
-        mState.mOutputVariables[locationIndex] = locationData;
+        mState.mOutputLocations[locationIndex] = locationData;
     }
 
     stream.readInt(&mState.mSamplerUniformRange.start);
@@ -991,7 +1008,14 @@
     stream.writeInt(mState.mTransformFeedbackBufferMode);
 
     stream.writeInt(mState.mOutputVariables.size());
-    for (const auto &outputPair : mState.mOutputVariables)
+    for (const sh::OutputVariable &output : mState.mOutputVariables)
+    {
+        WriteShaderVar(&stream, output);
+        stream.writeInt(output.location);
+    }
+
+    stream.writeInt(mState.mOutputLocations.size());
+    for (const auto &outputPair : mState.mOutputLocations)
     {
         stream.writeInt(outputPair.first);
         stream.writeIntOrNegOne(outputPair.second.element);
@@ -1222,11 +1246,29 @@
     return static_cast<GLint>(maxLength);
 }
 
+GLuint Program::getInputResourceIndex(const GLchar *name) const
+{
+    for (GLuint attributeIndex = 0; attributeIndex < mState.mAttributes.size(); ++attributeIndex)
+    {
+        const sh::Attribute &attribute = mState.mAttributes[attributeIndex];
+        if (attribute.name == name)
+        {
+            return attributeIndex;
+        }
+    }
+    return GL_INVALID_INDEX;
+}
+
+GLuint Program::getOutputResourceIndex(const GLchar *name) const
+{
+    return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
+}
+
 GLint Program::getFragDataLocation(const std::string &name) const
 {
     std::string baseName(name);
     unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
-    for (auto outputPair : mState.mOutputVariables)
+    for (auto outputPair : mState.mOutputLocations)
     {
         const VariableLocation &outputVariable = outputPair.second;
         if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
@@ -1679,7 +1721,7 @@
 GLuint Program::getUniformBlockIndex(const std::string &name) const
 {
     size_t subscript     = GL_INVALID_INDEX;
-    std::string baseName = ParseUniformName(name, &subscript);
+    std::string baseName = ParseResourceName(name, &subscript);
 
     unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
     for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
@@ -2505,14 +2547,13 @@
     if (fragmentShader->getShaderVersion() == 100)
         return;
 
-    const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
-
+    mState.mOutputVariables = fragmentShader->getActiveOutputVariables();
     // TODO(jmadill): any caps validation here?
 
-    for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
+    for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
          outputVariableIndex++)
     {
-        const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
+        const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
 
         // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
         if (outputVariable.isBuiltIn())
@@ -2525,9 +2566,9 @@
              elementIndex++)
         {
             const int location = baseLocation + elementIndex;
-            ASSERT(mState.mOutputVariables.count(location) == 0);
+            ASSERT(mState.mOutputLocations.count(location) == 0);
             unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
-            mState.mOutputVariables[location] =
+            mState.mOutputLocations[location] =
                 VariableLocation(outputVariable.name, element, outputVariableIndex);
         }
     }