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/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index c424acd..4dd1de1 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -41,6 +41,11 @@
     return "[" + str(i) + "]";
 }
 
+std::string arrayString(unsigned int i)
+{
+    return (i == GL_INVALID_INDEX ? "" : "[" + str(i) + "]");
+}
+
 namespace gl_d3d
 {
     std::string TypeString(GLenum type)
@@ -1055,6 +1060,32 @@
     return registers;
 }
 
+void ProgramBinary::defineOutputVariables(FragmentShader *fragmentShader)
+{
+    const sh::ActiveShaderVariables &outputVars = fragmentShader->getOutputVariables();
+
+    for (unsigned int outputVariableIndex = 0; outputVariableIndex < outputVars.size(); outputVariableIndex++)
+    {
+        const sh::ShaderVariable &outputVariable = outputVars[outputVariableIndex];
+        const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location;
+
+        if (outputVariable.arraySize > 0)
+        {
+            for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++)
+            {
+                const int location = baseLocation + elementIndex;
+                ASSERT(mOutputVariables.count(location) == 0);
+                mOutputVariables[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex);
+            }
+        }
+        else
+        {
+            ASSERT(mOutputVariables.count(baseLocation) == 0);
+            mOutputVariables[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex);
+        }
+    }
+}
+
 bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
                                  std::string& pixelHLSL, std::string& vertexHLSL,
                                  FragmentShader *fragmentShader, VertexShader *vertexShader)
@@ -1355,9 +1386,28 @@
                  "struct PS_OUTPUT\n"
                  "{\n";
 
-    for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
+    if (mShaderVersion < 300)
     {
-        pixelHLSL += "    float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
+        for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
+        {
+            pixelHLSL += "    float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
+        }
+    }
+    else
+    {
+        defineOutputVariables(fragmentShader);
+
+        const sh::ActiveShaderVariables &outputVars = fragmentShader->getOutputVariables();
+        for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
+        {
+            const VariableLocation &outputLocation = locationIt->second;
+            const sh::ShaderVariable &outputVariable = outputVars[outputLocation.index];
+            const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
+
+            pixelHLSL += "    " + gl_d3d::TypeString(outputVariable.type) +
+                         " out_" + outputLocation.name + elementString +
+                         " : " + targetSemantic + str(locationIt->first) + ";\n";
+        }
     }
 
     pixelHLSL += "};\n"
@@ -1473,11 +1523,26 @@
                  "\n"
                  "    PS_OUTPUT output;\n";
 
-    for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
+    if (mShaderVersion < 300)
     {
-        unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
+        for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
+        {
+            unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
 
-        pixelHLSL += "    output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
+            pixelHLSL += "    output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
+        }
+    }
+    else
+    {
+        for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
+        {
+            const VariableLocation &outputLocation = locationIt->second;
+            const std::string &variableName = "out_" + outputLocation.name;
+            const std::string &outVariableName = variableName + (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
+            const std::string &staticVariableName = variableName + arrayString(outputLocation.element);
+
+            pixelHLSL += "    output." + outVariableName + " = " + staticVariableName + ";\n";
+        }
     }
 
     pixelHLSL += "\n"