Line data Source code
1 : //
2 : // Copyright (c) 2002-2015 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/RemovePow.h"
12 :
13 : #include "compiler/translator/InfoSink.h"
14 : #include "compiler/translator/IntermNode.h"
15 :
16 : namespace sh
17 : {
18 :
19 : namespace
20 : {
21 :
22 0 : bool IsProblematicPow(TIntermTyped *node)
23 : {
24 0 : TIntermAggregate *agg = node->getAsAggregate();
25 0 : if (agg != nullptr && agg->getOp() == EOpPow)
26 : {
27 0 : ASSERT(agg->getSequence()->size() == 2);
28 0 : return agg->getSequence()->at(1)->getAsConstantUnion() != nullptr;
29 : }
30 0 : return false;
31 : }
32 :
33 : // Traverser that converts all pow operations simultaneously.
34 0 : class RemovePowTraverser : public TIntermTraverser
35 : {
36 : public:
37 : RemovePowTraverser();
38 :
39 : bool visitAggregate(Visit visit, TIntermAggregate *node) override;
40 :
41 0 : void nextIteration() { mNeedAnotherIteration = false; }
42 0 : bool needAnotherIteration() const { return mNeedAnotherIteration; }
43 :
44 : protected:
45 : bool mNeedAnotherIteration;
46 : };
47 :
48 0 : RemovePowTraverser::RemovePowTraverser()
49 : : TIntermTraverser(true, false, false),
50 0 : mNeedAnotherIteration(false)
51 : {
52 0 : }
53 :
54 0 : bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
55 : {
56 0 : if (IsProblematicPow(node))
57 : {
58 0 : TIntermTyped *x = node->getSequence()->at(0)->getAsTyped();
59 0 : TIntermTyped *y = node->getSequence()->at(1)->getAsTyped();
60 :
61 0 : TIntermUnary *log = new TIntermUnary(EOpLog2, x);
62 0 : log->setLine(node->getLine());
63 :
64 0 : TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType());
65 0 : TIntermBinary *mul = new TIntermBinary(op, y, log);
66 0 : mul->setLine(node->getLine());
67 :
68 0 : TIntermUnary *exp = new TIntermUnary(EOpExp2, mul);
69 0 : exp->setLine(node->getLine());
70 :
71 0 : queueReplacement(node, exp, OriginalNode::IS_DROPPED);
72 :
73 : // If the x parameter also needs to be replaced, we need to do that in another traversal,
74 : // since it's parent node will change in a way that's not handled correctly by updateTree().
75 0 : if (IsProblematicPow(x))
76 : {
77 0 : mNeedAnotherIteration = true;
78 0 : return false;
79 : }
80 : }
81 0 : return true;
82 : }
83 :
84 : } // namespace
85 :
86 0 : void RemovePow(TIntermNode *root)
87 : {
88 0 : RemovePowTraverser traverser;
89 : // Iterate as necessary, and reset the traverser between iterations.
90 0 : do
91 : {
92 0 : traverser.nextIteration();
93 0 : root->traverse(&traverser);
94 0 : traverser.updateTree();
95 : }
96 : while (traverser.needAnotherIteration());
97 0 : }
98 :
99 : } // namespace sh
|