Line data Source code
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 "angle_gl.h"
8 : #include "compiler/translator/BuiltInFunctionEmulator.h"
9 : #include "compiler/translator/SymbolTable.h"
10 : #include "compiler/translator/Cache.h"
11 :
12 : namespace sh
13 : {
14 :
15 0 : class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
16 : {
17 : public:
18 0 : BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
19 0 : : TIntermTraverser(true, false, false),
20 0 : mEmulator(emulator)
21 : {
22 0 : }
23 :
24 0 : bool visitUnary(Visit visit, TIntermUnary *node) override
25 : {
26 0 : if (visit == PreVisit)
27 : {
28 0 : bool needToEmulate = mEmulator.SetFunctionCalled(node->getOp(), node->getOperand()->getType());
29 0 : if (needToEmulate)
30 0 : node->setUseEmulatedFunction();
31 : }
32 0 : return true;
33 : }
34 :
35 0 : bool visitAggregate(Visit visit, TIntermAggregate *node) override
36 : {
37 0 : if (visit == PreVisit)
38 : {
39 : // Here we handle all the built-in functions instead of the ones we
40 : // currently identified as problematic.
41 0 : switch (node->getOp())
42 : {
43 : case EOpLessThan:
44 : case EOpGreaterThan:
45 : case EOpLessThanEqual:
46 : case EOpGreaterThanEqual:
47 : case EOpVectorEqual:
48 : case EOpVectorNotEqual:
49 : case EOpMod:
50 : case EOpPow:
51 : case EOpAtan:
52 : case EOpMin:
53 : case EOpMax:
54 : case EOpClamp:
55 : case EOpMix:
56 : case EOpStep:
57 : case EOpSmoothStep:
58 : case EOpDistance:
59 : case EOpDot:
60 : case EOpCross:
61 : case EOpFaceForward:
62 : case EOpReflect:
63 : case EOpRefract:
64 : case EOpOuterProduct:
65 : case EOpMul:
66 0 : break;
67 : default:
68 0 : return true;
69 : }
70 0 : const TIntermSequence &sequence = *(node->getSequence());
71 0 : bool needToEmulate = false;
72 : // Right now we only handle built-in functions with two or three parameters.
73 0 : if (sequence.size() == 2)
74 : {
75 0 : TIntermTyped *param1 = sequence[0]->getAsTyped();
76 0 : TIntermTyped *param2 = sequence[1]->getAsTyped();
77 0 : if (!param1 || !param2)
78 0 : return true;
79 0 : needToEmulate = mEmulator.SetFunctionCalled(
80 0 : node->getOp(), param1->getType(), param2->getType());
81 : }
82 0 : else if (sequence.size() == 3)
83 : {
84 0 : TIntermTyped *param1 = sequence[0]->getAsTyped();
85 0 : TIntermTyped *param2 = sequence[1]->getAsTyped();
86 0 : TIntermTyped *param3 = sequence[2]->getAsTyped();
87 0 : if (!param1 || !param2 || !param3)
88 0 : return true;
89 0 : needToEmulate = mEmulator.SetFunctionCalled(
90 0 : node->getOp(), param1->getType(), param2->getType(), param3->getType());
91 : }
92 : else
93 : {
94 0 : return true;
95 : }
96 :
97 0 : if (needToEmulate)
98 0 : node->setUseEmulatedFunction();
99 : }
100 0 : return true;
101 : }
102 :
103 : private:
104 : BuiltInFunctionEmulator &mEmulator;
105 : };
106 :
107 0 : BuiltInFunctionEmulator::BuiltInFunctionEmulator()
108 0 : {}
109 :
110 0 : void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param,
111 : const char *emulatedFunctionDefinition)
112 : {
113 0 : mEmulatedFunctions[FunctionId(op, param)] = std::string(emulatedFunctionDefinition);
114 0 : }
115 :
116 0 : void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2,
117 : const char *emulatedFunctionDefinition)
118 : {
119 0 : mEmulatedFunctions[FunctionId(op, param1, param2)] = std::string(emulatedFunctionDefinition);
120 0 : }
121 :
122 0 : void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2,
123 : const TType *param3, const char *emulatedFunctionDefinition)
124 : {
125 0 : mEmulatedFunctions[FunctionId(op, param1, param2, param3)] = std::string(emulatedFunctionDefinition);
126 0 : }
127 :
128 0 : bool BuiltInFunctionEmulator::IsOutputEmpty() const
129 : {
130 0 : return (mFunctions.size() == 0);
131 : }
132 :
133 0 : void BuiltInFunctionEmulator::OutputEmulatedFunctions(TInfoSinkBase &out) const
134 : {
135 0 : for (size_t i = 0; i < mFunctions.size(); ++i)
136 : {
137 0 : out << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n";
138 : }
139 0 : }
140 :
141 0 : bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType ¶m)
142 : {
143 0 : return SetFunctionCalled(FunctionId(op, ¶m));
144 : }
145 :
146 0 : bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType ¶m1, const TType ¶m2)
147 : {
148 0 : return SetFunctionCalled(FunctionId(op, ¶m1, ¶m2));
149 : }
150 :
151 0 : bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op,
152 : const TType ¶m1, const TType ¶m2, const TType ¶m3)
153 : {
154 0 : return SetFunctionCalled(FunctionId(op, ¶m1, ¶m2, ¶m3));
155 : }
156 :
157 0 : bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId)
158 : {
159 0 : if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end())
160 : {
161 0 : for (size_t i = 0; i < mFunctions.size(); ++i)
162 : {
163 0 : if (mFunctions[i] == functionId)
164 0 : return true;
165 : }
166 : // Copy the functionId if it needs to be stored, to make sure that the TType pointers inside
167 : // remain valid and constant.
168 0 : mFunctions.push_back(functionId.getCopy());
169 0 : return true;
170 : }
171 0 : return false;
172 : }
173 :
174 0 : void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(TIntermNode *root)
175 : {
176 0 : ASSERT(root);
177 :
178 0 : if (mEmulatedFunctions.empty())
179 0 : return;
180 :
181 0 : BuiltInFunctionEmulationMarker marker(*this);
182 0 : root->traverse(&marker);
183 : }
184 :
185 0 : void BuiltInFunctionEmulator::Cleanup()
186 : {
187 0 : mFunctions.clear();
188 0 : }
189 :
190 : //static
191 0 : TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
192 : const TString &name)
193 : {
194 0 : ASSERT(name[name.length() - 1] == '(');
195 0 : return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
196 : }
197 :
198 0 : BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param)
199 : : mOp(op),
200 : mParam1(param),
201 0 : mParam2(TCache::getType(EbtVoid)),
202 0 : mParam3(TCache::getType(EbtVoid))
203 : {
204 0 : }
205 :
206 0 : BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2)
207 : : mOp(op),
208 : mParam1(param1),
209 : mParam2(param2),
210 0 : mParam3(TCache::getType(EbtVoid))
211 : {
212 0 : }
213 :
214 0 : BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op,
215 0 : const TType *param1, const TType *param2, const TType *param3)
216 : : mOp(op),
217 : mParam1(param1),
218 : mParam2(param2),
219 0 : mParam3(param3)
220 : {
221 0 : }
222 :
223 0 : bool BuiltInFunctionEmulator::FunctionId::operator==(const BuiltInFunctionEmulator::FunctionId &other) const
224 : {
225 0 : return (mOp == other.mOp &&
226 0 : *mParam1 == *other.mParam1 &&
227 0 : *mParam2 == *other.mParam2 &&
228 0 : *mParam3 == *other.mParam3);
229 : }
230 :
231 0 : bool BuiltInFunctionEmulator::FunctionId::operator<(const BuiltInFunctionEmulator::FunctionId &other) const
232 : {
233 0 : if (mOp != other.mOp)
234 0 : return mOp < other.mOp;
235 0 : if (*mParam1 != *other.mParam1)
236 0 : return *mParam1 < *other.mParam1;
237 0 : if (*mParam2 != *other.mParam2)
238 0 : return *mParam2 < *other.mParam2;
239 0 : if (*mParam3 != *other.mParam3)
240 0 : return *mParam3 < *other.mParam3;
241 0 : return false; // all fields are equal
242 : }
243 :
244 0 : BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::FunctionId::getCopy() const
245 : {
246 0 : return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3));
247 : }
248 :
249 : } // namespace sh
|