| // |
| // Copyright 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_test.cpp: |
| // Tests for removing pow() function calls from the AST. |
| // |
| |
| #include "GLSLANG/ShaderLang.h" |
| #include "angle_gl.h" |
| #include "compiler/translator/TranslatorGLSL.h" |
| #include "compiler/translator/tree_util/NodeSearch.h" |
| #include "gtest/gtest.h" |
| |
| using namespace sh; |
| |
| class RemovePowTest : public testing::Test |
| { |
| public: |
| RemovePowTest() {} |
| |
| protected: |
| void SetUp() override |
| { |
| allocator.push(); |
| SetGlobalPoolAllocator(&allocator); |
| ShBuiltInResources resources; |
| sh::InitBuiltInResources(&resources); |
| mTranslatorGLSL = |
| new sh::TranslatorGLSL(GL_FRAGMENT_SHADER, SH_GLES2_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT); |
| ASSERT_TRUE(mTranslatorGLSL->Init(resources)); |
| } |
| |
| void TearDown() override |
| { |
| SafeDelete(mTranslatorGLSL); |
| SetGlobalPoolAllocator(nullptr); |
| allocator.pop(); |
| } |
| |
| void compile(const std::string &shaderString) |
| { |
| const char *shaderStrings[] = {shaderString.c_str()}; |
| mASTRoot = mTranslatorGLSL->compileTreeForTesting( |
| shaderStrings, 1, SH_OBJECT_CODE | SH_REMOVE_POW_WITH_CONSTANT_EXPONENT); |
| if (!mASTRoot) |
| { |
| TInfoSink &infoSink = mTranslatorGLSL->getInfoSink(); |
| FAIL() << "Shader compilation into ESSL failed " << infoSink.info.c_str(); |
| } |
| } |
| |
| template <class T> |
| bool foundInAST() |
| { |
| return T::search(mASTRoot); |
| } |
| |
| private: |
| sh::TranslatorGLSL *mTranslatorGLSL; |
| TIntermNode *mASTRoot; |
| |
| angle::PoolAllocator allocator; |
| }; |
| |
| // Check if there's a pow() node anywhere in the tree. |
| class FindPow : public sh::NodeSearchTraverser<FindPow> |
| { |
| public: |
| bool visitBinary(Visit visit, TIntermBinary *node) override |
| { |
| if (node->getOp() == EOpPow) |
| { |
| mFound = true; |
| } |
| return !mFound; |
| } |
| }; |
| |
| // Check if the tree starting at node corresponds to exp2(y * log2(x)) |
| // If the tree matches, set base to the node corresponding to x. |
| bool IsPowWorkaround(TIntermNode *node, TIntermNode **base) |
| { |
| TIntermUnary *exp = node->getAsUnaryNode(); |
| if (exp != nullptr && exp->getOp() == EOpExp2) |
| { |
| TIntermBinary *mul = exp->getOperand()->getAsBinaryNode(); |
| if (mul != nullptr && mul->isMultiplication()) |
| { |
| TIntermUnary *log = mul->getRight()->getAsUnaryNode(); |
| if (mul->getLeft()->getAsConstantUnion() && log != nullptr) |
| { |
| if (log->getOp() == EOpLog2) |
| { |
| if (base) |
| *base = log->getOperand(); |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| // Check if there's a node with the correct workaround to pow anywhere in the tree. |
| class FindPowWorkaround : public sh::NodeSearchTraverser<FindPowWorkaround> |
| { |
| public: |
| bool visitUnary(Visit visit, TIntermUnary *node) override |
| { |
| mFound = IsPowWorkaround(node, nullptr); |
| return !mFound; |
| } |
| }; |
| |
| // Check if there's a node with the correct workaround to pow with another workaround to pow |
| // nested within it anywhere in the tree. |
| class FindNestedPowWorkaround : public sh::NodeSearchTraverser<FindNestedPowWorkaround> |
| { |
| public: |
| bool visitUnary(Visit visit, TIntermUnary *node) override |
| { |
| TIntermNode *base = nullptr; |
| bool oneFound = IsPowWorkaround(node, &base); |
| if (oneFound && base) |
| mFound = IsPowWorkaround(base, nullptr); |
| return !mFound; |
| } |
| }; |
| |
| TEST_F(RemovePowTest, PowWithConstantExponent) |
| { |
| const std::string &shaderString = |
| "precision mediump float;\n" |
| "uniform float u;\n" |
| "void main() {\n" |
| " gl_FragColor = pow(vec4(u), vec4(0.5));\n" |
| "}\n"; |
| compile(shaderString); |
| ASSERT_FALSE(foundInAST<FindPow>()); |
| ASSERT_TRUE(foundInAST<FindPowWorkaround>()); |
| ASSERT_FALSE(foundInAST<FindNestedPowWorkaround>()); |
| } |
| |
| TEST_F(RemovePowTest, NestedPowWithConstantExponent) |
| { |
| const std::string &shaderString = |
| "precision mediump float;\n" |
| "uniform float u;\n" |
| "void main() {\n" |
| " gl_FragColor = pow(pow(vec4(u), vec4(2.0)), vec4(0.5));\n" |
| "}\n"; |
| compile(shaderString); |
| ASSERT_FALSE(foundInAST<FindPow>()); |
| ASSERT_TRUE(foundInAST<FindNestedPowWorkaround>()); |
| } |