Moved all HLSL-related code from ProgramBinary to DynamicHLSL.

DynamicHLSL encapsulates all HLSL generation we need outside the
the shader translator, such as for linking between input and output
stages and point sprite geometry shaders.

BUG=angle:560
Change-Id: Ib5079aa102000a7c37b166bcbe26b09cc82f8932
Reviewed-on: https://chromium-review.googlesource.com/185191
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index e98487e..a3e600b 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -23,62 +23,13 @@
 #include "libGLESv2/renderer/VertexDataManager.h"
 #include "libGLESv2/Context.h"
 #include "libGLESv2/Buffer.h"
-
-#include "compiler/translator/HLSLLayoutEncoder.h"
+#include "libGLESv2/DynamicHLSL.h"
 
 #undef near
 #undef far
 
 namespace gl
 {
-std::string str(int i)
-{
-    char buffer[20];
-    snprintf(buffer, sizeof(buffer), "%d", i);
-    return buffer;
-}
-
-std::string arrayString(int i)
-{
-    return "[" + str(i) + "]";
-}
-
-std::string arrayString(unsigned int i)
-{
-    return (i == GL_INVALID_INDEX ? "" : "[" + str(i) + "]");
-}
-
-namespace gl_d3d
-{
-    std::string TypeString(GLenum type)
-    {
-        switch (type)
-        {
-          case GL_FLOAT:        return "float";
-          case GL_FLOAT_VEC2:   return "float2";
-          case GL_FLOAT_VEC3:   return "float3";
-          case GL_FLOAT_VEC4:   return "float4";
-          case GL_INT:          return "int";
-          case GL_INT_VEC2:     return "int2";
-          case GL_INT_VEC3:     return "int3";
-          case GL_INT_VEC4:     return "int4";
-          case GL_UNSIGNED_INT: return "uint";
-          case GL_UNSIGNED_INT_VEC2: return "uint2";
-          case GL_UNSIGNED_INT_VEC3: return "uint3";
-          case GL_UNSIGNED_INT_VEC4: return "uint4";
-          case GL_FLOAT_MAT2:   return "float2x2";
-          case GL_FLOAT_MAT3:   return "float3x3";
-          case GL_FLOAT_MAT4:   return "float4x4";
-          case GL_FLOAT_MAT2x3: return "float2x3";
-          case GL_FLOAT_MAT3x2: return "float3x2";
-          case GL_FLOAT_MAT2x4: return "float2x4";
-          case GL_FLOAT_MAT4x2: return "float4x2";
-          case GL_FLOAT_MAT3x4: return "float3x4";
-          case GL_FLOAT_MAT4x3: return "float4x3";
-          default:  UNREACHABLE(); return "invalid-gl-type";
-        }
-    }
-}
 
 namespace 
 {
@@ -99,11 +50,6 @@
     return subscript;
 }
 
-static rx::D3DWorkaroundType DiscardWorkaround(bool usesDiscard)
-{
-    return (usesDiscard ? rx::ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER : rx::ANGLE_D3D_WORKAROUND_NONE);
-}
-
 }
 
 VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) 
@@ -116,6 +62,7 @@
 ProgramBinary::ProgramBinary(rx::Renderer *renderer)
     : RefCountObject(0),
       mRenderer(renderer),
+      mDynamicHLSL(NULL),
       mPixelExecutable(NULL),
       mVertexExecutable(NULL),
       mGeometryExecutable(NULL),
@@ -142,6 +89,8 @@
     {
         mSamplersVS[index].active = false;
     }
+
+    mDynamicHLSL = new DynamicHLSL(renderer);
 }
 
 ProgramBinary::~ProgramBinary()
@@ -164,6 +113,7 @@
 
     SafeDelete(mVertexUniformStorage);
     SafeDelete(mFragmentUniformStorage);
+    SafeDelete(mDynamicHLSL);
 }
 
 unsigned int ProgramBinary::getSerial() const
@@ -936,234 +886,21 @@
     return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
 }
 
-// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
-// Returns the number of used varying registers, or -1 if unsuccesful
-int ProgramBinary::packVaryings(InfoLog &infoLog, const sh::ShaderVariable *packing[][4], FragmentShader *fragmentShader)
+bool ProgramBinary::linkVaryings(InfoLog &infoLog, FragmentShader *fragmentShader, VertexShader *vertexShader)
 {
-    const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
-
-    fragmentShader->resetVaryingsRegisterAssignment();
-
-    for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
-    {
-        sh::Varying *varying = &fragmentShader->mVaryings[varyingIndex];
-        GLenum transposedType = TransposeMatrixType(varying->type);
-
-        // matrices within varying structs are not transposed
-        int registers = (varying->isStruct() ? sh::HLSLVariableRegisterCount(*varying) : gl::VariableRowCount(transposedType)) * varying->elementCount();
-        int elements = (varying->isStruct() ? 4 : VariableColumnCount(transposedType));
-        bool success = false;
-
-        if (elements == 2 || elements == 3 || elements == 4)
-        {
-            for (int r = 0; r <= maxVaryingVectors - registers && !success; r++)
-            {
-                bool available = true;
-
-                for (int y = 0; y < registers && available; y++)
-                {
-                    for (int x = 0; x < elements && available; x++)
-                    {
-                        if (packing[r + y][x])
-                        {
-                            available = false;
-                        }
-                    }
-                }
-
-                if (available)
-                {
-                    varying->registerIndex = r;
-                    varying->elementIndex = 0;
-
-                    for (int y = 0; y < registers; y++)
-                    {
-                        for (int x = 0; x < elements; x++)
-                        {
-                            packing[r + y][x] = &*varying;
-                        }
-                    }
-
-                    success = true;
-                }
-            }
-
-            if (!success && elements == 2)
-            {
-                for (int r = maxVaryingVectors - registers; r >= 0 && !success; r--)
-                {
-                    bool available = true;
-
-                    for (int y = 0; y < registers && available; y++)
-                    {
-                        for (int x = 2; x < 4 && available; x++)
-                        {
-                            if (packing[r + y][x])
-                            {
-                                available = false;
-                            }
-                        }
-                    }
-
-                    if (available)
-                    {
-                        varying->registerIndex = r;
-                        varying->elementIndex = 2;
-
-                        for (int y = 0; y < registers; y++)
-                        {
-                            for (int x = 2; x < 4; x++)
-                            {
-                                packing[r + y][x] = &*varying;
-                            }
-                        }
-
-                        success = true;
-                    }
-                }
-            }
-        }
-        else if (elements == 1)
-        {
-            int space[4] = {0};
-
-            for (int y = 0; y < maxVaryingVectors; y++)
-            {
-                for (int x = 0; x < 4; x++)
-                {
-                    space[x] += packing[y][x] ? 0 : 1;
-                }
-            }
-
-            int column = 0;
-
-            for (int x = 0; x < 4; x++)
-            {
-                if (space[x] >= registers && space[x] < space[column])
-                {
-                    column = x;
-                }
-            }
-
-            if (space[column] >= registers)
-            {
-                for (int r = 0; r < maxVaryingVectors; r++)
-                {
-                    if (!packing[r][column])
-                    {
-                        varying->registerIndex = r;
-
-                        for (int y = r; y < r + registers; y++)
-                        {
-                            packing[y][column] = &*varying;
-                        }
-
-                        break;
-                    }
-                }
-
-                varying->elementIndex = column;
-
-                success = true;
-            }
-        }
-        else UNREACHABLE();
-
-        if (!success)
-        {
-            infoLog.append("Could not pack varying %s", varying->name.c_str());
-
-            return -1;
-        }
-    }
-
-    // Return the number of used registers
-    int registers = 0;
-
-    for (int r = 0; r < maxVaryingVectors; r++)
-    {
-        if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
-        {
-            registers++;
-        }
-    }
-
-    return registers;
-}
-
-void ProgramBinary::defineOutputVariables(FragmentShader *fragmentShader)
-{
-    const std::vector<sh::Attribute> &outputVars = fragmentShader->getOutputVariables();
-
-    for (unsigned int outputVariableIndex = 0; outputVariableIndex < outputVars.size(); outputVariableIndex++)
-    {
-        const sh::Attribute &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 sh::ShaderVariable *packing[][4],
-                                 std::string& pixelHLSL, std::string& vertexHLSL,
-                                 FragmentShader *fragmentShader, VertexShader *vertexShader)
-{
-    if (pixelHLSL.empty() || vertexHLSL.empty())
-    {
-        return false;
-    }
-
-    bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
-    bool usesFragColor = fragmentShader->mUsesFragColor;
-    bool usesFragData = fragmentShader->mUsesFragData;
-    if (usesFragColor && usesFragData)
-    {
-        infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
-        return false;
-    }
-
-    // Write the HLSL input/output declarations
-    const int shaderModel = mRenderer->getMajorShaderModel();
-    const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
-
-    const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
-
-    // 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->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
-    const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
-
-    if (registersNeeded > maxVaryingVectors)
-    {
-        infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
-
-        return false;
-    }
-
     vertexShader->resetVaryingsRegisterAssignment();
 
-    for (unsigned int fragVaryingIndex = 0; fragVaryingIndex < fragmentShader->mVaryings.size(); fragVaryingIndex++)
+    std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
+    std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
+
+    for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
     {
-        sh::Varying *input = &fragmentShader->mVaryings[fragVaryingIndex];
+        sh::Varying *input = &fragmentVaryings[fragVaryingIndex];
         bool matched = false;
 
-        for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexShader->mVaryings.size(); vertVaryingIndex++)
+        for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
         {
-            sh::Varying *output = &vertexShader->mVaryings[vertVaryingIndex];
+            sh::Varying *output = &vertexVaryings[vertVaryingIndex];
             if (output->name == input->name)
             {
                 if (!linkValidateVariables(infoLog, output->name, *input, *output))
@@ -1182,457 +919,13 @@
         if (!matched)
         {
             infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
-
             return false;
         }
     }
 
-    mUsesPointSize = vertexShader->mUsesPointSize;
-    std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
-    std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
-    std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
-    std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
-
-    std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
-
-    // special varyings that use reserved registers
-    int reservedRegisterIndex = registers;
-    std::string fragCoordSemantic;
-    std::string pointCoordSemantic;
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
-    }
-
-    if (fragmentShader->mUsesPointCoord)
-    {
-        // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
-        // In DX11 we compute this in the GS.
-        if (shaderModel == 3)
-        {
-            pointCoordSemantic = "TEXCOORD0";
-        }
-        else if (shaderModel >= 4)
-        {
-            pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); 
-        }
-    }
-
-    vertexHLSL += "struct VS_INPUT\n"
-                  "{\n";
-
-    int semanticIndex = 0;
-    const std::vector<sh::Attribute> &activeAttributes = vertexShader->mActiveAttributes;
-    for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
-    {
-        const sh::Attribute &attribute = activeAttributes[attributeIndex];
-        vertexHLSL += "    " + gl_d3d::TypeString(TransposeMatrixType(attribute.type)) + " ";
-        vertexHLSL += decorateAttribute(attribute.name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
-
-        semanticIndex += AttributeRegisterCount(attribute.type);
-    }
-
-    vertexHLSL += "};\n"
-                  "\n"
-                  "struct VS_OUTPUT\n"
-                  "{\n";
-
-    if (shaderModel < 4)
-    {
-        vertexHLSL += "    float4 gl_Position : " + positionSemantic + ";\n";
-    }
-
-    vertexHLSL += varyingHLSL;
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        vertexHLSL += "    float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
-    }
-
-    if (vertexShader->mUsesPointSize && shaderModel >= 3)
-    {
-        vertexHLSL += "    float gl_PointSize : PSIZE;\n";
-    }
-
-    if (shaderModel >= 4)
-    {
-        vertexHLSL += "    float4 gl_Position : " + positionSemantic + ";\n";
-    }
-
-    vertexHLSL += "};\n"
-                  "\n"
-                  "VS_OUTPUT main(VS_INPUT input)\n"
-                  "{\n";
-
-    for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
-    {
-        const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
-        vertexHLSL += "    " + decorateAttribute(attribute.name) + " = ";
-
-        if (IsMatrixType(attribute.type))   // Matrix
-        {
-            vertexHLSL += "transpose";
-        }
-
-        vertexHLSL += "(input." + decorateAttribute(attribute.name) + ");\n";
-    }
-
-    if (shaderModel >= 4)
-    {
-        vertexHLSL += "\n"
-                      "    gl_main();\n"
-                      "\n"
-                      "    VS_OUTPUT output;\n"
-                      "    output.gl_Position.x = gl_Position.x;\n"
-                      "    output.gl_Position.y = -gl_Position.y;\n"
-                      "    output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
-                      "    output.gl_Position.w = gl_Position.w;\n";
-    }
-    else
-    {
-        vertexHLSL += "\n"
-                      "    gl_main();\n"
-                      "\n"
-                      "    VS_OUTPUT output;\n"
-                      "    output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
-                      "    output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"
-                      "    output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
-                      "    output.gl_Position.w = gl_Position.w;\n";
-    }
-
-    if (vertexShader->mUsesPointSize && shaderModel >= 3)
-    {
-        vertexHLSL += "    output.gl_PointSize = gl_PointSize;\n";
-    }
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        vertexHLSL += "    output.gl_FragCoord = gl_Position;\n";
-    }
-
-    for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexShader->mVaryings.size(); vertVaryingIndex++)
-    {
-        sh::Varying *varying = &vertexShader->mVaryings[vertVaryingIndex];
-        if (varying->registerAssigned())
-        {
-            for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
-            {
-                int variableRows = (varying->isStruct() ? 1 : VariableRowCount(TransposeMatrixType(varying->type)));
-
-                for (int row = 0; row < variableRows; row++)
-                {
-                    int r = varying->registerIndex + elementIndex * variableRows + row;
-                    vertexHLSL += "    output.v" + str(r);
-
-                    bool sharedRegister = false;   // Register used by multiple varyings
-                    
-                    for (int x = 0; x < 4; x++)
-                    {
-                        if (packing[r][x] && packing[r][x] != packing[r][0])
-                        {
-                            sharedRegister = true;
-                            break;
-                        }
-                    }
-
-                    if(sharedRegister)
-                    {
-                        vertexHLSL += ".";
-
-                        for (int x = 0; x < 4; x++)
-                        {
-                            if (packing[r][x] == &*varying)
-                            {
-                                switch(x)
-                                {
-                                  case 0: vertexHLSL += "x"; break;
-                                  case 1: vertexHLSL += "y"; break;
-                                  case 2: vertexHLSL += "z"; break;
-                                  case 3: vertexHLSL += "w"; break;
-                                }
-                            }
-                        }
-                    }
-
-                    vertexHLSL += " = _" + varying->name;
-                    
-                    if (varying->isArray())
-                    {
-                        vertexHLSL += arrayString(elementIndex);
-                    }
-
-                    if (variableRows > 1)
-                    {
-                        vertexHLSL += arrayString(row);
-                    }
-                    
-                    vertexHLSL += ";\n";
-                }
-            }
-        }
-    }
-
-    vertexHLSL += "\n"
-                  "    return output;\n"
-                  "}\n";
-
-    pixelHLSL += "struct PS_INPUT\n"
-                 "{\n";
-    
-    pixelHLSL += varyingHLSL;
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        pixelHLSL += "    float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
-    }
-        
-    if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
-    {
-        pixelHLSL += "    float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
-    }
-
-    // Must consume the PSIZE element if the geometry shader is not active
-    // We won't know if we use a GS until we draw
-    if (vertexShader->mUsesPointSize && shaderModel >= 4)
-    {
-        pixelHLSL += "    float gl_PointSize : PSIZE;\n";
-    }
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        if (shaderModel >= 4)
-        {
-            pixelHLSL += "    float4 dx_VPos : SV_Position;\n";
-        }
-        else if (shaderModel >= 3)
-        {
-            pixelHLSL += "    float2 dx_VPos : VPOS;\n";
-        }
-    }
-
-    pixelHLSL += "};\n"
-                 "\n"
-                 "struct PS_OUTPUT\n"
-                 "{\n";
-
-    if (mShaderVersion < 300)
-    {
-        for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
-        {
-            pixelHLSL += "    float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
-        }
-
-        if (fragmentShader->mUsesFragDepth)
-        {
-            pixelHLSL += "    float gl_Depth : " + depthSemantic + ";\n";
-        }
-    }
-    else
-    {
-        defineOutputVariables(fragmentShader);
-
-        const std::vector<sh::Attribute> &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"
-                 "\n";
-
-    if (fragmentShader->mUsesFrontFacing)
-    {
-        if (shaderModel >= 4)
-        {
-            pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
-                         "{\n";
-        }
-        else
-        {
-            pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
-                         "{\n";
-        }
-    }
-    else
-    {
-        pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
-                     "{\n";
-    }
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        pixelHLSL += "    float rhw = 1.0 / input.gl_FragCoord.w;\n";
-        
-        if (shaderModel >= 4)
-        {
-            pixelHLSL += "    gl_FragCoord.x = input.dx_VPos.x;\n"
-                         "    gl_FragCoord.y = input.dx_VPos.y;\n";
-        }
-        else if (shaderModel >= 3)
-        {
-            pixelHLSL += "    gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
-                         "    gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
-        }
-        else
-        {
-            // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
-            pixelHLSL += "    gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
-                         "    gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
-        }
-        
-        pixelHLSL += "    gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
-                     "    gl_FragCoord.w = rhw;\n";
-    }
-
-    if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
-    {
-        pixelHLSL += "    gl_PointCoord.x = input.gl_PointCoord.x;\n";
-        pixelHLSL += "    gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
-    }
-
-    if (fragmentShader->mUsesFrontFacing)
-    {
-        if (shaderModel <= 3)
-        {
-            pixelHLSL += "    gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
-        }
-        else
-        {
-            pixelHLSL += "    gl_FrontFacing = isFrontFace;\n";
-        }
-    }
-
-    for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
-    {
-        sh::Varying *varying = &fragmentShader->mVaryings[varyingIndex];
-        if (varying->registerAssigned())
-        {
-            for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
-            {
-                GLenum transposedType = TransposeMatrixType(varying->type);
-                int variableRows = (varying->isStruct() ? 1 : VariableRowCount(transposedType));
-                for (int row = 0; row < variableRows; row++)
-                {
-                    std::string n = str(varying->registerIndex + elementIndex * variableRows + row);
-                    pixelHLSL += "    _" + varying->name;
-
-                    if (varying->isArray())
-                    {
-                        pixelHLSL += arrayString(elementIndex);
-                    }
-
-                    if (variableRows > 1)
-                    {
-                        pixelHLSL += arrayString(row);
-                    }
-
-                    if (varying->isStruct())
-                    {
-                        pixelHLSL += " = input.v" + n + ";\n";   break;
-                    }
-                    else
-                    {
-                        switch (VariableColumnCount(transposedType))
-                        {
-                          case 1: pixelHLSL += " = input.v" + n + ".x;\n";   break;
-                          case 2: pixelHLSL += " = input.v" + n + ".xy;\n";  break;
-                          case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
-                          case 4: pixelHLSL += " = input.v" + n + ";\n";     break;
-                          default: UNREACHABLE();
-                        }
-                    }
-                }
-            }
-        }
-        else UNREACHABLE();
-    }
-
-    pixelHLSL += "\n"
-                 "    gl_main();\n"
-                 "\n"
-                 "    PS_OUTPUT output;\n";
-
-    if (mShaderVersion < 300)
-    {
-        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";
-        }
-
-        if (fragmentShader->mUsesFragDepth)
-        {
-            pixelHLSL += "    output.gl_Depth = gl_Depth;\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"
-                 "    return output;\n"
-                 "}\n";
-
     return true;
 }
 
-std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
-{
-    std::string varyingHLSL;
-
-    for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
-    {
-        sh::Varying *varying = &fragmentShader->mVaryings[varyingIndex];
-        if (varying->registerAssigned())
-        {
-            for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
-            {
-                GLenum transposedType = TransposeMatrixType(varying->type);
-                int variableRows = (varying->isStruct() ? 1 : VariableRowCount(transposedType));
-                for (int row = 0; row < variableRows; row++)
-                {
-                    switch (varying->interpolation)
-                    {
-                      case sh::INTERPOLATION_SMOOTH:   varyingHLSL += "    ";                 break;
-                      case sh::INTERPOLATION_FLAT:     varyingHLSL += "    nointerpolation "; break;
-                      case sh::INTERPOLATION_CENTROID: varyingHLSL += "    centroid ";        break;
-                      default:  UNREACHABLE();
-                    }
-
-                    std::string n = str(varying->registerIndex + elementIndex * variableRows + row);
-
-                    // matrices within structs are not transposed, hence we do not use the special struct prefix "rm"
-                    std::string typeString = varying->isStruct() ? "_" + varying->structName :
-                                             gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
-
-                    varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
-                }
-            }
-        }
-        else UNREACHABLE();
-    }
-
-    return varyingHLSL;
-}
-
 bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
 {
     BinaryInputStream stream(binary, length);
@@ -2045,14 +1338,20 @@
 
     // Map the varyings to the register file
     const sh::ShaderVariable *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
-    int registers = packVaryings(infoLog, packing, fragmentShader);
+    int registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShader);
 
     if (registers < 0)
     {
         return false;
     }
 
-    if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
+    if (!linkVaryings(infoLog, fragmentShader, vertexShader))
+    {
+        return false;
+    }
+
+    mUsesPointSize = vertexShader->usesPointSize();
+    if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader, &mOutputVariables))
     {
         return false;
     }
@@ -2070,7 +1369,7 @@
     }
 
     // special case for gl_DepthRange, the only built-in uniform (also a struct)
-    if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
+    if (vertexShader->usesDepthRange() || fragmentShader->usesDepthRange())
     {
         mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
         mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
@@ -2084,12 +1383,12 @@
 
     if (success)
     {
-        mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX, DiscardWorkaround(vertexShader->mUsesDiscardRewriting));
-        mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL, DiscardWorkaround(fragmentShader->mUsesDiscardRewriting));
+        mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX, vertexShader->getD3DWorkarounds());
+        mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL, vertexShader->getD3DWorkarounds());
 
         if (usesGeometryShader())
         {
-            std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
+            std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
             mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY, rx::ANGLE_D3D_WORKAROUND_NONE);
         }
 
@@ -2114,7 +1413,7 @@
 bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
 {
     unsigned int usedLocations = 0;
-    const std::vector<sh::Attribute> &activeAttributes = vertexShader->mActiveAttributes;
+    const std::vector<sh::Attribute> &activeAttributes = vertexShader->activeAttributes();
 
     // Link attributes that have a binding location
     for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
@@ -2414,12 +1713,11 @@
                 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
                 {
                     const sh::Uniform &field = constant.fields[fieldIndex];
-                    const std::string &uniformName = constant.name + arrayString(elementIndex) + "." + field.name;
+                    const std::string &uniformName = constant.name + ArrayString(elementIndex) + "." + field.name;
                     sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
                                              elementRegisterIndex, field.elementIndex);
 
                     fieldUniform.fields = field.fields;
-
                     if (!defineUniform(shader, fieldUniform, infoLog))
                     {
                         return false;
@@ -2659,7 +1957,7 @@
             {
                 for (unsigned int arrayElement = 0; arrayElement < field.arraySize; arrayElement++)
                 {
-                    const std::string uniformElementName = fieldName + arrayString(arrayElement);
+                    const std::string uniformElementName = fieldName + ArrayString(arrayElement);
                     defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
                 }
             }
@@ -2760,146 +2058,6 @@
     return true;
 }
 
-std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const sh::ShaderVariable *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
-{
-    // for now we only handle point sprite emulation
-    ASSERT(usesPointSpriteEmulation());
-    return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
-}
-
-std::string ProgramBinary::generatePointSpriteHLSL(int registers, const sh::ShaderVariable *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
-{
-    ASSERT(registers >= 0);
-    ASSERT(vertexShader->mUsesPointSize);
-    ASSERT(mRenderer->getMajorShaderModel() >= 4);
-
-    std::string geomHLSL;
-
-    std::string varyingSemantic = "TEXCOORD";
-
-    std::string fragCoordSemantic;
-    std::string pointCoordSemantic;
-
-    int reservedRegisterIndex = registers;
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
-    }
-
-    if (fragmentShader->mUsesPointCoord)
-    {
-        pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
-    }
-
-    geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
-                "\n"
-                "struct GS_INPUT\n"
-                "{\n";
-
-    std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
-
-    geomHLSL += varyingHLSL;
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        geomHLSL += "    float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
-    }
-
-    geomHLSL += "    float gl_PointSize : PSIZE;\n"
-                "    float4 gl_Position : SV_Position;\n"
-                "};\n"
-                "\n"
-                "struct GS_OUTPUT\n"
-                "{\n";
-
-    geomHLSL += varyingHLSL;
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        geomHLSL += "    float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
-    }
-
-    if (fragmentShader->mUsesPointCoord)
-    {
-        geomHLSL += "    float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
-    }
-
-    geomHLSL +=   "    float gl_PointSize : PSIZE;\n"
-                  "    float4 gl_Position : SV_Position;\n"
-                  "};\n"
-                  "\n"
-                  "static float2 pointSpriteCorners[] = \n"
-                  "{\n"
-                  "    float2( 0.5f, -0.5f),\n"
-                  "    float2( 0.5f,  0.5f),\n"
-                  "    float2(-0.5f, -0.5f),\n"
-                  "    float2(-0.5f,  0.5f)\n"
-                  "};\n"
-                  "\n"
-                  "static float2 pointSpriteTexcoords[] = \n"
-                  "{\n"
-                  "    float2(1.0f, 1.0f),\n"
-                  "    float2(1.0f, 0.0f),\n"
-                  "    float2(0.0f, 1.0f),\n"
-                  "    float2(0.0f, 0.0f)\n"
-                  "};\n"
-                  "\n"
-                  "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
-                  "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
-                  "\n"
-                  "[maxvertexcount(4)]\n"
-                  "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
-                  "{\n"
-                  "    GS_OUTPUT output = (GS_OUTPUT)0;\n"
-                  "    output.gl_PointSize = input[0].gl_PointSize;\n";
-
-    for (int r = 0; r < registers; r++)
-    {
-        geomHLSL += "    output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
-    }
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        geomHLSL += "    output.gl_FragCoord = input[0].gl_FragCoord;\n";
-    }
-
-    geomHLSL += "    \n"
-                "    float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
-                "    float4 gl_Position = input[0].gl_Position;\n"
-                "    float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * gl_Position.w;\n";
-
-    for (int corner = 0; corner < 4; corner++)
-    {
-        geomHLSL += "    \n"
-                    "    output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
-
-        if (fragmentShader->mUsesPointCoord)
-        {
-            geomHLSL += "    output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
-        }
-
-        geomHLSL += "    outStream.Append(output);\n";
-    }
-
-    geomHLSL += "    \n"
-                "    outStream.RestartStrip();\n"
-                "}\n";
-
-    return geomHLSL;
-}
-
-// This method needs to match OutputHLSL::decorate
-std::string ProgramBinary::decorateAttribute(const std::string &name)
-{
-    if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
-    {
-        return "_" + name;
-    }
-    
-    return name;
-}
-
 bool ProgramBinary::isValidated() const 
 {
     return mValidated;
@@ -3061,7 +2219,7 @@
 
         if (uniformBlock.isArrayElement())
         {
-            string += arrayString(uniformBlock.elementIndex);
+            string += ArrayString(uniformBlock.elementIndex);
         }
 
         strncpy(uniformBlockName, string.c_str(), bufSize);