// // 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" class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser { public: BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator) : mEmulator(emulator) { } virtual bool visitUnary(Visit visit, TIntermUnary* node) { if (visit == PreVisit) { bool needToEmulate = mEmulator.SetFunctionCalled( node->getOp(), node->getOperand()->getType()); if (needToEmulate) node->setUseEmulatedFunction(); } return true; } virtual bool visitAggregate(Visit visit, TIntermAggregate* node) { 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& param) { return SetFunctionCalled(FunctionId(op, param)); } bool BuiltInFunctionEmulator::SetFunctionCalled( TOperator op, const TType& param1, const TType& param2) { return SetFunctionCalled(FunctionId(op, param1, param2)); } bool BuiltInFunctionEmulator::SetFunctionCalled( TOperator op, const TType& param1, const TType& param2, const TType& param3) { return SetFunctionCalled(FunctionId(op, param1, param2, param3)); } 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; } mFunctions.push_back(functionId); 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(EbtVoid), mParam3(EbtVoid) { } BuiltInFunctionEmulator::FunctionId::FunctionId (TOperator op, const TType& param1, const TType& param2) : mOp(op), mParam1(param1), mParam2(param2), mParam3(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 }