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:
BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator & emulator)18 BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
19 : TIntermTraverser(true, false, false), mEmulator(emulator)
20 {}
21
visitUnary(Visit visit,TIntermUnary * node)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
visitAggregate(Visit visit,TIntermAggregate * node)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
BuiltInFunctionEmulator()51 BuiltInFunctionEmulator::BuiltInFunctionEmulator() {}
52
addEmulatedFunction(const TSymbolUniqueId & uniqueId,const char * emulatedFunctionDefinition)53 void BuiltInFunctionEmulator::addEmulatedFunction(const TSymbolUniqueId &uniqueId,
54 const char *emulatedFunctionDefinition)
55 {
56 mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition);
57 }
58
addEmulatedFunctionWithDependency(const TSymbolUniqueId & dependency,const TSymbolUniqueId & uniqueId,const char * emulatedFunctionDefinition)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
isOutputEmpty() const68 bool BuiltInFunctionEmulator::isOutputEmpty() const
69 {
70 return (mFunctions.size() == 0);
71 }
72
outputEmulatedFunctions(TInfoSinkBase & out) const73 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
findEmulatedFunction(int uniqueId) const84 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
setFunctionCalled(const TFunction * function)104 bool BuiltInFunctionEmulator::setFunctionCalled(const TFunction *function)
105 {
106 ASSERT(function != nullptr);
107 return setFunctionCalled(function->uniqueId().get());
108 }
109
setFunctionCalled(int uniqueId)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
markBuiltInFunctionsForEmulation(TIntermNode * root)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
cleanup()143 void BuiltInFunctionEmulator::cleanup()
144 {
145 mFunctions.clear();
146 mFunctionDependencies.clear();
147 }
148
addFunctionMap(BuiltinQueryFunc queryFunc)149 void BuiltInFunctionEmulator::addFunctionMap(BuiltinQueryFunc queryFunc)
150 {
151 mQueryFunctions.push_back(queryFunc);
152 }
153
154 // static
WriteEmulatedFunctionName(TInfoSinkBase & out,const char * name)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
162