Bug 1088858 - Backport ANGLE fixes to make WebGL work on Windows in Firefox 33. r=jmuizelaar, a=sledru
authorBenoit Jacob <bjacob@mozilla.com>
Fri, 24 Oct 2014 13:17:00 -0400
changeset 218150 d49ad0a834a8
parent 218149 efd4bca5ac0d
child 218151 b4f797f3cd52
push id555
push userryanvm@gmail.com
push date2014-10-29 17:07 +0000
treeherdermozilla-release@b4f797f3cd52 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmuizelaar, sledru
bugs1088858
milestone33.0.2
Bug 1088858 - Backport ANGLE fixes to make WebGL work on Windows in Firefox 33. r=jmuizelaar, a=sledru
gfx/angle/src/compiler/translator/IntermTraverse.cpp
gfx/angle/src/compiler/translator/OutputHLSL.cpp
gfx/angle/src/compiler/translator/OutputHLSL.h
gfx/angle/src/compiler/translator/RewriteElseBlocks.cpp
gfx/angle/src/compiler/translator/RewriteElseBlocks.h
gfx/angle/src/compiler/translator/intermediate.h
--- a/gfx/angle/src/compiler/translator/IntermTraverse.cpp
+++ b/gfx/angle/src/compiler/translator/IntermTraverse.cpp
@@ -252,8 +252,12 @@ void TIntermBranch::traverse(TIntermTrav
         expression->traverse(it);
         it->decrementDepth();
     }
 
     if (visit && it->postVisit)
         it->visitBranch(PostVisit, this);
 }
 
+void TIntermRaw::traverse(TIntermTraverser *it)
+{
+    it->visitRaw(this);
+}
--- a/gfx/angle/src/compiler/translator/OutputHLSL.cpp
+++ b/gfx/angle/src/compiler/translator/OutputHLSL.cpp
@@ -1847,16 +1847,21 @@ void OutputHLSL::visitSymbol(TIntermSymb
         }
         else
         {
             out << decorate(name);
         }
     }
 }
 
+void OutputHLSL::visitRaw(TIntermRaw *node)
+{
+    mBody << node->getRawText();
+}
+
 bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
 {
     TInfoSinkBase &out = mBody;
 
     // Handle accessing std140 structs by value
     if (mFlaggedStructMappedNames.count(node) > 0)
     {
         out << mFlaggedStructMappedNames[node];
--- a/gfx/angle/src/compiler/translator/OutputHLSL.h
+++ b/gfx/angle/src/compiler/translator/OutputHLSL.h
@@ -50,16 +50,17 @@ class OutputHLSL : public TIntermTravers
     static TString decorateUniform(const TString &string, const TType &type);
     static TString decorateField(const TString &string, const TStructure &structure);
 
   protected:
     void header();
 
     // Visit AST nodes and output their code to the body stream
     void visitSymbol(TIntermSymbol*);
+    void visitRaw(TIntermRaw*);
     void visitConstantUnion(TIntermConstantUnion*);
     bool visitBinary(Visit visit, TIntermBinary*);
     bool visitUnary(Visit visit, TIntermUnary*);
     bool visitSelection(Visit visit, TIntermSelection*);
     bool visitAggregate(Visit visit, TIntermAggregate*);
     bool visitLoop(Visit visit, TIntermLoop*);
     bool visitBranch(Visit visit, TIntermBranch*);
 
--- a/gfx/angle/src/compiler/translator/RewriteElseBlocks.cpp
+++ b/gfx/angle/src/compiler/translator/RewriteElseBlocks.cpp
@@ -31,35 +31,47 @@ TIntermBinary *MakeNewBinary(TOperator o
 
 TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
 {
     TIntermUnary *unary = new TIntermUnary(op, operand->getType());
     unary->setOperand(operand);
     return unary;
 }
 
+ElseBlockRewriter::ElseBlockRewriter()
+    : TIntermTraverser(true, false, true, false),
+      mTemporaryIndex(0),
+      mFunctionType(NULL)
+{}
+
 bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
 {
     switch (node->getOp())
     {
       case EOpSequence:
+        if (visit == PostVisit)
         {
             for (size_t statementIndex = 0; statementIndex != node->getSequence().size(); statementIndex++)
             {
                 TIntermNode *statement = node->getSequence()[statementIndex];
                 TIntermSelection *selection = statement->getAsSelectionNode();
                 if (selection && selection->getFalseBlock() != NULL)
                 {
                     node->getSequence()[statementIndex] = rewriteSelection(selection);
                     delete selection;
                 }
             }
         }
         break;
 
+      case EOpFunction:
+        // Store the current function context (see comment below)
+        mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL);
+        break;
+
       default: break;
     }
 
     return true;
 }
 
 TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
 {
@@ -69,18 +81,32 @@ TIntermNode *ElseBlockRewriter::rewriteS
     TIntermTyped *typedCondition = selection->getCondition()->getAsTyped();
     TType resultType(EbtBool, EbpUndefined);
     TIntermSymbol *conditionSymbolA = MakeNewTemporary(temporaryName, EbtBool);
     TIntermSymbol *conditionSymbolB = MakeNewTemporary(temporaryName, EbtBool);
     TIntermSymbol *conditionSymbolC = MakeNewTemporary(temporaryName, EbtBool);
     TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolA,
                                                   typedCondition, resultType);
     TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolB);
+    TIntermNode *negatedElse = NULL;
+
+    // crbug.com/346463
+    // 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
+    // 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);
+    }
+
     TIntermSelection *falseBlock = new TIntermSelection(negatedCondition,
-                                                        selection->getFalseBlock(), NULL);
+                                                        selection->getFalseBlock(), negatedElse);
     TIntermSelection *newIfElse = new TIntermSelection(conditionSymbolC,
                                                        selection->getTrueBlock(), falseBlock);
 
     TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration);
     declaration->getSequence().push_back(storeCondition);
 
     TIntermAggregate *block = new TIntermAggregate(EOpSequence);
     block->getSequence().push_back(declaration);
--- a/gfx/angle/src/compiler/translator/RewriteElseBlocks.h
+++ b/gfx/angle/src/compiler/translator/RewriteElseBlocks.h
@@ -13,26 +13,24 @@
 #include "compiler/translator/intermediate.h"
 
 namespace sh
 {
 
 class ElseBlockRewriter : public TIntermTraverser
 {
   public:
-      ElseBlockRewriter()
-          : TIntermTraverser(false, false, true, false)
-          , mTemporaryIndex(0)
-      {}
+    ElseBlockRewriter();
 
   protected:
     bool visitAggregate(Visit visit, TIntermAggregate *aggregate);
 
   private:
     int mTemporaryIndex;
+    const TType *mFunctionType;
 
     TIntermNode *rewriteSelection(TIntermSelection *selection);
 };
 
 void RewriteElseBlocks(TIntermNode *node);
 
 }
 
--- a/gfx/angle/src/compiler/translator/intermediate.h
+++ b/gfx/angle/src/compiler/translator/intermediate.h
@@ -206,16 +206,17 @@ class TIntermAggregate;
 class TIntermBinary;
 class TIntermUnary;
 class TIntermConstantUnion;
 class TIntermSelection;
 class TIntermTyped;
 class TIntermSymbol;
 class TIntermLoop;
 class TInfoSink;
+class TIntermRaw;
 
 //
 // Base class for the tree nodes
 //
 class TIntermNode {
 public:
     POOL_ALLOCATOR_NEW_DELETE();
     TIntermNode() {
@@ -233,16 +234,17 @@ public:
     virtual TIntermTyped* getAsTyped() { return 0; }
     virtual TIntermConstantUnion* getAsConstantUnion() { return 0; }
     virtual TIntermAggregate* getAsAggregate() { return 0; }
     virtual TIntermBinary* getAsBinaryNode() { return 0; }
     virtual TIntermUnary* getAsUnaryNode() { return 0; }
     virtual TIntermSelection* getAsSelectionNode() { return 0; }
     virtual TIntermSymbol* getAsSymbolNode() { return 0; }
     virtual TIntermLoop* getAsLoopNode() { return 0; }
+    virtual TIntermRaw* getAsRawNode() { return 0; }
 
     // Replace a child node. Return true if |original| is a child
     // node and it is replaced; otherwise, return false.
     virtual bool replaceChildNode(
         TIntermNode *original, TIntermNode *replacement) = 0;
 
     // For traversing a tree in no particular order, but using
     // heap memory.
@@ -392,16 +394,39 @@ public:
 
     virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {}
 
 protected:
     int id;
     TString symbol;
 };
 
+// A Raw node stores raw code, that the translator will insert verbatim
+// into the output stream. Useful for transformation operations that make
+// complex code that might not fit naturally into the GLSL model.
+class TIntermRaw : public TIntermTyped {
+public:
+    TIntermRaw(const TType &t, const TString &rawTextIn)
+        : TIntermTyped(t), rawText(rawTextIn)
+    {}
+
+    virtual bool hasSideEffects() const { return false; }
+
+    TString getRawText() const { return rawText; }
+
+    virtual void traverse(TIntermTraverser*);
+
+    virtual TIntermRaw* getAsRawNode() { return this; }
+    virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
+    virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {}
+
+protected:
+    TString rawText;
+};
+
 class TIntermConstantUnion : public TIntermTyped {
 public:
     TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
 
     virtual bool hasSideEffects() const { return false; }
 
     ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
     
@@ -614,16 +639,17 @@ public:
             inVisit(inVisit),
             postVisit(postVisit),
             rightToLeft(rightToLeft),
             depth(0),
             maxDepth(0) {}
     virtual ~TIntermTraverser() {}
 
     virtual void visitSymbol(TIntermSymbol*) {}
+    virtual void visitRaw(TIntermRaw*) {}
     virtual void visitConstantUnion(TIntermConstantUnion*) {}
     virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;}
     virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;}
     virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;}
     virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
     virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
     virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}