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