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