Commit 4836d22a by Jamie Madill

Fix ASSERT when rewriting else-if blocks with no else.

The code assumed an else-if would end in an else. We can also save a few allocations in the cases where there is no else. BUG=angle:699 Change-Id: I550857366775b4a34aea97e117ef732297d3f448 Reviewed-on: https://chromium-review.googlesource.com/208681Tested-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarNicolas Capens <capn@chromium.org>
parent 048c4fe7
...@@ -14,6 +14,24 @@ ...@@ -14,6 +14,24 @@
namespace sh namespace sh
{ {
namespace
{
class ElseBlockRewriter : public TIntermTraverser
{
public:
ElseBlockRewriter();
protected:
bool visitAggregate(Visit visit, TIntermAggregate *aggregate);
private:
int mTemporaryIndex;
const TType *mFunctionType;
TIntermNode *rewriteSelection(TIntermSelection *selection);
};
TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type) TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type)
{ {
TType variableType(type, EbpHigh, EvqInternal); TType variableType(type, EbpHigh, EvqInternal);
...@@ -83,46 +101,54 @@ bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -83,46 +101,54 @@ bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection) TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
{ {
ASSERT(selection->getFalseBlock() != NULL); ASSERT(selection != NULL);
TString temporaryName = "cond_" + str(mTemporaryIndex++); TString temporaryName = "cond_" + str(mTemporaryIndex++);
TIntermTyped *typedCondition = selection->getCondition()->getAsTyped(); TIntermTyped *typedCondition = selection->getCondition()->getAsTyped();
TType resultType(EbtBool, EbpUndefined); TType resultType(EbtBool, EbpUndefined);
TIntermSymbol *conditionSymbolA = MakeNewTemporary(temporaryName, EbtBool); TIntermSymbol *conditionSymbolInit = MakeNewTemporary(temporaryName, EbtBool);
TIntermSymbol *conditionSymbolB = MakeNewTemporary(temporaryName, EbtBool); TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolInit,
TIntermSymbol *conditionSymbolC = MakeNewTemporary(temporaryName, EbtBool);
TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolA,
typedCondition, resultType); typedCondition, resultType);
TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolB);
TIntermNode *negatedElse = NULL; TIntermNode *negatedElse = NULL;
// crbug.com/346463 TIntermSelection *falseBlock = NULL;
// D3D generates error messages claiming a function has no return value, when rewriting
// an if-else clause that returns something non-void in a function. By appending dummy if (selection->getFalseBlock())
// returns (that are unreachable) we can silence this compile error.
if (mFunctionType && mFunctionType->getBasicType() != EbtVoid)
{ {
TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() : // crbug.com/346463
mFunctionType->getBasicString(); // D3D generates error messages claiming a function has no return value, when rewriting
TString rawText = "return (" + typeString + ")0"; // an if-else clause that returns something non-void in a function. By appending dummy
negatedElse = new TIntermRaw(*mFunctionType, rawText); // returns (that are unreachable) we can silence this compile error.
if (mFunctionType && mFunctionType->getBasicType() != EbtVoid)
{
TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() :
mFunctionType->getBasicString();
TString rawText = "return (" + typeString + ")0";
negatedElse = new TIntermRaw(*mFunctionType, rawText);
}
TIntermSymbol *conditionSymbolElse = MakeNewTemporary(temporaryName, EbtBool);
TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolElse);
falseBlock = new TIntermSelection(negatedCondition,
selection->getFalseBlock(), negatedElse);
} }
TIntermSelection *falseBlock = new TIntermSelection(negatedCondition, TIntermSymbol *conditionSymbolSel = MakeNewTemporary(temporaryName, EbtBool);
selection->getFalseBlock(), negatedElse); TIntermSelection *newSelection = new TIntermSelection(conditionSymbolSel,
TIntermSelection *newIfElse = new TIntermSelection(conditionSymbolC, selection->getTrueBlock(), falseBlock);
selection->getTrueBlock(), falseBlock);
TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration); TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration);
declaration->getSequence()->push_back(storeCondition); declaration->getSequence()->push_back(storeCondition);
TIntermAggregate *block = new TIntermAggregate(EOpSequence); TIntermAggregate *block = new TIntermAggregate(EOpSequence);
block->getSequence()->push_back(declaration); block->getSequence()->push_back(declaration);
block->getSequence()->push_back(newIfElse); block->getSequence()->push_back(newSelection);
return block; return block;
} }
}
void RewriteElseBlocks(TIntermNode *node) void RewriteElseBlocks(TIntermNode *node)
{ {
ElseBlockRewriter rewriter; ElseBlockRewriter rewriter;
......
...@@ -15,21 +15,6 @@ ...@@ -15,21 +15,6 @@
namespace sh namespace sh
{ {
class ElseBlockRewriter : public TIntermTraverser
{
public:
ElseBlockRewriter();
protected:
bool visitAggregate(Visit visit, TIntermAggregate *aggregate);
private:
int mTemporaryIndex;
const TType *mFunctionType;
TIntermNode *rewriteSelection(TIntermSelection *selection);
};
void RewriteElseBlocks(TIntermNode *node); void RewriteElseBlocks(TIntermNode *node);
} }
......
...@@ -143,3 +143,65 @@ TEST_F(GLSLTest, DxPositionBug) ...@@ -143,3 +143,65 @@ TEST_F(GLSLTest, DxPositionBug)
GLuint program = compileProgram(vertexShaderSource, fragmentShaderSource); GLuint program = compileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_NE(0u, program); EXPECT_NE(0u, program);
} }
TEST_F(GLSLTest, ElseIfRewriting)
{
const std::string &vertexShaderSource =
"attribute vec4 a_position;\n"
"varying float v;\n"
"void main() {\n"
" gl_Position = a_position;\n"
" v = 1.0;\n"
" if (a_position.x <= 0.5) {\n"
" v = 0.0;\n"
" } else if (a_position.x >= 0.5) {\n"
" v = 2.0;\n"
" }\n"
"}\n";
const std::string &fragmentShaderSource =
"precision highp float;\n"
"varying float v;\n"
"void main() {\n"
" vec4 color = vec4(1.0, 0.0, 0.0, 1.0);\n"
" if (v >= 1.0) color = vec4(0.0, 1.0, 0.0, 1.0);\n"
" if (v >= 2.0) color = vec4(0.0, 0.0, 1.0, 1.0);\n"
" gl_FragColor = color;\n"
"}\n";
GLuint program = compileProgram(vertexShaderSource, fragmentShaderSource);
ASSERT_NE(0u, program);
drawQuad(program, "a_position", 0.5f);
swapBuffers();
EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
EXPECT_PIXEL_EQ(getWindowWidth()-1, 0, 0, 255, 0, 255);
}
TEST_F(GLSLTest, TwoElseIfRewriting)
{
const std::string &vertexShaderSource =
"attribute vec4 a_position;\n"
"varying float v;\n"
"void main() {\n"
" gl_Position = a_position;\n"
" if (a_position.x == 0.0`) {\n"
" v = 1.0;\n"
" } else if (a_position.x > 0.5) {\n"
" v = 0.0;\n"
" } else if (a_position.x > 0.75) {\n"
" v = 0.5;\n"
" }\n"
"}\n";
const std::string &fragmentShaderSource =
"precision highp float;\n"
"varying float v;\n"
"void main() {\n"
" gl_FragColor = vec4(v, 0.0, 0.0, 1.0);\n"
"}\n";
GLuint program = compileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_NE(0u, program);
}
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