ProgramD3D: Move some common code into a Metadata class.

This metadata class captures some of our commonly referenced but also
complex flats into a shared place. We can then re-use them in the
semantic code, the DynamicHLSL linking code, and the program code.

Refactoring patch only.

BUG=angleproject:1202

Change-Id: I8b6088cfa5488c5173a6f06c15abab5a4ead4cb8
Reviewed-on: https://chromium-review.googlesource.com/311700
Tryjob-Request: Jamie Madill <jmadill@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
index 0640407..8f5f006 100644
--- a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -444,14 +444,13 @@
 
 bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
                                          const gl::Program::Data &programData,
+                                         const ProgramD3DMetadata &programMetadata,
                                          InfoLog &infoLog,
                                          unsigned int registerCount,
                                          std::string *pixelHLSL,
                                          std::string *vertexHLSL,
                                          const std::vector<PackedVarying> &packedVaryings,
-                                         std::vector<D3DVarying> *d3dVaryingsOut,
-                                         std::vector<PixelShaderOutputVariable> *outPixelShaderKey,
-                                         bool *outUsesFragDepth) const
+                                         std::vector<D3DVarying> *d3dVaryingsOut) const
 {
     ASSERT(pixelHLSL->empty() && vertexHLSL->empty());
 
@@ -461,15 +460,12 @@
     const ShaderD3D *fragmentShader    = GetImplAs<ShaderD3D>(fragmentShaderGL);
     const int shaderModel              = mRenderer->getMajorShaderModel();
 
-    bool usesMRT        = fragmentShader->usesMultipleRenderTargets();
-    bool usesFragCoord  = fragmentShader->usesFragCoord();
+    bool usesFragCoord  = programMetadata.usesFragCoord();
     bool usesPointCoord = fragmentShader->usesPointCoord();
     bool usesPointSize = vertexShader->usesPointSize();
     bool useInstancedPointSpriteEmulation =
-        usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
-    bool insertDummyPointCoordValue = !usesPointSize && usesPointCoord && shaderModel >= 4;
-    bool addPointCoord =
-        (useInstancedPointSpriteEmulation && usesPointCoord) || insertDummyPointCoordValue;
+        programMetadata.usesPointSize() &&
+        mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
 
     // Validation done in the compiler
     ASSERT(!fragmentShader->usesFragColor() || !fragmentShader->usesFragData());
@@ -478,19 +474,6 @@
     const unsigned int registersNeeded =
         registerCount + (usesFragCoord ? 1u : 0u) + (usesPointCoord ? 1u : 0u);
 
-    // Two cases when writing to gl_FragColor and using ESSL 1.0:
-    // - with a 3.0 context, the output color is copied to channel 0
-    // - with a 2.0 context, the output color is broadcast to all channels
-    const bool broadcast                = (fragmentShader->usesFragColor() && data.clientVersion < 3);
-    const unsigned int numRenderTargets = (broadcast || usesMRT ? data.caps->maxDrawBuffers : 1);
-
-    // gl_Position only needs to be outputted from the vertex shader if transform feedback is
-    // active. This isn't supported on D3D11 Feature Level 9_3, so we don't output gl_Position from
-    // the vertex shader in this case. This saves us 1 output vector.
-    bool outputPositionFromVS = !(shaderModel >= 4 && mRenderer->getShaderModelSuffix() != "");
-
-    int shaderVersion = vertexShaderGL->getShaderVersion();
-
     if (static_cast<GLuint>(registersNeeded) > data.caps->maxVaryingVectors)
     {
         infoLog << "No varying registers left to support gl_FragCoord/gl_PointCoord";
@@ -504,9 +487,8 @@
     // PS_INPUT of the generated pixel shader. The Geometry Shader point sprite implementation needs
     // gl_PointSize to be in VS_OUTPUT and GS_INPUT. Instanced point sprites doesn't need
     // gl_PointSize in VS_OUTPUT.
-    const SemanticInfo &vertexSemantics = GetSemanticInfo(
-        SHADER_VERTEX, shaderModel, registerCount, outputPositionFromVS, usesFragCoord,
-        addPointCoord, (!useInstancedPointSpriteEmulation && usesPointSize));
+    const SemanticInfo &vertexSemantics =
+        GetSemanticInfo(SHADER_VERTEX, programMetadata, registerCount);
 
     storeUserVaryings(packedVaryings, usesPointSize, d3dVaryingsOut);
     storeBuiltinVaryings(vertexSemantics, d3dVaryingsOut);
@@ -545,7 +527,7 @@
                  << "\n"
                  << "    VS_OUTPUT output;\n";
 
-    if (outputPositionFromVS)
+    if (vertexSemantics.glPosition.enabled)
     {
         vertexStream << "    output.gl_Position = gl_Position;\n";
     }
@@ -614,7 +596,7 @@
                         "gl_PointSize / (dx_ViewCoords.y*2), input.spriteVertexPos.z) * "
                         "output.dx_Position.w;\n";
 
-        if (usesPointCoord)
+        if (programMetadata.usesPointCoord())
         {
             vertexStream << "\n"
                          << "    output.gl_PointCoord = input.spriteTexCoord;\n";
@@ -624,7 +606,7 @@
     // Renderers that enable instanced pointsprite emulation require the vertex shader output member
     // gl_PointCoord to be set to a default value if used without gl_PointSize. 0.5,0.5 is the same
     // default value used in the generated pixel shader.
-    if (insertDummyPointCoordValue)
+    if (programMetadata.usesInsertedPointCoordValue())
     {
         ASSERT(!useInstancedPointSpriteEmulation);
         vertexStream << "\n"
@@ -638,57 +620,13 @@
     std::stringstream pixelStream;
     pixelStream << fragmentShaderGL->getTranslatedSource();
 
-    const SemanticInfo &pixelSemantics = GetSemanticInfo(
-        SHADER_PIXEL, shaderModel, registerCount, outputPositionFromVS, usesFragCoord,
-        usesPointCoord, (!useInstancedPointSpriteEmulation && usesPointSize));
+    const SemanticInfo &pixelSemantics =
+        GetSemanticInfo(SHADER_PIXEL, programMetadata, registerCount);
 
     pixelStream << "struct PS_INPUT\n";
     generateVaryingLinkHLSL(*data.caps, usesPointSize, pixelSemantics, packedVaryings, pixelStream);
     pixelStream << "\n";
 
-    if (shaderVersion < 300)
-    {
-        for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets;
-             renderTargetIndex++)
-        {
-            PixelShaderOutputVariable outputKeyVariable;
-            outputKeyVariable.type = GL_FLOAT_VEC4;
-            outputKeyVariable.name = "gl_Color" + Str(renderTargetIndex);
-            outputKeyVariable.source =
-                broadcast ? "gl_Color[0]" : "gl_Color[" + Str(renderTargetIndex) + "]";
-            outputKeyVariable.outputIndex = renderTargetIndex;
-
-            outPixelShaderKey->push_back(outputKeyVariable);
-        }
-
-        *outUsesFragDepth = fragmentShader->usesFragDepth();
-    }
-    else
-    {
-        const auto &shaderOutputVars = fragmentShaderGL->getActiveOutputVariables();
-
-        for (auto outputPair : programData.getOutputVariables())
-        {
-            const VariableLocation &outputLocation   = outputPair.second;
-            const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index];
-            const std::string &variableName = "out_" + outputLocation.name;
-            const std::string &elementString =
-                (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element));
-
-            ASSERT(outputVariable.staticUse);
-
-            PixelShaderOutputVariable outputKeyVariable;
-            outputKeyVariable.type        = outputVariable.type;
-            outputKeyVariable.name        = variableName + elementString;
-            outputKeyVariable.source      = variableName + ArrayString(outputLocation.element);
-            outputKeyVariable.outputIndex = outputPair.first;
-
-            outPixelShaderKey->push_back(outputKeyVariable);
-        }
-
-        *outUsesFragDepth = false;
-    }
-
     pixelStream << PIXEL_OUTPUT_STUB_STRING + "\n";
 
     if (fragmentShader->usesFrontFacing())
@@ -830,6 +768,7 @@
 std::string DynamicHLSL::generateGeometryShaderPreamble(
     const gl::Data &data,
     const gl::Program::Data &programData,
+    const ProgramD3DMetadata &programMetadata,
     unsigned int registerCount,
     const std::vector<PackedVarying> &packedVaryings) const
 {
@@ -844,14 +783,12 @@
     ASSERT(vertexShader && fragmentShader);
 
     bool usesFragCoord  = fragmentShader->usesFragCoord();
-    bool usesPointCoord = fragmentShader->usesPointCoord();
     bool usesPointSize  = vertexShader->usesPointSize();
 
-    const SemanticInfo &inSemantics = GetSemanticInfo(
-        SHADER_VERTEX, majorShaderModel, registerCount, true, usesFragCoord, false, usesPointSize);
+    const SemanticInfo &inSemantics =
+        GetSemanticInfo(SHADER_VERTEX, programMetadata, registerCount);
     const SemanticInfo &outSemantics =
-        GetSemanticInfo(SHADER_GEOMETRY, majorShaderModel, registerCount, true, usesFragCoord,
-                        usesPointCoord, usesPointSize);
+        GetSemanticInfo(SHADER_GEOMETRY, programMetadata, registerCount);
 
     std::stringstream preambleStream;
 
@@ -1085,4 +1022,58 @@
     // No conversion necessary
     return attribString;
 }
+
+void DynamicHLSL::getPixelShaderOutputKey(const gl::Data &data,
+                                          const gl::Program::Data &programData,
+                                          const ProgramD3DMetadata &metadata,
+                                          std::vector<PixelShaderOutputVariable> *outPixelShaderKey)
+{
+    // Two cases when writing to gl_FragColor and using ESSL 1.0:
+    // - with a 3.0 context, the output color is copied to channel 0
+    // - with a 2.0 context, the output color is broadcast to all channels
+    bool broadcast = metadata.usesBroadcast(data);
+    const unsigned int numRenderTargets =
+        (broadcast || metadata.usesMultipleFragmentOuts() ? data.caps->maxDrawBuffers : 1);
+
+    if (metadata.getMajorShaderVersion() < 300)
+    {
+        for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets;
+             renderTargetIndex++)
+        {
+            PixelShaderOutputVariable outputKeyVariable;
+            outputKeyVariable.type = GL_FLOAT_VEC4;
+            outputKeyVariable.name = "gl_Color" + Str(renderTargetIndex);
+            outputKeyVariable.source =
+                broadcast ? "gl_Color[0]" : "gl_Color[" + Str(renderTargetIndex) + "]";
+            outputKeyVariable.outputIndex = renderTargetIndex;
+
+            outPixelShaderKey->push_back(outputKeyVariable);
+        }
+    }
+    else
+    {
+        const auto &shaderOutputVars =
+            metadata.getFragmentShader()->getData().getActiveOutputVariables();
+
+        for (auto outputPair : programData.getOutputVariables())
+        {
+            const VariableLocation &outputLocation   = outputPair.second;
+            const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index];
+            const std::string &variableName = "out_" + outputLocation.name;
+            const std::string &elementString =
+                (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element));
+
+            ASSERT(outputVariable.staticUse);
+
+            PixelShaderOutputVariable outputKeyVariable;
+            outputKeyVariable.type        = outputVariable.type;
+            outputKeyVariable.name        = variableName + elementString;
+            outputKeyVariable.source      = variableName + ArrayString(outputLocation.element);
+            outputKeyVariable.outputIndex = outputPair.first;
+
+            outPixelShaderKey->push_back(outputKeyVariable);
+        }
+    }
+}
+
 }  // namespace rx