BuiltInFunctionEmulator.cpp (4352B)
1 // 2 // Copyright 2002 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #include "compiler/translator/BuiltInFunctionEmulator.h" 8 #include "angle_gl.h" 9 #include "compiler/translator/Symbol.h" 10 #include "compiler/translator/tree_util/IntermTraverse.h" 11 12 namespace sh 13 { 14 15 class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser 16 { 17 public: 18 BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator) 19 : TIntermTraverser(true, false, false), mEmulator(emulator) 20 {} 21 22 bool visitUnary(Visit visit, TIntermUnary *node) override 23 { 24 if (node->getFunction()) 25 { 26 bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction()); 27 if (needToEmulate) 28 node->setUseEmulatedFunction(); 29 } 30 return true; 31 } 32 33 bool visitAggregate(Visit visit, TIntermAggregate *node) override 34 { 35 // Here we handle all the math built-in functions, not just the ones that are currently 36 // identified as problematic. 37 if (!BuiltInGroup::IsMath(node->getOp())) 38 { 39 return true; 40 } 41 bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction()); 42 if (needToEmulate) 43 node->setUseEmulatedFunction(); 44 return true; 45 } 46 47 private: 48 BuiltInFunctionEmulator &mEmulator; 49 }; 50 51 BuiltInFunctionEmulator::BuiltInFunctionEmulator() {} 52 53 void BuiltInFunctionEmulator::addEmulatedFunction(const TSymbolUniqueId &uniqueId, 54 const char *emulatedFunctionDefinition) 55 { 56 mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition); 57 } 58 59 void BuiltInFunctionEmulator::addEmulatedFunctionWithDependency( 60 const TSymbolUniqueId &dependency, 61 const TSymbolUniqueId &uniqueId, 62 const char *emulatedFunctionDefinition) 63 { 64 mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition); 65 mFunctionDependencies[uniqueId.get()] = dependency.get(); 66 } 67 68 bool BuiltInFunctionEmulator::isOutputEmpty() const 69 { 70 return (mFunctions.size() == 0); 71 } 72 73 void BuiltInFunctionEmulator::outputEmulatedFunctions(TInfoSinkBase &out) const 74 { 75 for (const auto &function : mFunctions) 76 { 77 const char *body = findEmulatedFunction(function); 78 ASSERT(body); 79 out << body; 80 out << "\n\n"; 81 } 82 } 83 84 const char *BuiltInFunctionEmulator::findEmulatedFunction(int uniqueId) const 85 { 86 for (const auto &queryFunction : mQueryFunctions) 87 { 88 const char *result = queryFunction(uniqueId); 89 if (result) 90 { 91 return result; 92 } 93 } 94 95 const auto &result = mEmulatedFunctions.find(uniqueId); 96 if (result != mEmulatedFunctions.end()) 97 { 98 return result->second.c_str(); 99 } 100 101 return nullptr; 102 } 103 104 bool BuiltInFunctionEmulator::setFunctionCalled(const TFunction *function) 105 { 106 ASSERT(function != nullptr); 107 return setFunctionCalled(function->uniqueId().get()); 108 } 109 110 bool BuiltInFunctionEmulator::setFunctionCalled(int uniqueId) 111 { 112 if (!findEmulatedFunction(uniqueId)) 113 { 114 return false; 115 } 116 117 for (size_t i = 0; i < mFunctions.size(); ++i) 118 { 119 if (mFunctions[i] == uniqueId) 120 return true; 121 } 122 // If the function depends on another, mark the dependency as called. 123 auto dependency = mFunctionDependencies.find(uniqueId); 124 if (dependency != mFunctionDependencies.end()) 125 { 126 setFunctionCalled((*dependency).second); 127 } 128 mFunctions.push_back(uniqueId); 129 return true; 130 } 131 132 void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root) 133 { 134 ASSERT(root); 135 136 if (mEmulatedFunctions.empty() && mQueryFunctions.empty()) 137 return; 138 139 BuiltInFunctionEmulationMarker marker(*this); 140 root->traverse(&marker); 141 } 142 143 void BuiltInFunctionEmulator::cleanup() 144 { 145 mFunctions.clear(); 146 mFunctionDependencies.clear(); 147 } 148 149 void BuiltInFunctionEmulator::addFunctionMap(BuiltinQueryFunc queryFunc) 150 { 151 mQueryFunctions.push_back(queryFunc); 152 } 153 154 // static 155 void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name) 156 { 157 ASSERT(name[strlen(name) - 1] != '('); 158 out << name << "_emu"; 159 } 160 161 } // namespace sh