Proper support for fragment output variables for GLSL ES shader version 300.

TRAC #22704

Signed-off-by: Geoff Lang
Signed-off-by: Nicolas Capens
Authored-by: Jamie Madill
diff --git a/src/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
index 95bbc29..b36d456 100644
--- a/src/compiler/OutputHLSL.cpp
+++ b/src/compiler/OutputHLSL.cpp
@@ -156,6 +156,11 @@
     return mActiveInterfaceBlocks;
 }
 
+const ActiveShaderVariables &OutputHLSL::getOutputVariables() const
+{
+    return mActiveOutputVariables;
+}
+
 int OutputHLSL::vectorSize(const TType &type) const
 {
     int elementSize = type.isMatrix() ? type.getCols() : 1;
@@ -391,23 +396,44 @@
         TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers");
         const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire));
 
-        const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
-
         out << "// Varyings\n";
         out <<  varyings;
-        out << "\n"
-               "static float4 gl_Color[" << numColorValues << "] =\n"
-               "{\n";
-        for (unsigned int i = 0; i < numColorValues; i++)
+        out << "\n";
+
+        if (mContext.getShaderVersion() >= 300)
         {
-            out << "    float4(0, 0, 0, 0)";
-            if (i + 1 != numColorValues)
+            for (auto outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
             {
-                out << ",";
+                const TString &variableName = outputVariableIt->first;
+                const TType &variableType = outputVariableIt->second->getType();
+                const TLayoutQualifier &layoutQualifier = variableType.getLayoutQualifier();
+
+                out << "static " + typeString(variableType) + " out_" + variableName + arrayString(variableType) +
+                       " = " + initializer(variableType) + ";\n";
+
+                ShaderVariable outputVar(glVariableType(variableType), glVariablePrecision(variableType), variableName.c_str(),
+                                         (unsigned int)variableType.getArraySize(), layoutQualifier.location);
+                mActiveOutputVariables.push_back(outputVar);
             }
-            out << "\n";
         }
-        out << "};\n";
+        else
+        {
+            const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
+
+            out << "static float4 gl_Color[" << numColorValues << "] =\n"
+                   "{\n";
+            for (unsigned int i = 0; i < numColorValues; i++)
+            {
+                out << "    float4(0, 0, 0, 0)";
+                if (i + 1 != numColorValues)
+                {
+                    out << ",";
+                }
+                out << "\n";
+            }
+
+            out << "};\n";
+        }
 
         if (mUsesFragCoord)
         {
@@ -1407,7 +1433,12 @@
             mReferencedVaryings[name] = node;
             out << decorate(name);
         }
-        else if (qualifier == EvqFragColor || qualifier == EvqFragmentOutput)
+        else if (qualifier == EvqFragmentOutput)
+        {
+            mReferencedOutputVariables[name] = node;
+            out << "out_" << name;
+        }
+        else if (qualifier == EvqFragColor)
         {
             out << "gl_Color[0]";
             mUsesFragColor = true;
diff --git a/src/compiler/OutputHLSL.h b/src/compiler/OutputHLSL.h
index 0e1ca71..c22ad4f 100644
--- a/src/compiler/OutputHLSL.h
+++ b/src/compiler/OutputHLSL.h
@@ -34,6 +34,7 @@
     TInfoSinkBase &getBodyStream();
     const ActiveUniforms &getUniforms();
     const ActiveInterfaceBlocks &getInterfaceBlocks() const;
+    const ActiveShaderVariables &getOutputVariables() const;
 
     TString typeString(const TType &type);
     TString textureString(const TType &type);
@@ -88,6 +89,7 @@
     ReferencedSymbols mReferencedInterfaceBlocks;
     ReferencedSymbols mReferencedAttributes;
     ReferencedSymbols mReferencedVaryings;
+    ReferencedSymbols mReferencedOutputVariables;
 
     // Parameters determining what goes in the header output
     bool mUsesTexture2D;
@@ -192,6 +194,7 @@
 
     ActiveUniforms mActiveUniforms;
     ActiveInterfaceBlocks mActiveInterfaceBlocks;
+    ActiveShaderVariables mActiveOutputVariables;
 };
 }
 
diff --git a/src/compiler/ParseHelper.cpp b/src/compiler/ParseHelper.cpp
index 31af70d..e49ae7c 100644
--- a/src/compiler/ParseHelper.cpp
+++ b/src/compiler/ParseHelper.cpp
@@ -2028,6 +2028,11 @@
                 error(location, "", "[", "array indexes for interface blocks arrays must be constant integeral expressions");
                 recover();
             }
+            else if (baseExpression->getQualifier() == EvqFragmentOutput)
+            {
+                error(location, "", "[", "array indexes for output variables must be constant integeral expressions");
+                recover();
+            }
 
             indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
         }
diff --git a/src/compiler/ShaderLang.cpp b/src/compiler/ShaderLang.cpp
index 7b3fa75..07313dd 100644
--- a/src/compiler/ShaderLang.cpp
+++ b/src/compiler/ShaderLang.cpp
@@ -379,6 +379,9 @@
     case SH_ACTIVE_INTERFACE_BLOCKS_ARRAY:
         *params = (void*)&translator->getInterfaceBlocks();
         break;
+    case SH_ACTIVE_OUTPUT_VARIABLES_ARRAY:
+        *params = (void*)&translator->getOutputVariables();
+        break;
     default: UNREACHABLE();
     }
 }
diff --git a/src/compiler/TranslatorHLSL.cpp b/src/compiler/TranslatorHLSL.cpp
index 0819424..6ef91f4 100644
--- a/src/compiler/TranslatorHLSL.cpp
+++ b/src/compiler/TranslatorHLSL.cpp
@@ -22,4 +22,5 @@
     outputHLSL.output();
     mActiveUniforms = outputHLSL.getUniforms();
     mActiveInterfaceBlocks = outputHLSL.getInterfaceBlocks();
+    mActiveOutputVariables = outputHLSL.getOutputVariables();
 }
diff --git a/src/compiler/TranslatorHLSL.h b/src/compiler/TranslatorHLSL.h
index 3cb8b90..c031446 100644
--- a/src/compiler/TranslatorHLSL.h
+++ b/src/compiler/TranslatorHLSL.h
@@ -17,12 +17,14 @@
     virtual TranslatorHLSL *getAsTranslatorHLSL() { return this; }
     const sh::ActiveUniforms &getUniforms() { return mActiveUniforms; }
     const sh::ActiveInterfaceBlocks &getInterfaceBlocks() const { return mActiveInterfaceBlocks; }
+    const sh::ActiveShaderVariables &getOutputVariables() { return mActiveOutputVariables; }
 
 protected:
     virtual void translate(TIntermNode* root);
 
     sh::ActiveUniforms mActiveUniforms;
     sh::ActiveInterfaceBlocks mActiveInterfaceBlocks;
+    sh::ActiveShaderVariables mActiveOutputVariables;
     ShShaderOutput mOutputType;
 };
 
diff --git a/src/compiler/Uniform.cpp b/src/compiler/Uniform.cpp
index 8a8b998..602eed5 100644
--- a/src/compiler/Uniform.cpp
+++ b/src/compiler/Uniform.cpp
@@ -11,6 +11,15 @@
 namespace sh
 {
 
+ShaderVariable::ShaderVariable(GLenum type, GLenum precision, const char *name, unsigned int arraySize, int location)
+    : type(type),
+      precision(precision),
+      name(name),
+      arraySize(arraySize),
+      location(location)
+{
+}
+
 Uniform::Uniform(GLenum type, GLenum precision, const char *name, unsigned int arraySize, unsigned int registerIndex)
 {
     this->type = type;
diff --git a/src/compiler/Uniform.h b/src/compiler/Uniform.h
index 22ace9f..e43533a 100644
--- a/src/compiler/Uniform.h
+++ b/src/compiler/Uniform.h
@@ -17,6 +17,19 @@
 namespace sh
 {
 
+struct ShaderVariable
+{
+    ShaderVariable(GLenum type, GLenum precision, const char *name, unsigned int arraySize, int location);
+
+    GLenum type;
+    GLenum precision;
+    std::string name;
+    unsigned int arraySize;
+    int location;
+};
+
+typedef std::vector<ShaderVariable> ActiveShaderVariables;
+
 struct Uniform
 {
     Uniform(GLenum type, GLenum precision, const char *name, unsigned int arraySize, unsigned int registerIndex);