Compiler - implement proper varying linking
TRAC #11716
Signed-off-by: Shannon Woods
Signed-off-by: Daniel Koch

Author:    Nicolas Capens

git-svn-id: https://angleproject.googlecode.com/svn/trunk@97 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Program.cpp b/src/libGLESv2/Program.cpp
index 3030ac1..252c5a4 100644
--- a/src/libGLESv2/Program.cpp
+++ b/src/libGLESv2/Program.cpp
@@ -41,6 +41,8 @@
         mAttributeName[index] = NULL;
     }
 
+    mPixelHLSL = NULL;
+    mVertexHLSL = NULL;
     mInfoLog = NULL;
 
     unlink();
@@ -398,6 +400,92 @@
     return NULL;
 }
 
+void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
+{
+    char *input = strstr(hlsl, structure);
+    input += strlen(structure);
+
+    while (input && *input != '}')
+    {
+        char varyingType[256];
+        char varyingName[256];
+        unsigned int semanticIndex;
+        int matches = sscanf(input, "    %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
+
+        if (matches == 3)
+        {
+            ASSERT(semanticIndex <= 9);   // Single character
+
+            varyings.push_back(Varying(varyingName, input));
+        }
+
+        input = strstr(input, ";");
+        input += 2;
+    }
+}
+
+bool Program::linkVaryings()
+{
+    if (!mPixelHLSL || !mVertexHLSL)
+    {
+        return false;
+    }
+
+    VaryingArray vertexVaryings;
+    VaryingArray pixelVaryings;
+
+    parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
+    parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
+
+    for (unsigned int out = 0; out < vertexVaryings.size(); out++)
+    {
+        unsigned int in;
+        for (in = 0; in < pixelVaryings.size(); in++)
+        {
+            if (vertexVaryings[out].name == pixelVaryings[in].name)
+            {
+                pixelVaryings[in].link = out;
+                vertexVaryings[out].link = in;
+
+                break;
+            }
+        }
+
+        if (in != pixelVaryings.size())
+        {
+            // FIXME: Verify matching type and qualifiers
+
+            char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
+            char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
+            outputSemantic[11] = inputSemantic[11];
+        }
+        else
+        {
+            // Comment out the declaration and output assignment
+            vertexVaryings[out].declaration[0] = '/';
+            vertexVaryings[out].declaration[1] = '/';
+
+            char outputString[256];
+            sprintf(outputString, "    output.%s = ", vertexVaryings[out].name.c_str());
+            char *varyingOutput = strstr(mVertexHLSL, outputString);
+
+            varyingOutput[0] = '/';
+            varyingOutput[1] = '/';
+        }
+    }
+
+    // Verify that each pixel varying has been linked to a vertex varying
+    for (unsigned int in = 0; in < pixelVaryings.size(); in++)
+    {
+        if (pixelVaryings[in].link < 0)
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 // Links the HLSL code of the vertex and pixel shader by matching up their varyings,
 // compiling them into binaries, determining the attribute mappings, and collecting
 // a list of uniforms
@@ -410,9 +498,6 @@
 
     unlink();
 
-    delete[] mInfoLog;
-    mInfoLog = NULL;
-
     if (!mFragmentShader || !mFragmentShader->isCompiled())
     {
         return;
@@ -427,10 +512,21 @@
     const char *vertexProfile = context->getVertexShaderProfile();
     const char *pixelProfile = context->getPixelShaderProfile();
 
-    const char *pixelHLSL = mFragmentShader->linkHLSL();
-    const char *vertexHLSL = mVertexShader->linkHLSL(pixelHLSL);
-    ID3DXBuffer *vertexBinary = compileToBinary(vertexHLSL, vertexProfile, &mConstantTableVS);
-    ID3DXBuffer *pixelBinary = compileToBinary(pixelHLSL, pixelProfile, &mConstantTablePS);
+    const char *ps = mFragmentShader->getHLSL();
+    const char *vs = mVertexShader->getHLSL();
+
+    mPixelHLSL = new char[strlen(ps) + 1];
+    strcpy(mPixelHLSL, ps);
+    mVertexHLSL = new char[strlen(vs) + 1];
+    strcpy(mVertexHLSL, vs);
+
+    if (!linkVaryings())
+    {
+        return;
+    }
+
+    ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
+    ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
 
     if (vertexBinary && pixelBinary)
     {
@@ -968,9 +1064,6 @@
             delete[] mAttributeName[index];
             mAttributeName[index] = NULL;
         }
-
-        delete[] mInfoLog;
-        mInfoLog = NULL;
     }
 
     if (mPixelExecutable)
@@ -1013,6 +1106,15 @@
         mUniforms.pop_back();
     }
 
+    delete[] mPixelHLSL;
+    mPixelHLSL = NULL;
+
+    delete[] mVertexHLSL;
+    mVertexHLSL = NULL;
+
+    delete[] mInfoLog;
+    mInfoLog = NULL;
+
     mLinked = false;
 }