Add support for struct varyings, and more robust varying link validation.
TRAC #23749
Signed-off-by: Geoff Lang
Signed-off-by: Nicolas Capens
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index 78db619..b0fef82 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -938,19 +938,21 @@
{
sh::Varying *varying = &fragmentShader->mVaryings[varyingIndex];
GLenum transposedType = TransposeMatrixType(varying->type);
- int n = VariableRowCount(transposedType) * varying->elementCount();
- int m = VariableColumnCount(transposedType);
+
+ // 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 (m == 2 || m == 3 || m == 4)
+ if (elements == 2 || elements == 3 || elements == 4)
{
- for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
+ for (int r = 0; r <= maxVaryingVectors - registers && !success; r++)
{
bool available = true;
- for (int y = 0; y < n && available; y++)
+ for (int y = 0; y < registers && available; y++)
{
- for (int x = 0; x < m && available; x++)
+ for (int x = 0; x < elements && available; x++)
{
if (packing[r + y][x])
{
@@ -964,9 +966,9 @@
varying->registerIndex = r;
varying->elementIndex = 0;
- for (int y = 0; y < n; y++)
+ for (int y = 0; y < registers; y++)
{
- for (int x = 0; x < m; x++)
+ for (int x = 0; x < elements; x++)
{
packing[r + y][x] = &*varying;
}
@@ -976,13 +978,13 @@
}
}
- if (!success && m == 2)
+ if (!success && elements == 2)
{
- for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
+ for (int r = maxVaryingVectors - registers; r >= 0 && !success; r--)
{
bool available = true;
- for (int y = 0; y < n && available; y++)
+ for (int y = 0; y < registers && available; y++)
{
for (int x = 2; x < 4 && available; x++)
{
@@ -998,7 +1000,7 @@
varying->registerIndex = r;
varying->elementIndex = 2;
- for (int y = 0; y < n; y++)
+ for (int y = 0; y < registers; y++)
{
for (int x = 2; x < 4; x++)
{
@@ -1011,7 +1013,7 @@
}
}
}
- else if (m == 1)
+ else if (elements == 1)
{
int space[4] = {0};
@@ -1027,13 +1029,13 @@
for (int x = 0; x < 4; x++)
{
- if (space[x] >= n && space[x] < space[column])
+ if (space[x] >= registers && space[x] < space[column])
{
column = x;
}
}
- if (space[column] >= n)
+ if (space[column] >= registers)
{
for (int r = 0; r < maxVaryingVectors; r++)
{
@@ -1041,7 +1043,7 @@
{
varying->registerIndex = r;
- for (int y = r; y < r + n; y++)
+ for (int y = r; y < r + registers; y++)
{
packing[y][column] = &*varying;
}
@@ -1154,10 +1156,8 @@
sh::Varying *output = &vertexShader->mVaryings[vertVaryingIndex];
if (output->name == input->name)
{
- if (output->type != input->type || output->arraySize != input->arraySize || output->interpolation != input->interpolation)
+ if (!linkValidateVariables(infoLog, output->name, *input, *output))
{
- infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
-
return false;
}
@@ -1308,7 +1308,7 @@
{
for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
{
- int variableRows = VariableRowCount(TransposeMatrixType(varying->type));
+ int variableRows = (varying->isStruct() ? 1 : VariableRowCount(TransposeMatrixType(varying->type)));
for (int row = 0; row < variableRows; row++)
{
@@ -1508,7 +1508,7 @@
for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
{
GLenum transposedType = TransposeMatrixType(varying->type);
- int variableRows = VariableRowCount(transposedType);
+ int variableRows = (varying->isStruct() ? 1 : VariableRowCount(transposedType));
for (int row = 0; row < variableRows; row++)
{
std::string n = str(varying->registerIndex + elementIndex * variableRows + row);
@@ -1524,13 +1524,20 @@
pixelHLSL += arrayString(row);
}
- switch (VariableColumnCount(transposedType))
+ if (varying->isStruct())
{
- 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();
+ 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();
+ }
}
}
}
@@ -1589,7 +1596,7 @@
for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
{
GLenum transposedType = TransposeMatrixType(varying->type);
- int variableRows = VariableRowCount(transposedType);
+ int variableRows = (varying->isStruct() ? 1 : VariableRowCount(transposedType));
for (int row = 0; row < variableRows; row++)
{
switch (varying->interpolation)
@@ -1601,7 +1608,10 @@
}
std::string n = str(varying->registerIndex + elementIndex * variableRows + row);
- std::string typeString = gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
+
+ // 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";
}
@@ -2153,7 +2163,7 @@
return true;
}
-bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, const sh::ShaderVariable &fragmentVariable)
+bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
{
if (vertexVariable.type != fragmentVariable.type)
{
@@ -2165,7 +2175,7 @@
infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
return false;
}
- if (vertexVariable.precision != fragmentVariable.precision)
+ if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
{
infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
return false;
@@ -2190,12 +2200,12 @@
if (vertexMember.name != fragmentMember.name)
{
- infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
- memberIndex, varName.c_str(), vertexVar.name.c_str(), fragmentVar.name.c_str());
+ infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
+ memberIndex, varName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
return false;
}
- const std::string memberName = varName + "." + vertexVar.name;
+ const std::string memberName = varName.substr(0, varName.length()-1) + "." + vertexVar.name + "'";
if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember))
{
return false;
@@ -2207,7 +2217,7 @@
bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
{
- if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform))
+ if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
{
return false;
}
@@ -2220,9 +2230,30 @@
return true;
}
+bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
+{
+ if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
+ {
+ return false;
+ }
+
+ if (vertexVarying.interpolation != fragmentVarying.interpolation)
+ {
+ infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
+ return false;
+ }
+
+ if (!linkValidateFields<sh::Varying>(infoLog, varyingName, vertexVarying, fragmentVarying))
+ {
+ return false;
+ }
+
+ return true;
+}
+
bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
{
- if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform))
+ if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
{
return false;
}
@@ -2260,7 +2291,7 @@
if (entry != linkedUniforms.end())
{
const sh::Uniform &vertexUniform = *entry->second;
- const std::string &uniformName = "uniform " + vertexUniform.name;
+ const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform))
{
return false;
@@ -2519,12 +2550,12 @@
if (vertexMember.name != fragmentMember.name)
{
- infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
+ infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
return false;
}
- std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
+ std::string uniformName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember))
{
return false;