Commit 55e79e09 by Jamie Madill

Implement equality ops for nested structs.

This fixes the WebGL test glsl_misc_struct_equals as well as several dEQP tests in functional.shaders.struct. BUG=391957 BUG=angle:910 Change-Id: I09f3cd3f51bbc3541b64dbcfddfe01884ddba6f5 Reviewed-on: https://chromium-review.googlesource.com/247083Tested-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent b2a5e342
......@@ -326,6 +326,15 @@ void OutputHLSL::header(const BuiltInFunctionEmulatorHLSL *builtInFunctionEmulat
out << mUniformHLSL->uniformsHeader(mOutputType, mReferencedUniforms);
out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks);
if (!mStructEqualityFunctions.empty())
{
out << "\n// Structure equality functions\n\n";
for (const auto &eqFunction : mStructEqualityFunctions)
{
out << eqFunction.functionDefinition << "\n";
}
}
if (mUsesDiscardRewriting)
{
out << "#define ANGLE_USES_DISCARD_REWRITING\n";
......@@ -1533,50 +1542,23 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
outputTriplet(visit, "(", " != ", ")");
}
}
else if (node->getLeft()->getBasicType() == EbtStruct)
else
{
if (node->getOp() == EOpEqual)
if (visit == PreVisit && node->getOp() == EOpNotEqual)
{
out << "(";
}
else
{
out << "!(";
}
const TStructure &structure = *node->getLeft()->getType().getStruct();
const TFieldList &fields = structure.fields();
for (size_t i = 0; i < fields.size(); i++)
{
const TField *field = fields[i];
node->getLeft()->traverse(this);
out << "." + DecorateField(field->name(), structure) + " == ";
node->getRight()->traverse(this);
out << "." + DecorateField(field->name(), structure);
if (i < fields.size() - 1)
{
out << " && ";
}
out << "!";
}
out << ")";
return false;
}
else
{
ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector());
if (node->getOp() == EOpEqual)
if (node->getLeft()->getBasicType() == EbtStruct)
{
outputTriplet(visit, "all(", " == ", ")");
const TStructure &structure = *node->getLeft()->getType().getStruct();
const TString &functionName = addStructEqualityFunction(structure);
outputTriplet(visit, functionName + "(", ", ", ")");
}
else
{
outputTriplet(visit, "!all(", " == ", ")");
ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector());
outputTriplet(visit, "all(", " == ", ")");
}
}
break;
......@@ -2861,4 +2843,65 @@ void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out)
<< "\n";
}
TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
{
const TFieldList &fields = structure.fields();
for (const auto &eqFunction : mStructEqualityFunctions)
{
if (eqFunction.structure == &structure)
{
return eqFunction.functionName;
}
}
const TString &structNameString = StructNameString(structure);
StructEqualityFunction function;
function.structure = &structure;
function.functionName = "angle_eq_" + structNameString;
TString &func = function.functionDefinition;
func = "bool " + function.functionName + "(" + structNameString + " a, " + structNameString + " b)\n" +
"{\n"
" return ";
for (size_t i = 0; i < fields.size(); i++)
{
const TField *field = fields[i];
const TType *fieldType = field->type();
const TString &fieldNameA = "a." + Decorate(field->name());
const TString &fieldNameB = "b." + Decorate(field->name());
if (i > 0)
{
func += " && ";
}
if (fieldType->getBasicType() == EbtStruct)
{
const TStructure &fieldStruct = *fieldType->getStruct();
const TString &functionName = addStructEqualityFunction(fieldStruct);
func += functionName + "(" + fieldNameA + ", " + fieldNameB + ")";
}
else if (fieldType->isScalar())
{
func += "(" + fieldNameA + " == " + fieldNameB + ")";
}
else
{
ASSERT(fieldType->isMatrix() || fieldType->isVector());
func += "all(" + fieldNameA + " == " + fieldNameB + ")";
}
}
func = func + ";\n" + "}\n";
mStructEqualityFunctions.push_back(function);
return function.functionName;
}
}
......@@ -73,6 +73,9 @@ class OutputHLSL : public TIntermTraverser
bool writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression);
void writeDeferredGlobalInitializers(TInfoSinkBase &out);
// Returns the function name
TString addStructEqualityFunction(const TStructure &structure);
TParseContext &mContext;
const ShShaderOutput mOutputType;
UnfoldShortCircuit *mUnfoldShortCircuit;
......@@ -160,6 +163,17 @@ class OutputHLSL : public TIntermTraverser
// shader input structure, which we set in the D3D main function. Instead, we can initialize
// these static globals after we initialize our other globals.
std::vector<std::pair<TIntermSymbol*, TIntermTyped*>> mDeferredGlobalInitializers;
// A list of structure equality comparison functions. It's important to preserve the order at
// which we add the functions, since nested structures call each other recursively.
struct StructEqualityFunction
{
const TStructure *structure;
TString functionName;
TString functionDefinition;
};
std::vector<StructEqualityFunction> mStructEqualityFunctions;
};
}
......
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