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/BuiltInFunctionEmulator.h"
8 :
9 : #include "compiler/SymbolTable.h"
10 :
11 : namespace {
12 :
13 : // we use macros here instead of function definitions to work around more GLSL
14 : // compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
15 : // problematic because if the argument has side-effects they will be repeatedly
16 : // evaluated. This is unlikely to show up in real shaders, but is something to
17 : // consider.
18 : const char* kFunctionEmulationVertexSource[] = {
19 : "#error no emulation for atan(float, float)",
20 : "vec2 webgl_atan_emu(vec2 y, vec2 x) { return vec2(atan(y[0], x[0]), atan(y[1], x[1])); }",
21 : "vec3 webgl_atan_emu(vec3 y, vec3 x) { return vec3(atan(y[0], x[0]), atan(y[1], x[1]), atan(y[2], x[2])); }",
22 : "vec4 webgl_atan_emu(vec4 y, vec4 x) { return vec4(atan(y[0], x[0]), atan(y[1], x[1]), atan(y[2], x[2]), atan(y[3], x[3])); }",
23 :
24 : "#error no emulation for cos(float)",
25 : "#error no emulation for cos(vec2)",
26 : "#error no emulation for cos(vec3)",
27 : "#error no emulation for cos(vec4)",
28 :
29 : "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
30 : "#error no emulation for distance(vec2, vec2)",
31 : "#error no emulation for distance(vec3, vec3)",
32 : "#error no emulation for distance(vec4, vec4)",
33 :
34 : "#define webgl_dot_emu(x, y) ((x) * (y))",
35 : "#error no emulation for dot(vec2, vec2)",
36 : "#error no emulation for dot(vec3, vec3)",
37 : "#error no emulation for dot(vec4, vec4)",
38 :
39 : "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
40 : "#error no emulation for length(vec2)",
41 : "#error no emulation for length(vec3)",
42 : "#error no emulation for length(vec4)",
43 :
44 : "#error no emulation for mod(float, float)",
45 : "vec2 webgl_mod_emu(vec2 x, vec2 y) { return vec2(mod(x[0], y[0]), mod(x[1], y[1])); }",
46 : "vec3 webgl_mod_emu(vec3 x, vec3 y) { return vec3(mod(x[0], y[0]), mod(x[1], y[1]), mod(x[2], y[2])); }",
47 : "vec4 webgl_mod_emu(vec4 x, vec4 y) { return vec4(mod(x[0], y[0]), mod(x[1], y[1]), mod(x[2], y[2]), mod(x[3], y[3])); }",
48 :
49 : "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
50 : "#error no emulation for normalize(vec2)",
51 : "#error no emulation for normalize(vec3)",
52 : "#error no emulation for normalize(vec4)",
53 :
54 : "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
55 : "#error no emulation for reflect(vec2, vec2)",
56 : "#error no emulation for reflect(vec3, vec3)",
57 : "#error no emulation for reflect(vec4, vec4)"
58 : };
59 :
60 : const char* kFunctionEmulationFragmentSource[] = {
61 : "#error no emulation for atan(float, float)",
62 : "#error no emulation for atan(vec2, vec2)",
63 : "#error no emulation for atan(vec3, vec3)",
64 : "#error no emulation for atan(vec4, vec4)",
65 :
66 : "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
67 : "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
68 : "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
69 : "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
70 :
71 : "#error no emulation for distance(float, float)",
72 : "#error no emulation for distance(vec2, vec2)",
73 : "#error no emulation for distance(vec3, vec3)",
74 : "#error no emulation for distance(vec4, vec4)",
75 :
76 : "#error no emulation for dot(float, float)",
77 : "#error no emulation for dot(vec2, vec2)",
78 : "#error no emulation for dot(vec3, vec3)",
79 : "#error no emulation for dot(vec4, vec4)",
80 :
81 : "#error no emulation for length(float)",
82 : "#error no emulation for length(vec2)",
83 : "#error no emulation for length(vec3)",
84 : "#error no emulation for length(vec4)",
85 :
86 : "#error no emulation for mod(float, float)",
87 : "#error no emulation for mod(vec2, vec2)",
88 : "#error no emulation for mod(vec3, vec3)",
89 : "#error no emulation for mod(vec4, vec4)",
90 :
91 : "#error no emulation for normalize(float)",
92 : "#error no emulation for normalize(vec2)",
93 : "#error no emulation for normalize(vec3)",
94 : "#error no emulation for normalize(vec4)",
95 :
96 : "#error no emulation for reflect(float, float)",
97 : "#error no emulation for reflect(vec2, vec2)",
98 : "#error no emulation for reflect(vec3, vec3)",
99 : "#error no emulation for reflect(vec4, vec4)"
100 : };
101 :
102 : const bool kFunctionEmulationVertexMask[] = {
103 : #if defined(__APPLE__)
104 : // Work around ATI driver bugs in Mac.
105 : false, // TFunctionAtan1_1
106 : false, // TFunctionAtan2_2
107 : false, // TFunctionAtan3_3
108 : false, // TFunctionAtan4_4
109 : false, // TFunctionCos1
110 : false, // TFunctionCos2
111 : false, // TFunctionCos3
112 : false, // TFunctionCos4
113 : true, // TFunctionDistance1_1
114 : false, // TFunctionDistance2_2
115 : false, // TFunctionDistance3_3
116 : false, // TFunctionDistance4_4
117 : true, // TFunctionDot1_1
118 : false, // TFunctionDot2_2
119 : false, // TFunctionDot3_3
120 : false, // TFunctionDot4_4
121 : true, // TFunctionLength1
122 : false, // TFunctionLength2
123 : false, // TFunctionLength3
124 : false, // TFunctionLength4
125 : false, // TFunctionMod1_1
126 : false, // TFunctionMod2_2
127 : false, // TFunctionMod3_3
128 : false, // TFunctionMod4_4
129 : true, // TFunctionNormalize1
130 : false, // TFunctionNormalize2
131 : false, // TFunctionNormalize3
132 : false, // TFunctionNormalize4
133 : true, // TFunctionReflect1_1
134 : false, // TFunctionReflect2_2
135 : false, // TFunctionReflect3_3
136 : false, // TFunctionReflect4_4
137 : #else
138 : // Work around D3D driver bug in Win.
139 : false, // TFunctionAtan1_1
140 : true, // TFunctionAtan2_2
141 : true, // TFunctionAtan3_3
142 : true, // TFunctionAtan4_4
143 : false, // TFunctionCos1
144 : false, // TFunctionCos2
145 : false, // TFunctionCos3
146 : false, // TFunctionCos4
147 : false, // TFunctionDistance1_1
148 : false, // TFunctionDistance2_2
149 : false, // TFunctionDistance3_3
150 : false, // TFunctionDistance4_4
151 : false, // TFunctionDot1_1
152 : false, // TFunctionDot2_2
153 : false, // TFunctionDot3_3
154 : false, // TFunctionDot4_4
155 : false, // TFunctionLength1
156 : false, // TFunctionLength2
157 : false, // TFunctionLength3
158 : false, // TFunctionLength4
159 : false, // TFunctionMod1_1
160 : true, // TFunctionMod2_2
161 : true, // TFunctionMod3_3
162 : true, // TFunctionMod4_4
163 : false, // TFunctionNormalize1
164 : false, // TFunctionNormalize2
165 : false, // TFunctionNormalize3
166 : false, // TFunctionNormalize4
167 : false, // TFunctionReflect1_1
168 : false, // TFunctionReflect2_2
169 : false, // TFunctionReflect3_3
170 : false, // TFunctionReflect4_4
171 : #endif
172 : false // TFunctionUnknown
173 : };
174 :
175 : const bool kFunctionEmulationFragmentMask[] = {
176 : false, // TFunctionAtan1_1
177 : false, // TFunctionAtan2_2
178 : false, // TFunctionAtan3_3
179 : false, // TFunctionAtan4_4
180 : #if defined(__APPLE__)
181 : // Work around a ATI driver bug in Mac that causes crashes.
182 : true, // TFunctionCos1
183 : true, // TFunctionCos2
184 : true, // TFunctionCos3
185 : true, // TFunctionCos4
186 : #else
187 : false, // TFunctionCos1
188 : false, // TFunctionCos2
189 : false, // TFunctionCos3
190 : false, // TFunctionCos4
191 : #endif
192 : false, // TFunctionDistance1_1
193 : false, // TFunctionDistance2_2
194 : false, // TFunctionDistance3_3
195 : false, // TFunctionDistance4_4
196 : false, // TFunctionDot1_1
197 : false, // TFunctionDot2_2
198 : false, // TFunctionDot3_3
199 : false, // TFunctionDot4_4
200 : false, // TFunctionLength1
201 : false, // TFunctionLength2
202 : false, // TFunctionLength3
203 : false, // TFunctionLength4
204 : false, // TFunctionMod1_1
205 : false, // TFunctionMod2_2
206 : false, // TFunctionMod3_3
207 : false, // TFunctionMod4_4
208 : false, // TFunctionNormalize1
209 : false, // TFunctionNormalize2
210 : false, // TFunctionNormalize3
211 : false, // TFunctionNormalize4
212 : false, // TFunctionReflect1_1
213 : false, // TFunctionReflect2_2
214 : false, // TFunctionReflect3_3
215 : false, // TFunctionReflect4_4
216 : false // TFunctionUnknown
217 : };
218 :
219 : class BuiltInFunctionEmulationMarker : public TIntermTraverser {
220 : public:
221 0 : BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
222 0 : : mEmulator(emulator)
223 : {
224 0 : }
225 :
226 0 : virtual bool visitUnary(Visit visit, TIntermUnary* node)
227 : {
228 0 : if (visit == PreVisit) {
229 : bool needToEmulate = mEmulator.SetFunctionCalled(
230 0 : node->getOp(), node->getOperand()->getType());
231 0 : if (needToEmulate)
232 0 : node->setUseEmulatedFunction();
233 : }
234 0 : return true;
235 : }
236 :
237 0 : virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
238 : {
239 0 : if (visit == PreVisit) {
240 : // Here we handle all the built-in functions instead of the ones we
241 : // currently identified as problematic.
242 0 : switch (node->getOp()) {
243 : case EOpLessThan:
244 : case EOpGreaterThan:
245 : case EOpLessThanEqual:
246 : case EOpGreaterThanEqual:
247 : case EOpVectorEqual:
248 : case EOpVectorNotEqual:
249 : case EOpMod:
250 : case EOpPow:
251 : case EOpAtan:
252 : case EOpMin:
253 : case EOpMax:
254 : case EOpClamp:
255 : case EOpMix:
256 : case EOpStep:
257 : case EOpSmoothStep:
258 : case EOpDistance:
259 : case EOpDot:
260 : case EOpCross:
261 : case EOpFaceForward:
262 : case EOpReflect:
263 : case EOpRefract:
264 : case EOpMul:
265 : break;
266 : default:
267 0 : return true;
268 : };
269 0 : const TIntermSequence& sequence = node->getSequence();
270 : // Right now we only handle built-in functions with two parameters.
271 0 : if (sequence.size() != 2)
272 0 : return true;
273 0 : TIntermTyped* param1 = sequence[0]->getAsTyped();
274 0 : TIntermTyped* param2 = sequence[1]->getAsTyped();
275 0 : if (!param1 || !param2)
276 0 : return true;
277 : bool needToEmulate = mEmulator.SetFunctionCalled(
278 0 : node->getOp(), param1->getType(), param2->getType());
279 0 : if (needToEmulate)
280 0 : node->setUseEmulatedFunction();
281 : }
282 0 : return true;
283 : }
284 :
285 : private:
286 : BuiltInFunctionEmulator& mEmulator;
287 : };
288 :
289 : } // anonymous namepsace
290 :
291 0 : BuiltInFunctionEmulator::BuiltInFunctionEmulator(ShShaderType shaderType)
292 : {
293 0 : if (shaderType == SH_FRAGMENT_SHADER) {
294 0 : mFunctionMask = kFunctionEmulationFragmentMask;
295 0 : mFunctionSource = kFunctionEmulationFragmentSource;
296 : } else {
297 0 : mFunctionMask = kFunctionEmulationVertexMask;
298 0 : mFunctionSource = kFunctionEmulationVertexSource;
299 : }
300 0 : }
301 :
302 0 : bool BuiltInFunctionEmulator::SetFunctionCalled(
303 : TOperator op, const TType& param)
304 : {
305 0 : TBuiltInFunction function = IdentifyFunction(op, param);
306 0 : return SetFunctionCalled(function);
307 : }
308 :
309 0 : bool BuiltInFunctionEmulator::SetFunctionCalled(
310 : TOperator op, const TType& param1, const TType& param2)
311 : {
312 0 : TBuiltInFunction function = IdentifyFunction(op, param1, param2);
313 0 : return SetFunctionCalled(function);
314 : }
315 :
316 0 : bool BuiltInFunctionEmulator::SetFunctionCalled(
317 : BuiltInFunctionEmulator::TBuiltInFunction function) {
318 0 : if (function == TFunctionUnknown || mFunctionMask[function] == false)
319 0 : return false;
320 0 : for (size_t i = 0; i < mFunctions.size(); ++i) {
321 0 : if (mFunctions[i] == function)
322 0 : return true;
323 : }
324 0 : mFunctions.push_back(function);
325 0 : return true;
326 : }
327 :
328 0 : void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
329 : TInfoSinkBase& out, bool withPrecision) const
330 : {
331 0 : if (mFunctions.size() == 0)
332 0 : return;
333 0 : out << "// BEGIN: Generated code for built-in function emulation\n\n";
334 0 : if (withPrecision) {
335 0 : out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
336 0 : << "#define webgl_emu_precision highp\n"
337 0 : << "#else\n"
338 0 : << "#define webgl_emu_precision mediump\n"
339 0 : << "#endif\n\n";
340 : } else {
341 0 : out << "#define webgl_emu_precision\n\n";
342 : }
343 0 : for (size_t i = 0; i < mFunctions.size(); ++i) {
344 0 : out << mFunctionSource[mFunctions[i]] << "\n\n";
345 : }
346 0 : out << "// END: Generated code for built-in function emulation\n\n";
347 : }
348 :
349 : BuiltInFunctionEmulator::TBuiltInFunction
350 0 : BuiltInFunctionEmulator::IdentifyFunction(
351 : TOperator op, const TType& param)
352 : {
353 0 : if (param.getNominalSize() > 4)
354 0 : return TFunctionUnknown;
355 0 : unsigned int function = TFunctionUnknown;
356 0 : switch (op) {
357 : case EOpCos:
358 0 : function = TFunctionCos1;
359 0 : break;
360 : case EOpLength:
361 0 : function = TFunctionLength1;
362 0 : break;
363 : case EOpNormalize:
364 0 : function = TFunctionNormalize1;
365 0 : break;
366 : default:
367 0 : break;
368 : }
369 0 : if (function == TFunctionUnknown)
370 0 : return TFunctionUnknown;
371 0 : if (param.isVector())
372 0 : function += param.getNominalSize() - 1;
373 0 : return static_cast<TBuiltInFunction>(function);
374 : }
375 :
376 : BuiltInFunctionEmulator::TBuiltInFunction
377 0 : BuiltInFunctionEmulator::IdentifyFunction(
378 : TOperator op, const TType& param1, const TType& param2)
379 : {
380 : // Right now for all the emulated functions with two parameters, the two
381 : // parameters have the same type.
382 0 : if (param1.isVector() != param2.isVector() ||
383 0 : param1.getNominalSize() != param2.getNominalSize() ||
384 0 : param1.getNominalSize() > 4)
385 0 : return TFunctionUnknown;
386 :
387 0 : unsigned int function = TFunctionUnknown;
388 0 : switch (op) {
389 : case EOpAtan:
390 0 : function = TFunctionAtan1_1;
391 0 : break;
392 : case EOpDistance:
393 0 : function = TFunctionDistance1_1;
394 0 : break;
395 : case EOpDot:
396 0 : function = TFunctionDot1_1;
397 0 : break;
398 : case EOpMod:
399 0 : function = TFunctionMod1_1;
400 0 : break;
401 : case EOpReflect:
402 0 : function = TFunctionReflect1_1;
403 0 : break;
404 : default:
405 0 : break;
406 : }
407 0 : if (function == TFunctionUnknown)
408 0 : return TFunctionUnknown;
409 0 : if (param1.isVector())
410 0 : function += param1.getNominalSize() - 1;
411 0 : return static_cast<TBuiltInFunction>(function);
412 : }
413 :
414 0 : void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
415 : TIntermNode* root)
416 : {
417 0 : ASSERT(root);
418 :
419 0 : BuiltInFunctionEmulationMarker marker(*this);
420 0 : root->traverse(&marker);
421 0 : }
422 :
423 0 : void BuiltInFunctionEmulator::Cleanup()
424 : {
425 0 : mFunctions.clear();
426 0 : }
427 :
428 : //static
429 0 : TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
430 : const TString& name)
431 : {
432 0 : ASSERT(name[name.length() - 1] == '(');
433 0 : return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
434 : }
435 :
|