Hash :
03d863c8
Author :
Date :
2016-07-27T18:15:53
translator: Refactor node replacement APIs. BUG=angleproject:851 Change-Id: I50c3b3a4f00b27fed85f09509738513a441c7b5b Reviewed-on: https://chromium-review.googlesource.com/363990 Reviewed-by: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: Zhenyao Mo <zmo@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
//
// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RemovePow is an AST traverser to convert pow(x, y) built-in calls where y is a
// constant to exp2(y * log2(x)). This works around an issue in NVIDIA 311 series
// OpenGL drivers.
//
#include "compiler/translator/RemovePow.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
namespace
{
bool IsProblematicPow(TIntermTyped *node)
{
TIntermAggregate *agg = node->getAsAggregate();
if (agg != nullptr && agg->getOp() == EOpPow)
{
ASSERT(agg->getSequence()->size() == 2);
return agg->getSequence()->at(1)->getAsConstantUnion() != nullptr;
}
return false;
}
// Traverser that converts all pow operations simultaneously.
class RemovePowTraverser : public TIntermTraverser
{
public:
RemovePowTraverser();
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
void nextIteration() { mNeedAnotherIteration = false; }
bool needAnotherIteration() const { return mNeedAnotherIteration; }
protected:
bool mNeedAnotherIteration;
};
RemovePowTraverser::RemovePowTraverser()
: TIntermTraverser(true, false, false),
mNeedAnotherIteration(false)
{
}
bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
if (IsProblematicPow(node))
{
TInfoSink nullSink;
TIntermTyped *x = node->getSequence()->at(0)->getAsTyped();
TIntermTyped *y = node->getSequence()->at(1)->getAsTyped();
TIntermUnary *log = new TIntermUnary(EOpLog2);
log->setOperand(x);
log->setLine(node->getLine());
log->setType(x->getType());
TIntermBinary *mul = new TIntermBinary(EOpMul);
mul->setLeft(y);
mul->setRight(log);
mul->setLine(node->getLine());
bool valid = mul->promote(nullSink);
UNUSED_ASSERTION_VARIABLE(valid);
ASSERT(valid);
TIntermUnary *exp = new TIntermUnary(EOpExp2);
exp->setOperand(mul);
exp->setLine(node->getLine());
exp->setType(node->getType());
queueReplacement(node, exp, OriginalNode::IS_DROPPED);
// If the x parameter also needs to be replaced, we need to do that in another traversal,
// since it's parent node will change in a way that's not handled correctly by updateTree().
if (IsProblematicPow(x))
{
mNeedAnotherIteration = true;
return false;
}
}
return true;
}
} // namespace
void RemovePow(TIntermNode *root)
{
RemovePowTraverser traverser;
// Iterate as necessary, and reset the traverser between iterations.
do
{
traverser.nextIteration();
root->traverse(&traverser);
traverser.updateTree();
}
while (traverser.needAnotherIteration());
}