Commit a55102c5 by Olli Etuaho Committed by Commit Bot

Unify and simplify shader variable collection

Instead of setting variable information in both CollectVariables and the GetVariableTraverser helper class it uses, keep all of this functionality in CollectVariables. A single helper function handles setting variable information that doesn't depend on variable type, and the rest is done in "record" functions that are implemented for each variable type. This removes templates from the code, making it leaner and easier to understand, and will help with implementing future features like adding binding and location layout qualifiers for uniforms. BUG=angleproject:1442 TEST=angle_unittests, angle_end2end_tests, dEQP-GLES2.functional.shaders.* Change-Id: I79148b7b3fa9cb46634a22bdcc9ce0c04f970384 Reviewed-on: https://chromium-review.googlesource.com/446838 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 7d670a33
......@@ -35,11 +35,15 @@ class CollectVariables : public TIntermTraverser
bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
private:
template <typename VarT>
void visitVariable(const TIntermSymbol *variable, std::vector<VarT> *infoList) const;
template <typename VarT>
void visitInfoList(const TIntermSequence &sequence, std::vector<VarT> *infoList) const;
void setCommonVariableProperties(const TType &type,
const TString &name,
ShaderVariable *variableOut) const;
Attribute recordAttribute(const TIntermSymbol &variable) const;
OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
Varying recordVarying(const TIntermSymbol &variable) const;
InterfaceBlock recordInterfaceBlock(const TIntermSymbol &variable) const;
Uniform recordUniform(const TIntermSymbol &variable) const;
std::vector<Attribute> *mAttribs;
std::vector<OutputVariable> *mOutputVariables;
......
......@@ -701,97 +701,6 @@ TOperator TypeToConstructorOperator(const TType &type)
return EOpNull;
}
GetVariableTraverser::GetVariableTraverser(const TSymbolTable &symbolTable)
: mSymbolTable(symbolTable)
{
}
template void GetVariableTraverser::setTypeSpecificInfo(const TType &type,
const TString &name,
InterfaceBlockField *variable);
template void GetVariableTraverser::setTypeSpecificInfo(const TType &type,
const TString &name,
ShaderVariable *variable);
template void GetVariableTraverser::setTypeSpecificInfo(const TType &type,
const TString &name,
Uniform *variable);
template <>
void GetVariableTraverser::setTypeSpecificInfo(const TType &type,
const TString &name,
Varying *variable)
{
ASSERT(variable);
switch (type.getQualifier())
{
case EvqVaryingIn:
case EvqVaryingOut:
case EvqVertexOut:
case EvqSmoothOut:
case EvqFlatOut:
case EvqCentroidOut:
if (mSymbolTable.isVaryingInvariant(std::string(name.c_str())) || type.isInvariant())
{
variable->isInvariant = true;
}
break;
default:
break;
}
variable->interpolation = GetInterpolationType(type.getQualifier());
}
template <typename VarT>
void GetVariableTraverser::traverse(const TType &type,
const TString &name,
std::vector<VarT> *output)
{
const TStructure *structure = type.getStruct();
VarT variable;
variable.name = name.c_str();
variable.arraySize = type.getArraySize();
if (!structure)
{
variable.type = GLVariableType(type);
variable.precision = GLVariablePrecision(type);
}
else
{
// Note: this enum value is not exposed outside ANGLE
variable.type = GL_STRUCT_ANGLEX;
variable.structName = structure->name().c_str();
const TFieldList &fields = structure->fields();
for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
{
TField *field = fields[fieldIndex];
traverse(*field->type(), field->name(), &variable.fields);
}
}
setTypeSpecificInfo(type, name, &variable);
visitVariable(&variable);
ASSERT(output);
output->push_back(variable);
}
template void GetVariableTraverser::traverse(const TType &,
const TString &,
std::vector<InterfaceBlockField> *);
template void GetVariableTraverser::traverse(const TType &,
const TString &,
std::vector<ShaderVariable> *);
template void GetVariableTraverser::traverse(const TType &,
const TString &,
std::vector<Uniform> *);
template void GetVariableTraverser::traverse(const TType &,
const TString &,
std::vector<Varying> *);
// GLSL ES 1.0.17 4.6.1 The Invariant Qualifier
bool CanBeInvariantESSL1(TQualifier qualifier)
{
......
......@@ -45,30 +45,6 @@ TType GetShaderVariableBasicType(const sh::ShaderVariable &var);
TOperator TypeToConstructorOperator(const TType &type);
class GetVariableTraverser : angle::NonCopyable
{
public:
GetVariableTraverser(const TSymbolTable &symbolTable);
virtual ~GetVariableTraverser() {}
template <typename VarT>
void traverse(const TType &type, const TString &name, std::vector<VarT> *output);
protected:
// May be overloaded
virtual void visitVariable(ShaderVariable *newVar) {}
private:
// Helper function called by traverse() to fill specific fields
// for attributes/varyings/uniforms.
template <typename VarT>
void setTypeSpecificInfo(const TType &type, const TString &name, VarT *variable)
{
}
const TSymbolTable &mSymbolTable;
};
bool IsBuiltinOutputVariable(TQualifier qualifier);
bool IsBuiltinFragmentInputVariable(TQualifier qualifier);
bool CanBeInvariantESSL1(TQualifier qualifier);
......
......@@ -740,3 +740,63 @@ TEST_F(CollectHashedVertexVariablesTest, StructUniform)
EXPECT_EQ("webgl_5", field.mappedName);
EXPECT_TRUE(field.fields.empty());
}
// Test a uniform declaration with multiple declarators.
TEST_F(CollectFragmentVariablesTest, MultiDeclaration)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 out_fragColor;\n"
"uniform float uA, uB;\n"
"void main()\n"
"{\n"
" vec4 color = vec4(uA, uA, uA, uB);\n"
" out_fragColor = color;\n"
"}\n";
compile(shaderString);
const auto &uniforms = mTranslator->getUniforms();
ASSERT_EQ(2u, uniforms.size());
const Uniform &uniform = uniforms[0];
EXPECT_EQ(0u, uniform.arraySize);
EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, uniform.precision);
EXPECT_TRUE(uniform.staticUse);
EXPECT_GLENUM_EQ(GL_FLOAT, uniform.type);
EXPECT_EQ("uA", uniform.name);
const Uniform &uniformB = uniforms[1];
EXPECT_EQ(0u, uniformB.arraySize);
EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, uniformB.precision);
EXPECT_TRUE(uniformB.staticUse);
EXPECT_GLENUM_EQ(GL_FLOAT, uniformB.type);
EXPECT_EQ("uB", uniformB.name);
}
// Test a uniform declaration starting with an empty declarator.
TEST_F(CollectFragmentVariablesTest, EmptyDeclarator)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 out_fragColor;\n"
"uniform float /* empty declarator */, uB;\n"
"void main()\n"
"{\n"
" out_fragColor = vec4(uB, uB, uB, uB);\n"
"}\n";
compile(shaderString);
const auto &uniforms = mTranslator->getUniforms();
ASSERT_EQ(1u, uniforms.size());
const Uniform &uniformB = uniforms[0];
EXPECT_EQ(0u, uniformB.arraySize);
EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, uniformB.precision);
EXPECT_TRUE(uniformB.staticUse);
EXPECT_GLENUM_EQ(GL_FLOAT, uniformB.type);
EXPECT_EQ("uB", uniformB.name);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment