• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // RemovePow is an AST traverser to convert pow(x, y) built-in calls where y is a
7 // constant to exp2(y * log2(x)). This works around an issue in NVIDIA 311 series
8 // OpenGL drivers.
9 //
10 
11 #include "compiler/translator/tree_ops/RemovePow.h"
12 
13 #include "compiler/translator/InfoSink.h"
14 #include "compiler/translator/tree_util/IntermNode_util.h"
15 #include "compiler/translator/tree_util/IntermTraverse.h"
16 
17 namespace sh
18 {
19 
20 namespace
21 {
22 
IsProblematicPow(TIntermTyped * node)23 bool IsProblematicPow(TIntermTyped *node)
24 {
25     TIntermAggregate *agg = node->getAsAggregate();
26     if (agg != nullptr && agg->getOp() == EOpPow)
27     {
28         ASSERT(agg->getSequence()->size() == 2);
29         return agg->getSequence()->at(1)->getAsConstantUnion() != nullptr;
30     }
31     return false;
32 }
33 
34 // Traverser that converts all pow operations simultaneously.
35 class RemovePowTraverser : public TIntermTraverser
36 {
37   public:
38     RemovePowTraverser(TSymbolTable *symbolTable);
39 
40     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
41 
nextIteration()42     void nextIteration() { mNeedAnotherIteration = false; }
needAnotherIteration() const43     bool needAnotherIteration() const { return mNeedAnotherIteration; }
44 
45   protected:
46     bool mNeedAnotherIteration;
47 };
48 
RemovePowTraverser(TSymbolTable * symbolTable)49 RemovePowTraverser::RemovePowTraverser(TSymbolTable *symbolTable)
50     : TIntermTraverser(true, false, false, symbolTable), mNeedAnotherIteration(false)
51 {}
52 
visitAggregate(Visit visit,TIntermAggregate * node)53 bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
54 {
55     if (IsProblematicPow(node))
56     {
57         TIntermTyped *x = node->getSequence()->at(0)->getAsTyped();
58         TIntermTyped *y = node->getSequence()->at(1)->getAsTyped();
59 
60         TIntermSequence *logArgs = new TIntermSequence();
61         logArgs->push_back(x);
62         TIntermTyped *log = CreateBuiltInFunctionCallNode("log2", logArgs, *mSymbolTable, 100);
63         log->setLine(node->getLine());
64 
65         TOperator op       = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType());
66         TIntermBinary *mul = new TIntermBinary(op, y, log);
67         mul->setLine(node->getLine());
68 
69         TIntermSequence *expArgs = new TIntermSequence();
70         expArgs->push_back(mul);
71         TIntermTyped *exp = CreateBuiltInFunctionCallNode("exp2", expArgs, *mSymbolTable, 100);
72         exp->setLine(node->getLine());
73 
74         queueReplacement(exp, OriginalNode::IS_DROPPED);
75 
76         // If the x parameter also needs to be replaced, we need to do that in another traversal,
77         // since it's parent node will change in a way that's not handled correctly by updateTree().
78         if (IsProblematicPow(x))
79         {
80             mNeedAnotherIteration = true;
81             return false;
82         }
83     }
84     return true;
85 }
86 
87 }  // namespace
88 
RemovePow(TCompiler * compiler,TIntermNode * root,TSymbolTable * symbolTable)89 bool RemovePow(TCompiler *compiler, TIntermNode *root, TSymbolTable *symbolTable)
90 {
91     RemovePowTraverser traverser(symbolTable);
92     // Iterate as necessary, and reset the traverser between iterations.
93     do
94     {
95         traverser.nextIteration();
96         root->traverse(&traverser);
97         if (!traverser.updateTree(compiler, root))
98         {
99             return false;
100         }
101     } while (traverser.needAnotherIteration());
102 
103     return true;
104 }
105 
106 }  // namespace sh
107