Move TF Feedback linked varyings into D3D-only.

The LinkedVarying structure is a D3D-specific type, and the GL
back-end doesn't need the extra info. Isolate this into the D3D
back-end so we can clean up the Impl inteface.

BUG=angleproject:1123

Change-Id: I76d77ac505876d865e3e02f47acbfd6665a9507e
Reviewed-on: https://chromium-review.googlesource.com/293764
Tested-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 969f35b..f470818 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -144,7 +144,6 @@
 Program::Data::Data()
     : mAttachedFragmentShader(nullptr),
       mAttachedVertexShader(nullptr),
-      mTransformFeedbackVaryings(),
       mTransformFeedbackBufferMode(GL_NONE)
 {
 }
@@ -305,22 +304,22 @@
         return Error(GL_NO_ERROR);
     }
 
+    const auto &mergedVaryings = getMergedVaryings();
+
+    if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, *data.caps))
+    {
+        return Error(GL_NO_ERROR);
+    }
+
     int registers;
-    std::vector<LinkedVarying> linkedVaryings;
     rx::LinkResult result =
         mProgram->link(data, mInfoLog, mData.mAttachedFragmentShader, mData.mAttachedVertexShader,
-                       &registers, &linkedVaryings, &mOutputVariables);
+                       &registers, &mOutputVariables);
     if (result.error.isError() || !result.linkSuccess)
     {
         return result.error;
     }
 
-    if (!gatherTransformFeedbackLinkedVaryings(
-            mInfoLog, linkedVaryings, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps))
-    {
-        return Error(GL_NO_ERROR);
-    }
-
     // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
     // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
     result = mProgram->compileProgramExecutables(mInfoLog, registers);
@@ -331,6 +330,8 @@
         return result.error;
     }
 
+    gatherTransformFeedbackVaryings(mergedVaryings);
+
     mLinked = true;
     return gl::Error(GL_NO_ERROR);
 }
@@ -367,7 +368,7 @@
     }
 
     mLinkedAttributes.assign(mLinkedAttributes.size(), sh::Attribute());
-    mOutputVariables.clear();
+    mData.mTransformFeedbackVaryingVars.clear();
 
     mProgram->reset();
 
@@ -1170,10 +1171,10 @@
 
 void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
 {
-    mData.mTransformFeedbackVaryings.resize(count);
+    mData.mTransformFeedbackVaryingNames.resize(count);
     for (GLsizei i = 0; i < count; i++)
     {
-        mData.mTransformFeedbackVaryings[i] = varyings[i];
+        mData.mTransformFeedbackVaryingNames[i] = varyings[i];
     }
 
     mData.mTransformFeedbackBufferMode = bufferMode;
@@ -1183,8 +1184,8 @@
 {
     if (mLinked)
     {
-        ASSERT(index < mProgram->getTransformFeedbackLinkedVaryings().size());
-        const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[index];
+        ASSERT(index < mData.mTransformFeedbackVaryingVars.size());
+        const sh::Varying &varying = mData.mTransformFeedbackVaryingVars[index];
         GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
         if (length)
         {
@@ -1192,7 +1193,7 @@
         }
         if (size)
         {
-            *size = varying.size;
+            *size = varying.elementCount();
         }
         if (type)
         {
@@ -1210,7 +1211,7 @@
 {
     if (mLinked)
     {
-        return static_cast<GLsizei>(mProgram->getTransformFeedbackLinkedVaryings().size());
+        return static_cast<GLsizei>(mData.mTransformFeedbackVaryingVars.size());
     }
     else
     {
@@ -1223,9 +1224,8 @@
     if (mLinked)
     {
         GLsizei maxSize = 0;
-        for (size_t i = 0; i < mProgram->getTransformFeedbackLinkedVaryings().size(); i++)
+        for (const sh::Varying &varying : mData.mTransformFeedbackVaryingVars)
         {
-            const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[i];
             maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
         }
 
@@ -1625,45 +1625,41 @@
     return true;
 }
 
-bool Program::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
-                                                    std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
-                                                    const Caps &caps) const
+bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
+                                            const std::vector<const sh::Varying *> &varyings,
+                                            const Caps &caps) const
 {
     size_t totalComponents = 0;
 
-    // Gather the linked varyings that are used for transform feedback, they should all exist.
-    outTransformFeedbackLinkedVaryings->clear();
-    for (size_t i = 0; i < mData.mTransformFeedbackVaryings.size(); i++)
+    std::set<std::string> uniqueNames;
+
+    for (const std::string &tfVaryingName : mData.mTransformFeedbackVaryingNames)
     {
         bool found = false;
-        for (size_t j = 0; j < linkedVaryings.size(); j++)
+        for (const sh::Varying *varying : varyings)
         {
-            if (mData.mTransformFeedbackVaryings[i] == linkedVaryings[j].name)
+            if (tfVaryingName == varying->name)
             {
-                for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
+                if (uniqueNames.count(tfVaryingName) > 0)
                 {
-                    if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
-                    {
-                        infoLog << "Two transform feedback varyings specify the same output variable ("
-                                << linkedVaryings[j].name << ").";
-                        return false;
-                    }
+                    infoLog << "Two transform feedback varyings specify the same output variable ("
+                            << tfVaryingName << ").";
+                    return false;
                 }
+                uniqueNames.insert(tfVaryingName);
 
-                size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
+                // TODO(jmadill): Investigate implementation limits on D3D11
+                size_t componentCount = gl::VariableComponentCount(varying->type);
                 if (mData.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
                     componentCount > caps.maxTransformFeedbackSeparateComponents)
                 {
-                    infoLog << "Transform feedback varying's " << linkedVaryings[j].name
-                            << " components (" << componentCount
-                            << ") exceed the maximum separate components ("
+                    infoLog << "Transform feedback varying's " << varying->name << " components ("
+                            << componentCount << ") exceed the maximum separate components ("
                             << caps.maxTransformFeedbackSeparateComponents << ").";
                     return false;
                 }
 
                 totalComponents += componentCount;
-
-                outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
                 found = true;
                 break;
             }
@@ -1686,4 +1682,46 @@
     return true;
 }
 
+void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings)
+{
+    // Gather the linked varyings that are used for transform feedback, they should all exist.
+    mData.mTransformFeedbackVaryingVars.clear();
+    for (const std::string &tfVaryingName : mData.mTransformFeedbackVaryingNames)
+    {
+        for (const sh::Varying *varying : varyings)
+        {
+            if (tfVaryingName == varying->name)
+            {
+                mData.mTransformFeedbackVaryingVars.push_back(*varying);
+                break;
+            }
+        }
+    }
+}
+
+std::vector<const sh::Varying *> Program::getMergedVaryings() const
+{
+    std::set<std::string> uniqueNames;
+    std::vector<const sh::Varying *> varyings;
+
+    for (const sh::Varying &varying : mData.mAttachedVertexShader->getVaryings())
+    {
+        if (uniqueNames.count(varying.name) == 0)
+        {
+            uniqueNames.insert(varying.name);
+            varyings.push_back(&varying);
+        }
+    }
+
+    for (const sh::Varying &varying : mData.mAttachedFragmentShader->getVaryings())
+    {
+        if (uniqueNames.count(varying.name) == 0)
+        {
+            uniqueNames.insert(varying.name);
+            varyings.push_back(&varying);
+        }
+    }
+
+    return varyings;
+}
 }