| // | |
| // 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>()); | |
| } |