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/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
index 785e18d..4a8ad7f 100644
--- a/src/compiler/OutputHLSL.cpp
+++ b/src/compiler/OutputHLSL.cpp
@@ -50,6 +50,7 @@
sprintf(semantic, " : TEXCOORD%d", semanticIndex);
semanticIndex += type.isArray() ? type.getArraySize() : 1;
+ // Program linking depends on this exact format
varyingInput += " " + typeString(type) + " " + name + arrayString(type) + semantic + ";\n";
varyingGlobals += "static " + typeString(type) + " " + name + arrayString(type) + " = " + initializer(type) + ";\n";
}
@@ -74,7 +75,7 @@
"struct PS_INPUT\n" // FIXME: Prevent name clashes
"{\n";
out << varyingInput;
- out << " float4 gl_FragCoord : TEXCOORD" << HLSL_FRAG_COORD_SEMANTIC << ";\n";
+ out << " float4 gl_FragCoord : TEXCOORD" << semanticIndex << ";\n";
out << " float __vFace : VFACE;\n"
"};\n"
"\n";
@@ -147,6 +148,7 @@
}
else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
{
+ // Program linking depends on this exact format
varyingOutput += " " + typeString(type) + " " + name + arrayString(type) + " : TEXCOORD0;\n"; // Actual semantic index assigned during link
varyingGlobals += "static " + typeString(type) + " " + name + arrayString(type) + " = " + initializer(type) + ";\n";
}
@@ -177,7 +179,7 @@
"{\n"
" float4 gl_Position : POSITION;\n"
" float gl_PointSize : PSIZE;\n"
- " float4 gl_FragCoord : TEXCOORD" << HLSL_FRAG_COORD_SEMANTIC << ";\n";
+ " float4 gl_FragCoord : TEXCOORD0;\n"; // Actual semantic index assigned during link
out << varyingOutput;
out << "};\n"
"\n"
@@ -501,6 +503,7 @@
if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
{
+ // Program linking depends on this exact format
out << " output." + name + " = " + name + ";\n"; // FIXME: Prevent name clashes
}
}
diff --git a/src/compiler/OutputHLSL.h b/src/compiler/OutputHLSL.h
index 667d9e8..2be9a86 100644
--- a/src/compiler/OutputHLSL.h
+++ b/src/compiler/OutputHLSL.h
@@ -12,11 +12,6 @@
namespace sh
{
-enum
-{
- HLSL_FRAG_COORD_SEMANTIC = 15 // Semantic index assigned to the gl_FragCoord varying
-};
-
class OutputHLSL : public TIntermTraverser
{
public:
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;
}
diff --git a/src/libGLESv2/Program.h b/src/libGLESv2/Program.h
index 9502ca0..bf60515 100644
--- a/src/libGLESv2/Program.h
+++ b/src/libGLESv2/Program.h
@@ -83,7 +83,25 @@
ID3DXBuffer *compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable);
void unlink(bool destroy = false);
+ struct Varying
+ {
+ Varying(const std::string &name, char *declaration) : name(name), declaration(declaration)
+ {
+ link = -1;
+ }
+
+ int link;
+ std::string name;
+ char *declaration;
+ };
+
+ typedef std::vector<Varying> VaryingArray;
+
+ void parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings);
+ bool linkVaryings();
+
bool linkAttributes();
+
bool linkUniforms(ID3DXConstantTable *constantTable);
bool defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name = "");
bool defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name);
@@ -102,6 +120,9 @@
FragmentShader *mFragmentShader;
VertexShader *mVertexShader;
+ char *mPixelHLSL;
+ char *mVertexHLSL;
+
IDirect3DPixelShader9 *mPixelExecutable;
IDirect3DVertexShader9 *mVertexExecutable;
ID3DXConstantTable *mConstantTablePS;
diff --git a/src/libGLESv2/Shader.cpp b/src/libGLESv2/Shader.cpp
index 90ce10f..7144a8f 100644
--- a/src/libGLESv2/Shader.cpp
+++ b/src/libGLESv2/Shader.cpp
@@ -171,7 +171,7 @@
return mHlsl != NULL;
}
-const char *Shader::linkHLSL()
+const char *Shader::getHLSL()
{
return mHlsl;
}
@@ -306,45 +306,6 @@
parseAttributes();
}
-const char *VertexShader::linkHLSL(const char *pixelHLSL)
-{
- if (mHlsl && pixelHLSL)
- {
- const char *input = strstr(pixelHLSL, "struct PS_INPUT");
- char *output = strstr(mHlsl, "struct VS_OUTPUT");
-
- while (*input != '}' && output)
- {
- char varyingName[100];
- unsigned int semanticIndex;
- int matches = sscanf(input, "%s : TEXCOORD%d;", varyingName, &semanticIndex);
-
- if (matches == 2 && semanticIndex != sh::HLSL_FRAG_COORD_SEMANTIC)
- {
- ASSERT(semanticIndex < MAX_VARYING_VECTORS);
- char *varying = strstr(output, varyingName);
-
- if (varying)
- {
- ASSERT(semanticIndex <= 9); // Single character
- varying = strstr(varying, " : TEXCOORD0;");
- varying[11] = '0' + semanticIndex;
- }
- else
- {
- return NULL;
- }
-
- input = strstr(input, ";");
- }
-
- input++;
- }
- }
-
- return mHlsl;
-}
-
const char *VertexShader::getAttributeName(unsigned int attributeIndex)
{
if (attributeIndex < MAX_VERTEX_ATTRIBS)
diff --git a/src/libGLESv2/Shader.h b/src/libGLESv2/Shader.h
index 6bc9cf5..5f5a327 100644
--- a/src/libGLESv2/Shader.h
+++ b/src/libGLESv2/Shader.h
@@ -39,7 +39,7 @@
virtual void compile() = 0;
bool isCompiled();
- const char *linkHLSL();
+ const char *getHLSL();
void attach();
void detach();
@@ -90,7 +90,6 @@
GLenum getType();
void compile();
- const char *linkHLSL(const char *pixelHLSL);
const char *getAttributeName(unsigned int attributeIndex);
bool isActiveAttribute(const char *attributeName);
int getInputMapping(const char *attributeName);