Pass varyings to the GLES API from the translator using a direct pointer.

Instead of parsing them indirectly from HLSL, the pointer will allow us to more flexibly
support new types, especially compound types such as structures.

TRAC #23754

Signed-off-by: Nicolas Capens
Signed-off-by: Shannon Woods

diff --git a/src/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
index aa32292..972d10a 100644
--- a/src/compiler/OutputHLSL.cpp
+++ b/src/compiler/OutputHLSL.cpp
@@ -205,6 +205,11 @@
     return mActiveAttributes;
 }
 
+const std::vector<Varying> &OutputHLSL::getVaryings() const
+{
+    return mActiveVaryings;
+}
+
 int OutputHLSL::vectorSize(const TType &type) const
 {
     int elementSize = type.isMatrix() ? type.getCols() : 1;
@@ -612,6 +617,8 @@
         // Program linking depends on this exact format
         varyings += "static " + interpolationString(type.getQualifier()) + " " + typeString(type) + " " +
                     decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+
+        declareVaryingToList(type, name, mActiveVaryings);
     }
 
     for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
@@ -3636,6 +3643,30 @@
     }
 }
 
+void OutputHLSL::declareVaryingToList(const TType &type, const TString &name, std::vector<Varying>& fieldsOut)
+{
+    const TStructure *structure = type.getStruct();
+
+    if (!structure)
+    {
+        Varying varying(glVariableType(type), glVariablePrecision(type), name.c_str(), (unsigned int)type.getArraySize());
+        fieldsOut.push_back(varying);
+    }
+    else
+    {
+        Varying structVarying(GL_NONE, GL_NONE, name.c_str(), (unsigned int)type.getArraySize());
+        const TFieldList &fields = structure->fields();
+
+        for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
+        {
+            const TField &field = *fields[fieldIndex];
+            declareVaryingToList(*field.type(), field.name(), structVarying.fields);
+        }
+
+        fieldsOut.push_back(structVarying);
+    }
+}
+
 void OutputHLSL::declareUniform(const TType &type, const TString &name, int index)
 {
     declareUniformToList(type, name, index, mActiveUniforms);
diff --git a/src/compiler/OutputHLSL.h b/src/compiler/OutputHLSL.h
index 2d32dbc..2adfbef 100644
--- a/src/compiler/OutputHLSL.h
+++ b/src/compiler/OutputHLSL.h
@@ -36,6 +36,7 @@
     const ActiveInterfaceBlocks &getInterfaceBlocks() const;
     const std::vector<Attribute> &getOutputVariables() const;
     const std::vector<Attribute> &getAttributes() const;
+    const std::vector<Varying> &getVaryings() const;
 
     TString typeString(const TType &type);
     TString textureString(const TType &type);
@@ -179,6 +180,7 @@
     void declareInterfaceBlockField(const TType &type, const TString &name, std::vector<InterfaceBlockField>& output);
     void declareUniformToList(const TType &type, const TString &name, int registerIndex, std::vector<Uniform>& output);
     void declareUniform(const TType &type, const TString &name, int index);
+    void declareVaryingToList(const TType &type, const TString &name, std::vector<Varying>& fieldsOut);
 
     TString interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, const TField &field);
     TString decoratePrivate(const TString &privateText);
@@ -202,6 +204,7 @@
     ActiveInterfaceBlocks mActiveInterfaceBlocks;
     std::vector<Attribute> mActiveOutputVariables;
     std::vector<Attribute> mActiveAttributes;
+    std::vector<Varying> mActiveVaryings;
     std::map<TString, int> mStd140StructElementIndexes;
     std::map<TIntermTyped*, TString> mFlaggedStructMappedNames;
     std::map<TIntermTyped*, TString> mFlaggedStructOriginalNames;
diff --git a/src/compiler/ShaderLang.cpp b/src/compiler/ShaderLang.cpp
index edfb3f8..77cb644 100644
--- a/src/compiler/ShaderLang.cpp
+++ b/src/compiler/ShaderLang.cpp
@@ -386,6 +386,9 @@
     case SH_ACTIVE_ATTRIBUTES_ARRAY:
         *params = (void*)&translator->getAttributes();
         break;
+    case SH_ACTIVE_VARYINGS_ARRAY:
+        *params = (void*)&translator->getVaryings();
+        break;
     default: UNREACHABLE();
     }
 }
diff --git a/src/compiler/TranslatorHLSL.cpp b/src/compiler/TranslatorHLSL.cpp
index 83468d4..6eea101 100644
--- a/src/compiler/TranslatorHLSL.cpp
+++ b/src/compiler/TranslatorHLSL.cpp
@@ -20,8 +20,10 @@
     sh::OutputHLSL outputHLSL(parseContext, getResources(), mOutputType);
 
     outputHLSL.output();
-    mActiveUniforms = outputHLSL.getUniforms();
-    mActiveInterfaceBlocks = outputHLSL.getInterfaceBlocks();
-    mActiveOutputVariables = outputHLSL.getOutputVariables();
-    mActiveAttributes = outputHLSL.getAttributes();
+
+    mActiveUniforms         = outputHLSL.getUniforms();
+    mActiveInterfaceBlocks  = outputHLSL.getInterfaceBlocks();
+    mActiveOutputVariables  = outputHLSL.getOutputVariables();
+    mActiveAttributes       = outputHLSL.getAttributes();
+    mActiveVaryings         = outputHLSL.getVaryings();
 }
diff --git a/src/compiler/TranslatorHLSL.h b/src/compiler/TranslatorHLSL.h
index e3c4d2e..b21f20e 100644
--- a/src/compiler/TranslatorHLSL.h
+++ b/src/compiler/TranslatorHLSL.h
@@ -19,6 +19,7 @@
     const sh::ActiveInterfaceBlocks &getInterfaceBlocks() const { return mActiveInterfaceBlocks; }
     const std::vector<sh::Attribute> &getOutputVariables() { return mActiveOutputVariables; }
     const std::vector<sh::Attribute> &getAttributes() { return mActiveAttributes; }
+    const std::vector<sh::Varying> &getVaryings() { return mActiveVaryings; }
 
 protected:
     virtual void translate(TIntermNode* root);
@@ -27,6 +28,7 @@
     sh::ActiveInterfaceBlocks mActiveInterfaceBlocks;
     std::vector<sh::Attribute> mActiveOutputVariables;
     std::vector<sh::Attribute> mActiveAttributes;
+    std::vector<sh::Varying> mActiveVaryings;
     ShShaderOutput mOutputType;
 };
 
diff --git a/src/compiler/Uniform.cpp b/src/compiler/Uniform.cpp
index 43a040e..f3a21ee 100644
--- a/src/compiler/Uniform.cpp
+++ b/src/compiler/Uniform.cpp
@@ -41,6 +41,11 @@
 {
 }
 
+Varying::Varying(GLenum typeIn, GLenum precisionIn, const char *nameIn, unsigned int arraySizeIn)
+    : ShaderVariable(typeIn, precisionIn, nameIn, arraySizeIn)
+{
+}
+
 BlockMemberInfo::BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix)
     : offset(offset),
       arrayStride(arrayStride),
diff --git a/src/compiler/Uniform.h b/src/compiler/Uniform.h
index d5275c0..1f88967 100644
--- a/src/compiler/Uniform.h
+++ b/src/compiler/Uniform.h
@@ -55,6 +55,15 @@
     bool isStruct() const { return !fields.empty(); }
 };
 
+struct Varying : public ShaderVariable
+{
+    std::vector<Varying> fields;
+
+    Varying(GLenum typeIn, GLenum precisionIn, const char *nameIn, unsigned int arraySizeIn);
+
+    bool isStruct() const { return !fields.empty(); }
+};
+
 struct BlockMemberInfo
 {
     BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix);