Fix validation of statically referenced varyings.
Varyings and in/out variables that are passed between shader pipeline
stages are verified to have matching types at link-time, even when only
statically referenced (this includes trivially optimized out branches)
or even just declared.
GLSL ES 3.00 - 4.3.10 Linking of Vertex Outputs and Fragment Inputs
Change-Id: I122b1cdcc4630c86a8ebfb4d4e37f3a7a335afbe
Reviewed-on: https://swiftshader-review.googlesource.com/16070
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/compiler/OutputASM.cpp b/src/OpenGL/compiler/OutputASM.cpp
index 8edd099..6afc880 100644
--- a/src/OpenGL/compiler/OutputASM.cpp
+++ b/src/OpenGL/compiler/OutputASM.cpp
@@ -661,14 +661,23 @@
void OutputASM::visitSymbol(TIntermSymbol *symbol)
{
- // Vertex varyings don't have to be actively used to successfully link
- // against pixel shaders that use them. So make sure they're declared.
- if(symbol->getQualifier() == EvqVaryingOut || symbol->getQualifier() == EvqInvariantVaryingOut || symbol->getQualifier() == EvqVertexOut)
+ // The type of vertex outputs and fragment inputs with the same name must match (validated at link time),
+ // so declare them but don't assign a register index yet (one will be assigned when referenced in reachable code).
+ switch(symbol->getQualifier())
{
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqInvariantVaryingIn:
+ case EvqInvariantVaryingOut:
+ case EvqVertexOut:
+ case EvqFragmentIn:
if(symbol->getBasicType() != EbtInvariant) // Typeless declarations are not new varyings
{
declareVarying(symbol, -1);
}
+ break;
+ default:
+ break;
}
TInterfaceBlock* block = symbol->getType().getInterfaceBlock();
diff --git a/src/OpenGL/compiler/SymbolTable.h b/src/OpenGL/compiler/SymbolTable.h
index 3bc7ff4..3466f2f 100644
--- a/src/OpenGL/compiler/SymbolTable.h
+++ b/src/OpenGL/compiler/SymbolTable.h
@@ -208,10 +208,10 @@
bool insert(TSymbol *symbol);
- // Insert a function using its unmangled name as the key.
- bool insertUnmangled(TFunction *function);
+ // Insert a function using its unmangled name as the key.
+ bool insertUnmangled(TFunction *function);
- TSymbol *find(const TString &name) const;
+ TSymbol *find(const TString &name) const;
static int nextUniqueId()
{
diff --git a/src/OpenGL/libGLESv2/Program.cpp b/src/OpenGL/libGLESv2/Program.cpp
index 42cf1b3..0d43096 100644
--- a/src/OpenGL/libGLESv2/Program.cpp
+++ b/src/OpenGL/libGLESv2/Program.cpp
@@ -1349,9 +1349,13 @@
if(!matched)
{
- appendToInfoLog("Fragment varying %s does not match any vertex varying", input.name.c_str());
+ // If a fragment varying is declared but not statically used, it's not an error to not have a matching vertex varying.
+ if(input.registerIndex >= 0)
+ {
+ appendToInfoLog("Fragment varying %s does not match any vertex varying", input.name.c_str());
- return false;
+ return false;
+ }
}
}