Emulate certain buil-in functions to work around driver bugs.

This is implemented by adding a new compile option SH_EMULATE_BUILT_IN_FUNCTIONS.  The emulated functions are names as webgl_originalName_emu so there will never be naming conflicts.

At the moment only three functions are emulated: normalize, abs, sign.  Also, the compile option will emulate all three.  However, the mechanism to emulate only a selected subset is also imeplemented.  It can be turned on easily.

ANGLEBUG=196
TEST=with this option, the failed test with abs.frag passes.
Review URL: http://codereview.appspot.com/4916043

git-svn-id: https://angleproject.googlecode.com/svn/trunk@738 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/OutputGLSLBase.cpp b/src/compiler/OutputGLSLBase.cpp
index eccc54b..36d054e 100644
--- a/src/compiler/OutputGLSLBase.cpp
+++ b/src/compiler/OutputGLSLBase.cpp
@@ -305,25 +305,28 @@
 
 bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
 {
+    TString preString;
+    TString postString = ")";
+
     switch (node->getOp())
     {
-        case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
-        case EOpVectorLogicalNot: writeTriplet(visit, "not(", NULL, ")"); break;
-        case EOpLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break;
+        case EOpNegative: preString = "(-"; break;
+        case EOpVectorLogicalNot: preString = "not("; break;
+        case EOpLogicalNot: preString = "(!"; break;
 
-        case EOpPostIncrement: writeTriplet(visit, "(", NULL, "++)"); break;
-        case EOpPostDecrement: writeTriplet(visit, "(", NULL, "--)"); break;
-        case EOpPreIncrement: writeTriplet(visit, "(++", NULL, ")"); break;
-        case EOpPreDecrement: writeTriplet(visit, "(--", NULL, ")"); break;
+        case EOpPostIncrement: preString = "("; postString = "++)"; break;
+        case EOpPostDecrement: preString = "("; postString = "--)"; break;
+        case EOpPreIncrement: preString = "(++"; break;
+        case EOpPreDecrement: preString = "(--"; break;
 
         case EOpConvIntToBool:
         case EOpConvFloatToBool:
             switch (node->getOperand()->getType().getNominalSize())
             {
-                case 1: writeTriplet(visit, "bool(", NULL, ")");  break;
-                case 2: writeTriplet(visit, "bvec2(", NULL, ")"); break;
-                case 3: writeTriplet(visit, "bvec3(", NULL, ")"); break;
-                case 4: writeTriplet(visit, "bvec4(", NULL, ")"); break;
+                case 1: preString =  "bool(";  break;
+                case 2: preString = "bvec2("; break;
+                case 3: preString = "bvec3("; break;
+                case 4: preString = "bvec4("; break;
                 default: UNREACHABLE();
             }
             break;
@@ -331,10 +334,10 @@
         case EOpConvIntToFloat:
             switch (node->getOperand()->getType().getNominalSize())
             {
-                case 1: writeTriplet(visit, "float(", NULL, ")");  break;
-                case 2: writeTriplet(visit, "vec2(", NULL, ")"); break;
-                case 3: writeTriplet(visit, "vec3(", NULL, ")"); break;
-                case 4: writeTriplet(visit, "vec4(", NULL, ")"); break;
+                case 1: preString = "float(";  break;
+                case 2: preString = "vec2("; break;
+                case 3: preString = "vec3("; break;
+                case 4: preString = "vec4("; break;
                 default: UNREACHABLE();
             }
             break;
@@ -342,49 +345,53 @@
         case EOpConvBoolToInt:
             switch (node->getOperand()->getType().getNominalSize())
             {
-                case 1: writeTriplet(visit, "int(", NULL, ")");  break;
-                case 2: writeTriplet(visit, "ivec2(", NULL, ")"); break;
-                case 3: writeTriplet(visit, "ivec3(", NULL, ")"); break;
-                case 4: writeTriplet(visit, "ivec4(", NULL, ")"); break;
+                case 1: preString = "int(";  break;
+                case 2: preString = "ivec2("; break;
+                case 3: preString = "ivec3("; break;
+                case 4: preString = "ivec4("; break;
                 default: UNREACHABLE();
             }
             break;
 
-        case EOpRadians: writeTriplet(visit, "radians(", NULL, ")"); break;
-        case EOpDegrees: writeTriplet(visit, "degrees(", NULL, ")"); break;
-        case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
-        case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
-        case EOpTan: writeTriplet(visit, "tan(", NULL, ")"); break;
-        case EOpAsin: writeTriplet(visit, "asin(", NULL, ")"); break;
-        case EOpAcos: writeTriplet(visit, "acos(", NULL, ")"); break;
-        case EOpAtan: writeTriplet(visit, "atan(", NULL, ")"); break;
+        case EOpRadians: preString = "radians("; break;
+        case EOpDegrees: preString = "degrees("; break;
+        case EOpSin: preString = "sin("; break;
+        case EOpCos: preString = "cos("; break;
+        case EOpTan: preString = "tan("; break;
+        case EOpAsin: preString = "asin("; break;
+        case EOpAcos: preString = "acos("; break;
+        case EOpAtan: preString = "atan("; break;
 
-        case EOpExp: writeTriplet(visit, "exp(", NULL, ")"); break;
-        case EOpLog: writeTriplet(visit, "log(", NULL, ")"); break;
-        case EOpExp2: writeTriplet(visit, "exp2(", NULL, ")"); break;
-        case EOpLog2: writeTriplet(visit, "log2(", NULL, ")"); break;
-        case EOpSqrt: writeTriplet(visit, "sqrt(", NULL, ")"); break;
-        case EOpInverseSqrt: writeTriplet(visit, "inversesqrt(", NULL, ")"); break;
+        case EOpExp: preString = "exp("; break;
+        case EOpLog: preString = "log("; break;
+        case EOpExp2: preString = "exp2("; break;
+        case EOpLog2: preString = "log2("; break;
+        case EOpSqrt: preString = "sqrt("; break;
+        case EOpInverseSqrt: preString = "inversesqrt("; break;
 
-        case EOpAbs: writeTriplet(visit, "abs(", NULL, ")"); break;
-        case EOpSign: writeTriplet(visit, "sign(", NULL, ")"); break;
-        case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
-        case EOpCeil: writeTriplet(visit, "ceil(", NULL, ")"); break;
-        case EOpFract: writeTriplet(visit, "fract(", NULL, ")"); break;
+        case EOpAbs: preString = "abs("; break;
+        case EOpSign: preString = "sign("; break;
+        case EOpFloor: preString = "floor("; break;
+        case EOpCeil: preString = "ceil("; break;
+        case EOpFract: preString = "fract("; break;
 
-        case EOpLength: writeTriplet(visit, "length(", NULL, ")"); break;
-        case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
+        case EOpLength: preString = "length("; break;
+        case EOpNormalize: preString = "normalize("; break;
 
-        case EOpDFdx: writeTriplet(visit, "dFdx(", NULL, ")"); break;
-        case EOpDFdy: writeTriplet(visit, "dFdy(", NULL, ")"); break;
-        case EOpFwidth: writeTriplet(visit, "fwidth(", NULL, ")"); break;
+        case EOpDFdx: preString = "dFdx("; break;
+        case EOpDFdy: preString = "dFdy("; break;
+        case EOpFwidth: preString = "fwidth("; break;
 
-        case EOpAny: writeTriplet(visit, "any(", NULL, ")"); break;
-        case EOpAll: writeTriplet(visit, "all(", NULL, ")"); break;
+        case EOpAny: preString = "any("; break;
+        case EOpAll: preString = "all("; break;
 
         default: UNREACHABLE(); break;
     }
 
+    if (visit == PreVisit && node->getUseEmulatedFunction())
+        preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
+    writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
+
     return true;
 }