zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
BuiltInFunctionEmulator.cpp
Go to the documentation of this file.
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 
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 cos(float)",
20  "#error no emulation for cos(vec2)",
21  "#error no emulation for cos(vec3)",
22  "#error no emulation for cos(vec4)",
23 
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)",
28 
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)",
33 
34  "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
35  "#error no emulation for length(vec2)",
36  "#error no emulation for length(vec3)",
37  "#error no emulation for length(vec4)",
38 
39  "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
40  "#error no emulation for normalize(vec2)",
41  "#error no emulation for normalize(vec3)",
42  "#error no emulation for normalize(vec4)",
43 
44  "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
45  "#error no emulation for reflect(vec2, vec2)",
46  "#error no emulation for reflect(vec3, vec3)",
47  "#error no emulation for reflect(vec4, vec4)"
48 };
49 
50 const char* kFunctionEmulationFragmentSource[] = {
51  "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
52  "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
53  "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
54  "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
55 
56  "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
57  "#error no emulation for distance(vec2, vec2)",
58  "#error no emulation for distance(vec3, vec3)",
59  "#error no emulation for distance(vec4, vec4)",
60 
61  "#define webgl_dot_emu(x, y) ((x) * (y))",
62  "#error no emulation for dot(vec2, vec2)",
63  "#error no emulation for dot(vec3, vec3)",
64  "#error no emulation for dot(vec4, vec4)",
65 
66  "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
67  "#error no emulation for length(vec2)",
68  "#error no emulation for length(vec3)",
69  "#error no emulation for length(vec4)",
70 
71  "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
72  "#error no emulation for normalize(vec2)",
73  "#error no emulation for normalize(vec3)",
74  "#error no emulation for normalize(vec4)",
75 
76  "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
77  "#error no emulation for reflect(vec2, vec2)",
78  "#error no emulation for reflect(vec3, vec3)",
79  "#error no emulation for reflect(vec4, vec4)"
80 };
81 
82 const bool kFunctionEmulationVertexMask[] = {
83 #if defined(__APPLE__)
84  // Work around ATI driver bugs in Mac.
85  false, // TFunctionCos1
86  false, // TFunctionCos2
87  false, // TFunctionCos3
88  false, // TFunctionCos4
89  true, // TFunctionDistance1_1
90  false, // TFunctionDistance2_2
91  false, // TFunctionDistance3_3
92  false, // TFunctionDistance4_4
93  true, // TFunctionDot1_1
94  false, // TFunctionDot2_2
95  false, // TFunctionDot3_3
96  false, // TFunctionDot4_4
97  true, // TFunctionLength1
98  false, // TFunctionLength2
99  false, // TFunctionLength3
100  false, // TFunctionLength4
101  true, // TFunctionNormalize1
102  false, // TFunctionNormalize2
103  false, // TFunctionNormalize3
104  false, // TFunctionNormalize4
105  true, // TFunctionReflect1_1
106  false, // TFunctionReflect2_2
107  false, // TFunctionReflect3_3
108  false, // TFunctionReflect4_4
109 #else
110  // Work around D3D driver bug in Win.
111  false, // TFunctionCos1
112  false, // TFunctionCos2
113  false, // TFunctionCos3
114  false, // TFunctionCos4
115  false, // TFunctionDistance1_1
116  false, // TFunctionDistance2_2
117  false, // TFunctionDistance3_3
118  false, // TFunctionDistance4_4
119  false, // TFunctionDot1_1
120  false, // TFunctionDot2_2
121  false, // TFunctionDot3_3
122  false, // TFunctionDot4_4
123  false, // TFunctionLength1
124  false, // TFunctionLength2
125  false, // TFunctionLength3
126  false, // TFunctionLength4
127  false, // TFunctionNormalize1
128  false, // TFunctionNormalize2
129  false, // TFunctionNormalize3
130  false, // TFunctionNormalize4
131  false, // TFunctionReflect1_1
132  false, // TFunctionReflect2_2
133  false, // TFunctionReflect3_3
134  false, // TFunctionReflect4_4
135 #endif
136  false // TFunctionUnknown
137 };
138 
139 const bool kFunctionEmulationFragmentMask[] = {
140 #if defined(__APPLE__)
141  // Work around ATI driver bugs in Mac.
142  true, // TFunctionCos1
143  true, // TFunctionCos2
144  true, // TFunctionCos3
145  true, // TFunctionCos4
146  true, // TFunctionDistance1_1
147  false, // TFunctionDistance2_2
148  false, // TFunctionDistance3_3
149  false, // TFunctionDistance4_4
150  true, // TFunctionDot1_1
151  false, // TFunctionDot2_2
152  false, // TFunctionDot3_3
153  false, // TFunctionDot4_4
154  true, // TFunctionLength1
155  false, // TFunctionLength2
156  false, // TFunctionLength3
157  false, // TFunctionLength4
158  true, // TFunctionNormalize1
159  false, // TFunctionNormalize2
160  false, // TFunctionNormalize3
161  false, // TFunctionNormalize4
162  true, // TFunctionReflect1_1
163  false, // TFunctionReflect2_2
164  false, // TFunctionReflect3_3
165  false, // TFunctionReflect4_4
166 #else
167  // Work around D3D driver bug in Win.
168  false, // TFunctionCos1
169  false, // TFunctionCos2
170  false, // TFunctionCos3
171  false, // TFunctionCos4
172  false, // TFunctionDistance1_1
173  false, // TFunctionDistance2_2
174  false, // TFunctionDistance3_3
175  false, // TFunctionDistance4_4
176  false, // TFunctionDot1_1
177  false, // TFunctionDot2_2
178  false, // TFunctionDot3_3
179  false, // TFunctionDot4_4
180  false, // TFunctionLength1
181  false, // TFunctionLength2
182  false, // TFunctionLength3
183  false, // TFunctionLength4
184  false, // TFunctionNormalize1
185  false, // TFunctionNormalize2
186  false, // TFunctionNormalize3
187  false, // TFunctionNormalize4
188  false, // TFunctionReflect1_1
189  false, // TFunctionReflect2_2
190  false, // TFunctionReflect3_3
191  false, // TFunctionReflect4_4
192 #endif
193  false // TFunctionUnknown
194 };
195 
196 class BuiltInFunctionEmulationMarker : public TIntermTraverser {
197 public:
198  BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
199  : mEmulator(emulator)
200  {
201  }
202 
203  virtual bool visitUnary(Visit visit, TIntermUnary* node)
204  {
205  if (visit == PreVisit) {
206  bool needToEmulate = mEmulator.SetFunctionCalled(
207  node->getOp(), node->getOperand()->getType());
208  if (needToEmulate)
209  node->setUseEmulatedFunction();
210  }
211  return true;
212  }
213 
214  virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
215  {
216  if (visit == PreVisit) {
217  // Here we handle all the built-in functions instead of the ones we
218  // currently identified as problematic.
219  switch (node->getOp()) {
220  case EOpLessThan:
221  case EOpGreaterThan:
222  case EOpLessThanEqual:
223  case EOpGreaterThanEqual:
224  case EOpVectorEqual:
225  case EOpVectorNotEqual:
226  case EOpMod:
227  case EOpPow:
228  case EOpAtan:
229  case EOpMin:
230  case EOpMax:
231  case EOpClamp:
232  case EOpMix:
233  case EOpStep:
234  case EOpSmoothStep:
235  case EOpDistance:
236  case EOpDot:
237  case EOpCross:
238  case EOpFaceForward:
239  case EOpReflect:
240  case EOpRefract:
241  case EOpMul:
242  break;
243  default:
244  return true;
245  };
246  const TIntermSequence& sequence = node->getSequence();
247  // Right now we only handle built-in functions with two parameters.
248  if (sequence.size() != 2)
249  return true;
250  TIntermTyped* param1 = sequence[0]->getAsTyped();
251  TIntermTyped* param2 = sequence[1]->getAsTyped();
252  if (!param1 || !param2)
253  return true;
254  bool needToEmulate = mEmulator.SetFunctionCalled(
255  node->getOp(), param1->getType(), param2->getType());
256  if (needToEmulate)
257  node->setUseEmulatedFunction();
258  }
259  return true;
260  }
261 
262 private:
263  BuiltInFunctionEmulator& mEmulator;
264 };
265 
266 } // anonymous namepsace
267 
269 {
270  if (shaderType == SH_FRAGMENT_SHADER) {
271  mFunctionMask = kFunctionEmulationFragmentMask;
272  mFunctionSource = kFunctionEmulationFragmentSource;
273  } else {
274  mFunctionMask = kFunctionEmulationVertexMask;
275  mFunctionSource = kFunctionEmulationVertexSource;
276  }
277 }
278 
280  TOperator op, const TType& param)
281 {
282  TBuiltInFunction function = IdentifyFunction(op, param);
283  return SetFunctionCalled(function);
284 }
285 
287  TOperator op, const TType& param1, const TType& param2)
288 {
289  TBuiltInFunction function = IdentifyFunction(op, param1, param2);
290  return SetFunctionCalled(function);
291 }
292 
294  BuiltInFunctionEmulator::TBuiltInFunction function) {
295  if (function == TFunctionUnknown || mFunctionMask[function] == false)
296  return false;
297  for (size_t i = 0; i < mFunctions.size(); ++i) {
298  if (mFunctions[i] == function)
299  return true;
300  }
301  mFunctions.push_back(function);
302  return true;
303 }
304 
306  TInfoSinkBase& out, bool withPrecision) const
307 {
308  if (mFunctions.size() == 0)
309  return;
310  out << "// BEGIN: Generated code for built-in function emulation\n\n";
311  if (withPrecision) {
312  out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
313  << "#define webgl_emu_precision highp\n"
314  << "#else\n"
315  << "#define webgl_emu_precision mediump\n"
316  << "#endif\n\n";
317  } else {
318  out << "#define webgl_emu_precision\n\n";
319  }
320  for (size_t i = 0; i < mFunctions.size(); ++i) {
321  out << mFunctionSource[mFunctions[i]] << "\n\n";
322  }
323  out << "// END: Generated code for built-in function emulation\n\n";
324 }
325 
326 BuiltInFunctionEmulator::TBuiltInFunction
327 BuiltInFunctionEmulator::IdentifyFunction(
328  TOperator op, const TType& param)
329 {
330  if (param.getNominalSize() > 4)
331  return TFunctionUnknown;
332  unsigned int function = TFunctionUnknown;
333  switch (op) {
334  case EOpCos:
335  function = TFunctionCos1;
336  break;
337  case EOpLength:
338  function = TFunctionLength1;
339  break;
340  case EOpNormalize:
341  function = TFunctionNormalize1;
342  break;
343  default:
344  break;
345  }
346  if (function == TFunctionUnknown)
347  return TFunctionUnknown;
348  if (param.isVector())
349  function += param.getNominalSize() - 1;
350  return static_cast<TBuiltInFunction>(function);
351 }
352 
353 BuiltInFunctionEmulator::TBuiltInFunction
354 BuiltInFunctionEmulator::IdentifyFunction(
355  TOperator op, const TType& param1, const TType& param2)
356 {
357  // Right now for all the emulated functions with two parameters, the two
358  // parameters have the same type.
359  if (param1.isVector() != param2.isVector() ||
360  param1.getNominalSize() != param2.getNominalSize() ||
361  param1.getNominalSize() > 4)
362  return TFunctionUnknown;
363 
364  unsigned int function = TFunctionUnknown;
365  switch (op) {
366  case EOpDistance:
367  function = TFunctionDistance1_1;
368  break;
369  case EOpDot:
370  function = TFunctionDot1_1;
371  break;
372  case EOpReflect:
373  function = TFunctionReflect1_1;
374  break;
375  default:
376  break;
377  }
378  if (function == TFunctionUnknown)
379  return TFunctionUnknown;
380  if (param1.isVector())
381  function += param1.getNominalSize() - 1;
382  return static_cast<TBuiltInFunction>(function);
383 }
384 
386  TIntermNode* root)
387 {
388  ASSERT(root);
389 
390  BuiltInFunctionEmulationMarker marker(*this);
391  root->traverse(&marker);
392 }
393 
395 {
396  mFunctions.clear();
397 }
398 
399 //static
401  const TString& name)
402 {
403  ASSERT(name[name.length() - 1] == '(');
404  return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
405 }
406 
TOperator
Definition: intermediate.h:29
Visit
Definition: intermediate.h:524
TOperator getOp() const
Definition: intermediate.h:389
GLenum GLint param
Definition: gl2ext.h:1491
TIntermSequence & getSequence()
Definition: intermediate.h:469
const GLchar * marker
Definition: gl2ext.h:1092
int getNominalSize() const
Definition: Types.h:118
EGLImageKHR EGLint * name
Definition: eglext.h:284
Definition: Types.h:93
bool SetFunctionCalled(TOperator op, const TType &param)
void setUseEmulatedFunction()
Definition: intermediate.h:443
static TString GetEmulatedFunctionName(const TString &name)
#define ASSERT(expression)
Definition: debug.h:36
virtual void traverse(TIntermTraverser *)=0
const TType & getType() const
Definition: intermediate.h:251
bool isVector() const
Definition: Types.h:167
TIntermTyped * getOperand()
Definition: intermediate.h:440
std::basic_string< char, std::char_traits< char >, TStringAllocator > TString
Definition: Common.h:41
BuiltInFunctionEmulator(ShShaderType shaderType)
void setUseEmulatedFunction()
Definition: intermediate.h:482
ShShaderType
Definition: ShaderLang.h:48
void MarkBuiltInFunctionsForEmulation(TIntermNode *root)
int i
Definition: pngrutil.c:1377
void OutputEmulatedFunctionDefinition(TInfoSinkBase &out, bool withPrecision) const