diff options
Diffstat (limited to 'gfx/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp')
-rwxr-xr-x | gfx/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/gfx/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp b/gfx/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp new file mode 100755 index 000000000..152251fde --- /dev/null +++ b/gfx/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp @@ -0,0 +1,249 @@ +// +// Copyright (c) 2002-2011 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. +// + +#include "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/Cache.h" + +namespace sh +{ + +class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser +{ + public: + BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator) + : TIntermTraverser(true, false, false), + mEmulator(emulator) + { + } + + bool visitUnary(Visit visit, TIntermUnary *node) override + { + if (visit == PreVisit) + { + bool needToEmulate = mEmulator.SetFunctionCalled(node->getOp(), node->getOperand()->getType()); + if (needToEmulate) + node->setUseEmulatedFunction(); + } + return true; + } + + bool visitAggregate(Visit visit, TIntermAggregate *node) override + { + if (visit == PreVisit) + { + // Here we handle all the built-in functions instead of the ones we + // currently identified as problematic. + switch (node->getOp()) + { + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + case EOpVectorEqual: + case EOpVectorNotEqual: + case EOpMod: + case EOpPow: + case EOpAtan: + case EOpMin: + case EOpMax: + case EOpClamp: + case EOpMix: + case EOpStep: + case EOpSmoothStep: + case EOpDistance: + case EOpDot: + case EOpCross: + case EOpFaceForward: + case EOpReflect: + case EOpRefract: + case EOpOuterProduct: + case EOpMul: + break; + default: + return true; + } + const TIntermSequence &sequence = *(node->getSequence()); + bool needToEmulate = false; + // Right now we only handle built-in functions with two or three parameters. + if (sequence.size() == 2) + { + TIntermTyped *param1 = sequence[0]->getAsTyped(); + TIntermTyped *param2 = sequence[1]->getAsTyped(); + if (!param1 || !param2) + return true; + needToEmulate = mEmulator.SetFunctionCalled( + node->getOp(), param1->getType(), param2->getType()); + } + else if (sequence.size() == 3) + { + TIntermTyped *param1 = sequence[0]->getAsTyped(); + TIntermTyped *param2 = sequence[1]->getAsTyped(); + TIntermTyped *param3 = sequence[2]->getAsTyped(); + if (!param1 || !param2 || !param3) + return true; + needToEmulate = mEmulator.SetFunctionCalled( + node->getOp(), param1->getType(), param2->getType(), param3->getType()); + } + else + { + return true; + } + + if (needToEmulate) + node->setUseEmulatedFunction(); + } + return true; + } + + private: + BuiltInFunctionEmulator &mEmulator; +}; + +BuiltInFunctionEmulator::BuiltInFunctionEmulator() +{} + +void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param, + const char *emulatedFunctionDefinition) +{ + mEmulatedFunctions[FunctionId(op, param)] = std::string(emulatedFunctionDefinition); +} + +void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2, + const char *emulatedFunctionDefinition) +{ + mEmulatedFunctions[FunctionId(op, param1, param2)] = std::string(emulatedFunctionDefinition); +} + +void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2, + const TType *param3, const char *emulatedFunctionDefinition) +{ + mEmulatedFunctions[FunctionId(op, param1, param2, param3)] = std::string(emulatedFunctionDefinition); +} + +bool BuiltInFunctionEmulator::IsOutputEmpty() const +{ + return (mFunctions.size() == 0); +} + +void BuiltInFunctionEmulator::OutputEmulatedFunctions(TInfoSinkBase &out) const +{ + for (size_t i = 0; i < mFunctions.size(); ++i) + { + out << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n"; + } +} + +bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType ¶m) +{ + return SetFunctionCalled(FunctionId(op, ¶m)); +} + +bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType ¶m1, const TType ¶m2) +{ + return SetFunctionCalled(FunctionId(op, ¶m1, ¶m2)); +} + +bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, + const TType ¶m1, const TType ¶m2, const TType ¶m3) +{ + return SetFunctionCalled(FunctionId(op, ¶m1, ¶m2, ¶m3)); +} + +bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId) +{ + if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end()) + { + for (size_t i = 0; i < mFunctions.size(); ++i) + { + if (mFunctions[i] == functionId) + return true; + } + // Copy the functionId if it needs to be stored, to make sure that the TType pointers inside + // remain valid and constant. + mFunctions.push_back(functionId.getCopy()); + return true; + } + return false; +} + +void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(TIntermNode *root) +{ + ASSERT(root); + + if (mEmulatedFunctions.empty()) + return; + + BuiltInFunctionEmulationMarker marker(*this); + root->traverse(&marker); +} + +void BuiltInFunctionEmulator::Cleanup() +{ + mFunctions.clear(); +} + +//static +TString BuiltInFunctionEmulator::GetEmulatedFunctionName( + const TString &name) +{ + ASSERT(name[name.length() - 1] == '('); + return "webgl_" + name.substr(0, name.length() - 1) + "_emu("; +} + +BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param) + : mOp(op), + mParam1(param), + mParam2(TCache::getType(EbtVoid)), + mParam3(TCache::getType(EbtVoid)) +{ +} + +BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2) + : mOp(op), + mParam1(param1), + mParam2(param2), + mParam3(TCache::getType(EbtVoid)) +{ +} + +BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, + const TType *param1, const TType *param2, const TType *param3) + : mOp(op), + mParam1(param1), + mParam2(param2), + mParam3(param3) +{ +} + +bool BuiltInFunctionEmulator::FunctionId::operator==(const BuiltInFunctionEmulator::FunctionId &other) const +{ + return (mOp == other.mOp && + *mParam1 == *other.mParam1 && + *mParam2 == *other.mParam2 && + *mParam3 == *other.mParam3); +} + +bool BuiltInFunctionEmulator::FunctionId::operator<(const BuiltInFunctionEmulator::FunctionId &other) const +{ + if (mOp != other.mOp) + return mOp < other.mOp; + if (*mParam1 != *other.mParam1) + return *mParam1 < *other.mParam1; + if (*mParam2 != *other.mParam2) + return *mParam2 < *other.mParam2; + if (*mParam3 != *other.mParam3) + return *mParam3 < *other.mParam3; + return false; // all fields are equal +} + +BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::FunctionId::getCopy() const +{ + return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3)); +} + +} // namespace sh |