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 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 268 BuiltInFunctionEmulator::BuiltInFunctionEmulator(ShShaderType shaderType) 269 { 270 if (shaderType == SH_FRAGMENT_SHADER) { 271 mFunctionMask = kFunctionEmulationFragmentMask; 272 mFunctionSource = kFunctionEmulationFragmentSource; 273 } else { 274 mFunctionMask = kFunctionEmulationVertexMask; 275 mFunctionSource = kFunctionEmulationVertexSource; 276 } 277 } 278 279 bool BuiltInFunctionEmulator::SetFunctionCalled( 280 TOperator op, const TType& param) 281 { 282 TBuiltInFunction function = IdentifyFunction(op, param); 283 return SetFunctionCalled(function); 284 } 285 286 bool BuiltInFunctionEmulator::SetFunctionCalled( 287 TOperator op, const TType& param1, const TType& param2) 288 { 289 TBuiltInFunction function = IdentifyFunction(op, param1, param2); 290 return SetFunctionCalled(function); 291 } 292 293 bool BuiltInFunctionEmulator::SetFunctionCalled( 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 305 void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition( 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 385 void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation( 386 TIntermNode* root) 387 { 388 ASSERT(root); 389 390 BuiltInFunctionEmulationMarker marker(*this); 391 root->traverse(&marker); 392 } 393 394 void BuiltInFunctionEmulator::Cleanup() 395 { 396 mFunctions.clear(); 397 } 398 399 //static 400 TString BuiltInFunctionEmulator::GetEmulatedFunctionName( 401 const TString& name) 402 { 403 ASSERT(name[name.length() - 1] == '('); 404 return "webgl_" + name.substr(0, name.length() - 1) + "_emu("; 405 } 406 407