Commit b8cb939f by Olli Etuaho Committed by Commit Bot

Fix tracking variables in folded ternary operators

The result of folding a ternary operator may be a TIntermSymbol node where the qualifier doesn't match the qualifier of the variable that the node is referring to. Get the qualifier from the variable instead of directly from TIntermSymbol when collecting variables in CollectVariables or when tracking referenced variables in OutputHLSL. BUG=angleproject:2288 TEST=angle_unittests, angle_end2end_tests Change-Id: If294a7fe9dca50f2ebcea3feff887e72a521d395 Reviewed-on: https://chromium-review.googlesource.com/836893Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 8a57b468
...@@ -349,11 +349,15 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol) ...@@ -349,11 +349,15 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
ShaderVariable *var = nullptr; ShaderVariable *var = nullptr;
const TString &symbolName = symbol->getName().getString(); const TString &symbolName = symbol->getName().getString();
if (IsVaryingIn(symbol->getQualifier())) // Check the qualifier from the variable, not from the symbol node. The node may have a
// different qualifier if it's the result of a folded ternary node.
TQualifier qualifier = symbol->variable().getType().getQualifier();
if (IsVaryingIn(qualifier))
{ {
var = FindVariable(symbolName, mInputVaryings); var = FindVariable(symbolName, mInputVaryings);
} }
else if (IsVaryingOut(symbol->getQualifier())) else if (IsVaryingOut(qualifier))
{ {
var = FindVariable(symbolName, mOutputVaryings); var = FindVariable(symbolName, mOutputVaryings);
} }
...@@ -363,7 +367,7 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol) ...@@ -363,7 +367,7 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
} }
else if (symbolName == "gl_DepthRange") else if (symbolName == "gl_DepthRange")
{ {
ASSERT(symbol->getQualifier() == EvqUniform); ASSERT(qualifier == EvqUniform);
if (!mDepthRangeAdded) if (!mDepthRangeAdded)
{ {
...@@ -406,7 +410,7 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol) ...@@ -406,7 +410,7 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
} }
else else
{ {
switch (symbol->getQualifier()) switch (qualifier)
{ {
case EvqAttribute: case EvqAttribute:
case EvqVertexIn: case EvqVertexIn:
......
...@@ -251,9 +251,12 @@ class TIntermBranch : public TIntermNode ...@@ -251,9 +251,12 @@ class TIntermBranch : public TIntermNode
TIntermTyped *mExpression; // non-zero except for "return exp;" statements TIntermTyped *mExpression; // non-zero except for "return exp;" statements
}; };
// // Nodes that correspond to variable symbols in the source code. These may be regular variables or
// Nodes that correspond to symbols or constants in the source code. // interface block instances. In declarations that only declare a struct type but no variables, a
// // TIntermSymbol node with an empty variable is used to store the type. In case the node is the
// result of folding a more complex expression such as a ternary operator, the node takes on the
// type of the expression. In this case the qualifier of the node may be different from the variable
// it refers to.
class TIntermSymbol : public TIntermTyped class TIntermSymbol : public TIntermTyped
{ {
public: public:
......
...@@ -403,11 +403,10 @@ void OutputHLSL::header(TInfoSinkBase &out, ...@@ -403,11 +403,10 @@ void OutputHLSL::header(TInfoSinkBase &out,
TString attributes; TString attributes;
TString mappedStructs = generateStructMapping(std140Structs); TString mappedStructs = generateStructMapping(std140Structs);
for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); for (const auto &varying : mReferencedVaryings)
varying != mReferencedVaryings.end(); varying++)
{ {
const TType &type = varying->second->getType(); const TType &type = varying.second->variable().getType();
const TString &name = varying->second->getSymbol(); const TString &name = varying.second->getSymbol();
// Program linking depends on this exact format // Program linking depends on this exact format
varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
...@@ -880,7 +879,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -880,7 +879,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
else else
{ {
const TType &nodeType = node->getType(); const TType &nodeType = node->getType();
TQualifier qualifier = node->getQualifier(); TQualifier qualifier = node->variable().getType().getQualifier();
ensureStructDefined(nodeType); ensureStructDefined(nodeType);
......
...@@ -1523,3 +1523,33 @@ TEST_F(CollectGeometryVariablesTest, CollectOutputsWithInvariant) ...@@ -1523,3 +1523,33 @@ TEST_F(CollectGeometryVariablesTest, CollectOutputsWithInvariant)
EXPECT_EQ("texcoord", varying->name); EXPECT_EQ("texcoord", varying->name);
EXPECT_TRUE(varying->isInvariant); EXPECT_TRUE(varying->isInvariant);
} }
// Test collecting a varying variable that is used inside a folded ternary operator. The result of
// the folded ternary operator has a different qualifier from the original variable, which makes
// this case tricky.
TEST_F(CollectFragmentVariablesTest, VaryingUsedInsideFoldedTernary)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
centroid in float vary;
out vec4 color;
void main() {
color = vec4(0.0, true ? vary : 0.0, 0.0, 1.0);
})";
compile(shaderString);
const std::vector<Varying> &varyings = mTranslator->getInputVaryings();
ASSERT_EQ(1u, varyings.size());
const Varying *varying = &varyings[0];
EXPECT_FALSE(varying->isArray());
EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, varying->precision);
EXPECT_TRUE(varying->staticUse);
EXPECT_GLENUM_EQ(GL_FLOAT, varying->type);
EXPECT_EQ("vary", varying->name);
EXPECT_EQ(DecorateName("vary"), varying->mappedName);
EXPECT_EQ(INTERPOLATION_CENTROID, varying->interpolation);
}
...@@ -3881,6 +3881,41 @@ TEST_P(GLSLTest, VectorScalarDivideAndAddInLoop) ...@@ -3881,6 +3881,41 @@ TEST_P(GLSLTest, VectorScalarDivideAndAddInLoop)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// Test that a varying with a flat qualifier that is used as an operand of a folded ternary operator
// is handled correctly.
TEST_P(GLSLTest_ES3, FlatVaryingUsedInFoldedTernary)
{
const std::string &vertexShader =
R"(#version 300 es
in vec4 inputAttribute;
flat out int v;
void main()
{
v = 1;
gl_Position = inputAttribute;
})";
const std::string &fragmentShader =
R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
flat in int v;
void main()
{
my_FragColor = vec4(0, (true ? v : 0), 0, 1);
})";
ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
drawQuad(program.get(), "inputAttribute", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(GLSLTest, ANGLE_INSTANTIATE_TEST(GLSLTest,
ES2_D3D9(), ES2_D3D9(),
......
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