Initialize BuiltInFunctionEmulator outside Compiler

This moves GLSL output specific code from the Compiler class to the
GLSL/ESSL translators.

BUG=angleproject:865

Change-Id: I2d552e9cdb41f7d8ddfee7b0249a99d629a6d7d7
Reviewed-on: https://chromium-review.googlesource.com/255471
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/compiler/translator/BuiltInFunctionEmulator.cpp
index c260d8f..5146120 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -100,7 +100,7 @@
 BuiltInFunctionEmulator::BuiltInFunctionEmulator()
 {}
 
-void BuiltInFunctionEmulator::AddEmulatedFunction(
+void BuiltInFunctionEmulator::addEmulatedFunction(
     TOperator op, const TType& param,
     const char* emulatedFunctionDefinition)
 {
@@ -108,7 +108,7 @@
         std::string(emulatedFunctionDefinition);
 }
 
-void BuiltInFunctionEmulator::AddEmulatedFunction(
+void BuiltInFunctionEmulator::addEmulatedFunction(
     TOperator op, const TType& param1, const TType& param2,
     const char* emulatedFunctionDefinition)
 {
@@ -116,7 +116,7 @@
         std::string(emulatedFunctionDefinition);
 }
 
-void BuiltInFunctionEmulator::AddEmulatedFunction(
+void BuiltInFunctionEmulator::addEmulatedFunction(
     TOperator op, const TType& param1, const TType& param2, const TType& param3,
     const char* emulatedFunctionDefinition)
 {
@@ -174,6 +174,9 @@
 {
     ASSERT(root);
 
+    if (mEmulatedFunctions.empty())
+        return;
+
     BuiltInFunctionEmulationMarker marker(*this);
     root->traverse(&marker);
 }
diff --git a/src/compiler/translator/BuiltInFunctionEmulator.h b/src/compiler/translator/BuiltInFunctionEmulator.h
index 04f9292..df55698 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.h
+++ b/src/compiler/translator/BuiltInFunctionEmulator.h
@@ -19,6 +19,8 @@
 class BuiltInFunctionEmulator
 {
   public:
+    BuiltInFunctionEmulator();
+
     void MarkBuiltInFunctionsForEmulation(TIntermNode* root);
 
     void Cleanup();
@@ -32,13 +34,10 @@
     // shader source.
     void OutputEmulatedFunctions(TInfoSinkBase& out) const;
 
-  protected:
-    BuiltInFunctionEmulator();
-
     // Add functions that need to be emulated.
-    void AddEmulatedFunction(TOperator op, const TType& param, const char* emulatedFunctionDefinition);
-    void AddEmulatedFunction(TOperator op, const TType& param1, const TType& param2, const char* emulatedFunctionDefinition);
-    void AddEmulatedFunction(TOperator op, const TType& param1, const TType& param2, const TType& param3, const char* emulatedFunctionDefinition);
+    void addEmulatedFunction(TOperator op, const TType& param, const char* emulatedFunctionDefinition);
+    void addEmulatedFunction(TOperator op, const TType& param1, const TType& param2, const char* emulatedFunctionDefinition);
+    void addEmulatedFunction(TOperator op, const TType& param1, const TType& param2, const TType& param3, const char* emulatedFunctionDefinition);
 
   private:
     class BuiltInFunctionEmulationMarker;
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
index 6f737d3..f71c722 100644
--- a/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
@@ -5,11 +5,11 @@
 //
 
 #include "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
 #include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
 #include "compiler/translator/SymbolTable.h"
 
-BuiltInFunctionEmulatorGLSL::BuiltInFunctionEmulatorGLSL(sh::GLenum shaderType)
-    : BuiltInFunctionEmulator()
+void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType)
 {
 #if defined(__APPLE__)
     // we use macros here instead of function definitions to work around more GLSL
@@ -25,15 +25,15 @@
 
     if (shaderType == GL_FRAGMENT_SHADER)
     {
-        AddEmulatedFunction(EOpCos, float1, "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }");
-        AddEmulatedFunction(EOpCos, float2, "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }");
-        AddEmulatedFunction(EOpCos, float3, "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }");
-        AddEmulatedFunction(EOpCos, float4, "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }");
+        emu->addEmulatedFunction(EOpCos, float1, "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }");
+        emu->addEmulatedFunction(EOpCos, float2, "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }");
+        emu->addEmulatedFunction(EOpCos, float3, "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }");
+        emu->addEmulatedFunction(EOpCos, float4, "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }");
     }
-    AddEmulatedFunction(EOpDistance, float1, float1, "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))");
-    AddEmulatedFunction(EOpDot, float1, float1, "#define webgl_dot_emu(x, y) ((x) * (y))");
-    AddEmulatedFunction(EOpLength, float1, "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))");
-    AddEmulatedFunction(EOpNormalize, float1, "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))");
-    AddEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))");
+    emu->addEmulatedFunction(EOpDistance, float1, float1, "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))");
+    emu->addEmulatedFunction(EOpDot, float1, float1, "#define webgl_dot_emu(x, y) ((x) * (y))");
+    emu->addEmulatedFunction(EOpLength, float1, "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))");
+    emu->addEmulatedFunction(EOpNormalize, float1, "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))");
+    emu->addEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))");
 #endif
 }
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h b/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
index 87e0960..5707a4b 100644
--- a/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
+++ b/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
@@ -7,15 +7,13 @@
 #ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
 #define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
 
-#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "GLSLANG/ShaderLang.h"
+
+class BuiltInFunctionEmulator;
 
 //
-// This class is only a workaround for OpenGL driver bugs, and isn't needed in general.
+// This is only a workaround for OpenGL driver bugs, and isn't needed in general.
 //
-class BuiltInFunctionEmulatorGLSL : public BuiltInFunctionEmulator
-{
-  public:
-    BuiltInFunctionEmulatorGLSL(sh::GLenum shaderType);
-};
+void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType);
 
 #endif  // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
index 96d99c5..7123a0d 100644
--- a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
@@ -5,61 +5,61 @@
 //
 
 #include "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
 #include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
 #include "compiler/translator/SymbolTable.h"
 
-BuiltInFunctionEmulatorHLSL::BuiltInFunctionEmulatorHLSL()
-    : BuiltInFunctionEmulator()
+void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
 {
     TType float1(EbtFloat);
     TType float2(EbtFloat, 2);
     TType float3(EbtFloat, 3);
     TType float4(EbtFloat, 4);
 
-    AddEmulatedFunction(EOpMod, float1, float1,
+    emu->addEmulatedFunction(EOpMod, float1, float1,
         "float webgl_mod_emu(float x, float y)\n"
         "{\n"
         "    return x - y * floor(x / y);\n"
         "}\n"
         "\n");
-    AddEmulatedFunction(EOpMod, float2, float2,
+    emu->addEmulatedFunction(EOpMod, float2, float2,
         "float2 webgl_mod_emu(float2 x, float2 y)\n"
         "{\n"
         "    return x - y * floor(x / y);\n"
         "}\n"
         "\n");
-    AddEmulatedFunction(EOpMod, float2, float1,
+    emu->addEmulatedFunction(EOpMod, float2, float1,
         "float2 webgl_mod_emu(float2 x, float y)\n"
         "{\n"
         "    return x - y * floor(x / y);\n"
         "}\n"
         "\n");
-    AddEmulatedFunction(EOpMod, float3, float3,
+    emu->addEmulatedFunction(EOpMod, float3, float3,
         "float3 webgl_mod_emu(float3 x, float3 y)\n"
         "{\n"
         "    return x - y * floor(x / y);\n"
         "}\n"
         "\n");
-    AddEmulatedFunction(EOpMod, float3, float1,
+    emu->addEmulatedFunction(EOpMod, float3, float1,
         "float3 webgl_mod_emu(float3 x, float y)\n"
         "{\n"
         "    return x - y * floor(x / y);\n"
         "}\n"
         "\n");
-    AddEmulatedFunction(EOpMod, float4, float4,
+    emu->addEmulatedFunction(EOpMod, float4, float4,
         "float4 webgl_mod_emu(float4 x, float4 y)\n"
         "{\n"
         "    return x - y * floor(x / y);\n"
         "}\n"
         "\n");
-    AddEmulatedFunction(EOpMod, float4, float1,
+    emu->addEmulatedFunction(EOpMod, float4, float1,
         "float4 webgl_mod_emu(float4 x, float y)\n"
         "{\n"
         "    return x - y * floor(x / y);\n"
         "}\n"
         "\n");
 
-    AddEmulatedFunction(EOpFaceForward, float1, float1, float1,
+    emu->addEmulatedFunction(EOpFaceForward, float1, float1, float1,
         "float webgl_faceforward_emu(float N, float I, float Nref)\n"
         "{\n"
         "    if(dot(Nref, I) >= 0)\n"
@@ -72,7 +72,7 @@
         "    }\n"
         "}\n"
         "\n");
-    AddEmulatedFunction(EOpFaceForward, float2, float2, float2,
+    emu->addEmulatedFunction(EOpFaceForward, float2, float2, float2,
         "float2 webgl_faceforward_emu(float2 N, float2 I, float2 Nref)\n"
         "{\n"
         "    if(dot(Nref, I) >= 0)\n"
@@ -85,7 +85,7 @@
         "    }\n"
         "}\n"
         "\n");
-    AddEmulatedFunction(EOpFaceForward, float3, float3, float3,
+    emu->addEmulatedFunction(EOpFaceForward, float3, float3, float3,
         "float3 webgl_faceforward_emu(float3 N, float3 I, float3 Nref)\n"
         "{\n"
         "    if(dot(Nref, I) >= 0)\n"
@@ -98,7 +98,7 @@
         "    }\n"
         "}\n"
         "\n");
-    AddEmulatedFunction(EOpFaceForward, float4, float4, float4,
+    emu->addEmulatedFunction(EOpFaceForward, float4, float4, float4,
         "float4 webgl_faceforward_emu(float4 N, float4 I, float4 Nref)\n"
         "{\n"
         "    if(dot(Nref, I) >= 0)\n"
@@ -112,20 +112,20 @@
         "}\n"
         "\n");
 
-    AddEmulatedFunction(EOpAtan, float1, float1,
+    emu->addEmulatedFunction(EOpAtan, float1, float1,
         "float webgl_atan_emu(float y, float x)\n"
         "{\n"
         "    if(x == 0 && y == 0) x = 1;\n"   // Avoid producing a NaN
         "    return atan2(y, x);\n"
         "}\n");
-    AddEmulatedFunction(EOpAtan, float2, float2,
+    emu->addEmulatedFunction(EOpAtan, float2, float2,
         "float2 webgl_atan_emu(float2 y, float2 x)\n"
         "{\n"
         "    if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
         "    if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
         "    return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
         "}\n");
-    AddEmulatedFunction(EOpAtan, float3, float3,
+    emu->addEmulatedFunction(EOpAtan, float3, float3,
         "float3 webgl_atan_emu(float3 y, float3 x)\n"
         "{\n"
         "    if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
@@ -133,7 +133,7 @@
         "    if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
         "    return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
         "}\n");
-    AddEmulatedFunction(EOpAtan, float4, float4,
+    emu->addEmulatedFunction(EOpAtan, float4, float4,
         "float4 webgl_atan_emu(float4 y, float4 x)\n"
         "{\n"
         "    if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
@@ -143,69 +143,69 @@
         "    return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n"
         "}\n");
 
-    AddEmulatedFunction(EOpAsinh, float1,
+    emu->addEmulatedFunction(EOpAsinh, float1,
         "float webgl_asinh_emu(in float x) {\n"
         "    return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
         "}\n");
-    AddEmulatedFunction(EOpAsinh, float2,
+    emu->addEmulatedFunction(EOpAsinh, float2,
         "float2 webgl_asinh_emu(in float2 x) {\n"
         "    return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
         "}\n");
-    AddEmulatedFunction(EOpAsinh, float3,
+    emu->addEmulatedFunction(EOpAsinh, float3,
         "float3 webgl_asinh_emu(in float3 x) {\n"
         "    return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
         "}\n");
-    AddEmulatedFunction(EOpAsinh, float4,
+    emu->addEmulatedFunction(EOpAsinh, float4,
         "float4 webgl_asinh_emu(in float4 x) {\n"
         "    return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
         "}\n");
 
-    AddEmulatedFunction(EOpAcosh, float1,
+    emu->addEmulatedFunction(EOpAcosh, float1,
         "float webgl_acosh_emu(in float x) {\n"
         "    return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
         "}\n");
-    AddEmulatedFunction(EOpAcosh, float2,
+    emu->addEmulatedFunction(EOpAcosh, float2,
         "float2 webgl_acosh_emu(in float2 x) {\n"
         "    return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
         "}\n");
-    AddEmulatedFunction(EOpAcosh, float3,
+    emu->addEmulatedFunction(EOpAcosh, float3,
         "float3 webgl_acosh_emu(in float3 x) {\n"
         "    return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
         "}\n");
-    AddEmulatedFunction(EOpAcosh, float4,
+    emu->addEmulatedFunction(EOpAcosh, float4,
         "float4 webgl_acosh_emu(in float4 x) {\n"
         "    return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
         "}\n");
 
-    AddEmulatedFunction(EOpAtanh, float1,
+    emu->addEmulatedFunction(EOpAtanh, float1,
         "float webgl_atanh_emu(in float x) {\n"
         "    return 0.5 * log((1.0 + x) / (1.0 - x));\n"
         "}\n");
-    AddEmulatedFunction(EOpAtanh, float2,
+    emu->addEmulatedFunction(EOpAtanh, float2,
         "float2 webgl_atanh_emu(in float2 x) {\n"
         "    return 0.5 * log((1.0 + x) / (1.0 - x));\n"
         "}\n");
-    AddEmulatedFunction(EOpAtanh, float3,
+    emu->addEmulatedFunction(EOpAtanh, float3,
         "float3 webgl_atanh_emu(in float3 x) {\n"
         "    return 0.5 * log((1.0 + x) / (1.0 - x));\n"
         "}\n");
-    AddEmulatedFunction(EOpAtanh, float4,
+    emu->addEmulatedFunction(EOpAtanh, float4,
         "float4 webgl_atanh_emu(in float4 x) {\n"
         "    return 0.5 * log((1.0 + x) / (1.0 - x));\n"
         "}\n");
 
-    AddEmulatedFunction(EOpRoundEven, float1,
+    emu->addEmulatedFunction(EOpRoundEven, float1,
         "float webgl_roundEven_emu(in float x) {\n"
         "    return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n"
         "}\n");
-    AddEmulatedFunction(EOpRoundEven, float2,
+    emu->addEmulatedFunction(EOpRoundEven, float2,
         "float2 webgl_roundEven_emu(in float2 x) {\n"
         "    float2 v;\n"
         "    v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
         "    v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
         "    return v;\n"
         "}\n");
-    AddEmulatedFunction(EOpRoundEven, float3,
+    emu->addEmulatedFunction(EOpRoundEven, float3,
         "float3 webgl_roundEven_emu(in float3 x) {\n"
         "    float3 v;\n"
         "    v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
@@ -213,7 +213,7 @@
         "    v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n"
         "    return v;\n"
         "}\n");
-    AddEmulatedFunction(EOpRoundEven, float4,
+    emu->addEmulatedFunction(EOpRoundEven, float4,
         "float4 webgl_roundEven_emu(in float4 x) {\n"
         "    float4 v;\n"
         "    v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
@@ -223,7 +223,7 @@
         "    return v;\n"
         "}\n");
 
-    AddEmulatedFunction(EOpPackSnorm2x16, float2,
+    emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
         "int webgl_toSnorm(in float x) {\n"
         "    return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n"
         "}\n"
@@ -233,7 +233,7 @@
         "    int y = webgl_toSnorm(v.y);\n"
         "    return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n"
         "}\n");
-    AddEmulatedFunction(EOpPackUnorm2x16, float2,
+    emu->addEmulatedFunction(EOpPackUnorm2x16, float2,
         "uint webgl_toUnorm(in float x) {\n"
         "    return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n"
         "}\n"
@@ -243,7 +243,7 @@
         "    uint y = webgl_toUnorm(v.y);\n"
         "    return (y << 16) | x;\n"
         "}\n");
-    AddEmulatedFunction(EOpPackHalf2x16, float2,
+    emu->addEmulatedFunction(EOpPackHalf2x16, float2,
         "uint webgl_packHalf2x16_emu(in float2 v) {\n"
         "    uint x = f32tof16(v.x);\n"
         "    uint y = f32tof16(v.y);\n"
@@ -252,7 +252,7 @@
 
     TType uint1(EbtUInt);
 
-    AddEmulatedFunction(EOpUnpackSnorm2x16, uint1,
+    emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
         "float webgl_fromSnorm(in uint x) {\n"
         "    int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);\n"
         "    return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
@@ -263,7 +263,7 @@
         "    uint x = u;\n"
         "    return float2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
         "}\n");
-    AddEmulatedFunction(EOpUnpackUnorm2x16, uint1,
+    emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1,
         "float webgl_fromUnorm(in uint x) {\n"
         "    return float(x) / 65535.0;\n"
         "}\n"
@@ -273,7 +273,7 @@
         "    uint x = u & 0xffffu;\n"
         "    return float2(webgl_fromUnorm(x), webgl_fromUnorm(y));\n"
         "}\n");
-    AddEmulatedFunction(EOpUnpackHalf2x16, uint1,
+    emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
         "float2 webgl_unpackHalf2x16_emu(in uint u) {\n"
         "    uint y = (u >> 16);\n"
         "    uint x = u & 0xffffu;\n"
@@ -289,40 +289,40 @@
     // transpose(r) and transpose(c) are in a sense free, since to get the
     // transpose of r, we simply can build a column matrix out of the original
     // vector instead of a row matrix.
-    AddEmulatedFunction(EOpOuterProduct, float2, float2,
+    emu->addEmulatedFunction(EOpOuterProduct, float2, float2,
         "float2x2 webgl_outerProduct_emu(in float2 c, in float2 r) {\n"
         "    return mul(float2x1(r), float1x2(c));\n"
         "}\n");
-    AddEmulatedFunction(EOpOuterProduct, float3, float3,
+    emu->addEmulatedFunction(EOpOuterProduct, float3, float3,
         "float3x3 webgl_outerProduct_emu(in float3 c, in float3 r) {\n"
         "    return mul(float3x1(r), float1x3(c));\n"
         "}\n");
-    AddEmulatedFunction(EOpOuterProduct, float4, float4,
+    emu->addEmulatedFunction(EOpOuterProduct, float4, float4,
         "float4x4 webgl_outerProduct_emu(in float4 c, in float4 r) {\n"
         "    return mul(float4x1(r), float1x4(c));\n"
         "}\n");
 
-    AddEmulatedFunction(EOpOuterProduct, float3, float2,
+    emu->addEmulatedFunction(EOpOuterProduct, float3, float2,
         "float2x3 webgl_outerProduct_emu(in float3 c, in float2 r) {\n"
         "    return mul(float2x1(r), float1x3(c));\n"
         "}\n");
-    AddEmulatedFunction(EOpOuterProduct, float2, float3,
+    emu->addEmulatedFunction(EOpOuterProduct, float2, float3,
         "float3x2 webgl_outerProduct_emu(in float2 c, in float3 r) {\n"
         "    return mul(float3x1(r), float1x2(c));\n"
         "}\n");
-    AddEmulatedFunction(EOpOuterProduct, float4, float2,
+    emu->addEmulatedFunction(EOpOuterProduct, float4, float2,
         "float2x4 webgl_outerProduct_emu(in float4 c, in float2 r) {\n"
         "    return mul(float2x1(r), float1x4(c));\n"
         "}\n");
-    AddEmulatedFunction(EOpOuterProduct, float2, float4,
+    emu->addEmulatedFunction(EOpOuterProduct, float2, float4,
         "float4x2 webgl_outerProduct_emu(in float2 c, in float4 r) {\n"
         "    return mul(float4x1(r), float1x2(c));\n"
         "}\n");
-    AddEmulatedFunction(EOpOuterProduct, float4, float3,
+    emu->addEmulatedFunction(EOpOuterProduct, float4, float3,
         "float3x4 webgl_outerProduct_emu(in float4 c, in float3 r) {\n"
         "    return mul(float3x1(r), float1x4(c));\n"
         "}\n");
-    AddEmulatedFunction(EOpOuterProduct, float3, float4,
+    emu->addEmulatedFunction(EOpOuterProduct, float3, float4,
         "float4x3 webgl_outerProduct_emu(in float3 c, in float4 r) {\n"
         "    return mul(float4x1(r), float1x3(c));\n"
         "}\n");
@@ -346,7 +346,7 @@
     // We don't need to care about divide-by-zero since results are undefined
     // for singular or poorly-conditioned matrices.
 
-    AddEmulatedFunction(EOpInverse, mat2,
+    emu->addEmulatedFunction(EOpInverse, mat2,
         "float2x2 webgl_inverse_emu(in float2x2 m) {\n"
         "    float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };\n"
         "    return cof / determinant(transpose(m));\n"
@@ -354,7 +354,7 @@
 
     // cofAB is the cofactor for column A and row B.
 
-    AddEmulatedFunction(EOpInverse, mat3,
+    emu->addEmulatedFunction(EOpInverse, mat3,
         "float3x3 webgl_inverse_emu(in float3x3 m) {\n"
         "    float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n"
         "    float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n"
@@ -369,7 +369,7 @@
         "    return cof / determinant(transpose(m));\n"
         "}\n");
 
-    AddEmulatedFunction(EOpInverse, mat4,
+    emu->addEmulatedFunction(EOpInverse, mat4,
         "float4x4 webgl_inverse_emu(in float4x4 m) {\n"
         "    float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * m[1][2] * m[2][3]"
                        " - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * m[1][3];\n"
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h
index 947ebc2..4c45a93 100644
--- a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h
+++ b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h
@@ -7,15 +7,10 @@
 #ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
 #define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
 
-#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "GLSLANG/ShaderLang.h"
 
-//
-// This class is needed to emulate GLSL functions that don't exist in HLSL.
-//
-class BuiltInFunctionEmulatorHLSL : public BuiltInFunctionEmulator
-{
-  public:
-    BuiltInFunctionEmulatorHLSL();
-};
+class BuiltInFunctionEmulator;
+
+void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu);
 
 #endif  // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index b8eebc9..534861c 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -125,7 +125,7 @@
       maxCallStackDepth(0),
       fragmentPrecisionHigh(false),
       clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
-      builtInFunctionEmulator(type),
+      builtInFunctionEmulator(),
       mSourcePath(NULL)
 {
 }
@@ -265,8 +265,11 @@
         }
 
         // Built-in function emulation needs to happen after validateLimitations pass.
-        if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
+        if (success)
+        {
+            initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions);
             builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
+        }
 
         // Clamping uniform array bounds needs to happen after validateLimitations pass.
         if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
@@ -649,7 +652,7 @@
     return clampingStrategy;
 }
 
-const BuiltInFunctionEmulatorGLSL& TCompiler::getBuiltInFunctionEmulator() const
+const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
 {
     return builtInFunctionEmulator;
 }
diff --git a/src/compiler/translator/Compiler.h b/src/compiler/translator/Compiler.h
index bb81741..bcdb0d4 100644
--- a/src/compiler/translator/Compiler.h
+++ b/src/compiler/translator/Compiler.h
@@ -14,7 +14,7 @@
 // This should not be included by driver code.
 //
 
-#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
 #include "compiler/translator/ExtensionBehavior.h"
 #include "compiler/translator/HashNames.h"
 #include "compiler/translator/InfoSink.h"
@@ -114,6 +114,8 @@
     bool validateLimitations(TIntermNode* root);
     // Collect info for all attribs, uniforms, varyings.
     void collectVariables(TIntermNode* root);
+    // Add emulated functions to the built-in function emulator.
+    virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) {};
     // Translate to object code.
     virtual void translate(TIntermNode *root, int compileOptions) = 0;
     // Returns true if, after applying the packing rules in the GLSL 1.017 spec
@@ -146,7 +148,7 @@
 
     const ArrayBoundsClamper& getArrayBoundsClamper() const;
     ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
-    const BuiltInFunctionEmulatorGLSL& getBuiltInFunctionEmulator() const;
+    const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
 
     std::vector<sh::Attribute> attributes;
     std::vector<sh::Attribute> outputVariables;
@@ -179,7 +181,7 @@
 
     ArrayBoundsClamper arrayBoundsClamper;
     ShArrayIndexClampingStrategy clampingStrategy;
-    BuiltInFunctionEmulatorGLSL builtInFunctionEmulator;
+    BuiltInFunctionEmulator builtInFunctionEmulator;
 
     // Results of compilation.
     int shaderVersion;
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index b109ad3..5bf7d7b 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -12,6 +12,7 @@
 
 #include "common/angleutils.h"
 #include "common/utilities.h"
+#include "compiler/translator/BuiltInFunctionEmulator.h"
 #include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
 #include "compiler/translator/DetectDiscontinuity.h"
 #include "compiler/translator/FlagStd140Structs.h"
@@ -178,7 +179,8 @@
         RewriteElseBlocks(treeRoot);
     }
 
-    BuiltInFunctionEmulatorHLSL builtInFunctionEmulator;
+    BuiltInFunctionEmulator builtInFunctionEmulator;
+    InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
     builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot);
 
     // Output the body and footer first to determine what has to go in the header
@@ -289,7 +291,7 @@
     return init;
 }
 
-void OutputHLSL::header(const BuiltInFunctionEmulatorHLSL *builtInFunctionEmulator)
+void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
 {
     TInfoSinkBase &out = getInfoSink();
 
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index 4c547c8..9cf4dfa 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -16,7 +16,7 @@
 #include "compiler/translator/IntermNode.h"
 #include "compiler/translator/ParseContext.h"
 
-class BuiltInFunctionEmulatorHLSL;
+class BuiltInFunctionEmulator;
 
 namespace sh
 {
@@ -47,7 +47,7 @@
     TInfoSinkBase &getInfoSink() { ASSERT(!mInfoSinkStack.empty()); return *mInfoSinkStack.top(); }
 
   protected:
-    void header(const BuiltInFunctionEmulatorHLSL *builtInFunctionEmulator);
+    void header(const BuiltInFunctionEmulator *builtInFunctionEmulator);
 
     // Visit AST nodes and output their code to the body stream
     void visitSymbol(TIntermSymbol*);
diff --git a/src/compiler/translator/TranslatorESSL.cpp b/src/compiler/translator/TranslatorESSL.cpp
index a38dbe6..9ded71d 100644
--- a/src/compiler/translator/TranslatorESSL.cpp
+++ b/src/compiler/translator/TranslatorESSL.cpp
@@ -6,6 +6,7 @@
 
 #include "compiler/translator/TranslatorESSL.h"
 
+#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
 #include "compiler/translator/EmulatePrecision.h"
 #include "compiler/translator/OutputESSL.h"
 #include "angle_gl.h"
@@ -15,6 +16,12 @@
 {
 }
 
+void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions)
+{
+    if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
+        InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType());
+}
+
 void TranslatorESSL::translate(TIntermNode *root, int) {
     TInfoSinkBase& sink = getInfoSink().obj;
 
diff --git a/src/compiler/translator/TranslatorESSL.h b/src/compiler/translator/TranslatorESSL.h
index 3ada498..89a3e47 100644
--- a/src/compiler/translator/TranslatorESSL.h
+++ b/src/compiler/translator/TranslatorESSL.h
@@ -15,6 +15,8 @@
     TranslatorESSL(sh::GLenum type, ShShaderSpec spec);
 
   protected:
+    void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override;
+
     virtual void translate(TIntermNode *root, int compileOptions);
 
   private:
diff --git a/src/compiler/translator/TranslatorGLSL.cpp b/src/compiler/translator/TranslatorGLSL.cpp
index 70e0a6c..aea3f77 100644
--- a/src/compiler/translator/TranslatorGLSL.cpp
+++ b/src/compiler/translator/TranslatorGLSL.cpp
@@ -7,6 +7,7 @@
 #include "compiler/translator/TranslatorGLSL.h"
 
 #include "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
 #include "compiler/translator/EmulatePrecision.h"
 #include "compiler/translator/OutputGLSL.h"
 #include "compiler/translator/VersionGLSL.h"
@@ -61,6 +62,12 @@
     : TCompiler(type, spec, output) {
 }
 
+void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions)
+{
+    if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
+        InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType());
+}
+
 void TranslatorGLSL::translate(TIntermNode *root, int) {
     TInfoSinkBase& sink = getInfoSink().obj;
 
diff --git a/src/compiler/translator/TranslatorGLSL.h b/src/compiler/translator/TranslatorGLSL.h
index b0684c7..4a5a641 100644
--- a/src/compiler/translator/TranslatorGLSL.h
+++ b/src/compiler/translator/TranslatorGLSL.h
@@ -15,6 +15,8 @@
     TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
 
   protected:
+    void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override;
+
     virtual void translate(TIntermNode *root, int compileOptions);
 
   private: