Implement hyperbolic function support for ESSL 3.00
Emulating arc hyperbolic functions is required on HLSL, where they do
not exist natively. For this, BuiltInFunctionEmulator is split into GLSL
and HLSL subclasses. The GLSL subclass handles the pre-existing built-in
emulation implemented for working around OSX bugs, and the HLSL subclass
handles emulating asinh, acosh and atanh on HLSL.
BUG=angle:855
Change-Id: I0dfeffb862ac27ba7f9ecf5492ec31d9d952b273
Reviewed-on: https://chromium-review.googlesource.com/236861
Reviewed-by: Nicolas Capens <capn@chromium.org>
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 0e8239c..280cb92 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -8,190 +8,8 @@
#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/SymbolTable.h"
-namespace {
-
-// we use macros here instead of function definitions to work around more GLSL
-// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
-// problematic because if the argument has side-effects they will be repeatedly
-// evaluated. This is unlikely to show up in real shaders, but is something to
-// consider.
-const char* kFunctionEmulationVertexSource[] = {
- "#error no emulation for cos(float)",
- "#error no emulation for cos(vec2)",
- "#error no emulation for cos(vec3)",
- "#error no emulation for cos(vec4)",
-
- "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
- "#error no emulation for distance(vec2, vec2)",
- "#error no emulation for distance(vec3, vec3)",
- "#error no emulation for distance(vec4, vec4)",
-
- "#define webgl_dot_emu(x, y) ((x) * (y))",
- "#error no emulation for dot(vec2, vec2)",
- "#error no emulation for dot(vec3, vec3)",
- "#error no emulation for dot(vec4, vec4)",
-
- "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
- "#error no emulation for length(vec2)",
- "#error no emulation for length(vec3)",
- "#error no emulation for length(vec4)",
-
- "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
- "#error no emulation for normalize(vec2)",
- "#error no emulation for normalize(vec3)",
- "#error no emulation for normalize(vec4)",
-
- "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
- "#error no emulation for reflect(vec2, vec2)",
- "#error no emulation for reflect(vec3, vec3)",
- "#error no emulation for reflect(vec4, vec4)"
-};
-
-const char* kFunctionEmulationFragmentSource[] = {
- "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
- "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
- "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
- "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
-
- "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
- "#error no emulation for distance(vec2, vec2)",
- "#error no emulation for distance(vec3, vec3)",
- "#error no emulation for distance(vec4, vec4)",
-
- "#define webgl_dot_emu(x, y) ((x) * (y))",
- "#error no emulation for dot(vec2, vec2)",
- "#error no emulation for dot(vec3, vec3)",
- "#error no emulation for dot(vec4, vec4)",
-
- "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
- "#error no emulation for length(vec2)",
- "#error no emulation for length(vec3)",
- "#error no emulation for length(vec4)",
-
- "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
- "#error no emulation for normalize(vec2)",
- "#error no emulation for normalize(vec3)",
- "#error no emulation for normalize(vec4)",
-
- "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
- "#error no emulation for reflect(vec2, vec2)",
- "#error no emulation for reflect(vec3, vec3)",
- "#error no emulation for reflect(vec4, vec4)"
-};
-
-const bool kFunctionEmulationVertexMask[] = {
-#if defined(__APPLE__)
- // Work around ATI driver bugs in Mac.
- false, // TFunctionCos1
- false, // TFunctionCos2
- false, // TFunctionCos3
- false, // TFunctionCos4
- true, // TFunctionDistance1_1
- false, // TFunctionDistance2_2
- false, // TFunctionDistance3_3
- false, // TFunctionDistance4_4
- true, // TFunctionDot1_1
- false, // TFunctionDot2_2
- false, // TFunctionDot3_3
- false, // TFunctionDot4_4
- true, // TFunctionLength1
- false, // TFunctionLength2
- false, // TFunctionLength3
- false, // TFunctionLength4
- true, // TFunctionNormalize1
- false, // TFunctionNormalize2
- false, // TFunctionNormalize3
- false, // TFunctionNormalize4
- true, // TFunctionReflect1_1
- false, // TFunctionReflect2_2
- false, // TFunctionReflect3_3
- false, // TFunctionReflect4_4
-#else
- // Work around D3D driver bug in Win.
- false, // TFunctionCos1
- false, // TFunctionCos2
- false, // TFunctionCos3
- false, // TFunctionCos4
- false, // TFunctionDistance1_1
- false, // TFunctionDistance2_2
- false, // TFunctionDistance3_3
- false, // TFunctionDistance4_4
- false, // TFunctionDot1_1
- false, // TFunctionDot2_2
- false, // TFunctionDot3_3
- false, // TFunctionDot4_4
- false, // TFunctionLength1
- false, // TFunctionLength2
- false, // TFunctionLength3
- false, // TFunctionLength4
- false, // TFunctionNormalize1
- false, // TFunctionNormalize2
- false, // TFunctionNormalize3
- false, // TFunctionNormalize4
- false, // TFunctionReflect1_1
- false, // TFunctionReflect2_2
- false, // TFunctionReflect3_3
- false, // TFunctionReflect4_4
-#endif
- false // TFunctionUnknown
-};
-
-const bool kFunctionEmulationFragmentMask[] = {
-#if defined(__APPLE__)
- // Work around ATI driver bugs in Mac.
- true, // TFunctionCos1
- true, // TFunctionCos2
- true, // TFunctionCos3
- true, // TFunctionCos4
- true, // TFunctionDistance1_1
- false, // TFunctionDistance2_2
- false, // TFunctionDistance3_3
- false, // TFunctionDistance4_4
- true, // TFunctionDot1_1
- false, // TFunctionDot2_2
- false, // TFunctionDot3_3
- false, // TFunctionDot4_4
- true, // TFunctionLength1
- false, // TFunctionLength2
- false, // TFunctionLength3
- false, // TFunctionLength4
- true, // TFunctionNormalize1
- false, // TFunctionNormalize2
- false, // TFunctionNormalize3
- false, // TFunctionNormalize4
- true, // TFunctionReflect1_1
- false, // TFunctionReflect2_2
- false, // TFunctionReflect3_3
- false, // TFunctionReflect4_4
-#else
- // Work around D3D driver bug in Win.
- false, // TFunctionCos1
- false, // TFunctionCos2
- false, // TFunctionCos3
- false, // TFunctionCos4
- false, // TFunctionDistance1_1
- false, // TFunctionDistance2_2
- false, // TFunctionDistance3_3
- false, // TFunctionDistance4_4
- false, // TFunctionDot1_1
- false, // TFunctionDot2_2
- false, // TFunctionDot3_3
- false, // TFunctionDot4_4
- false, // TFunctionLength1
- false, // TFunctionLength2
- false, // TFunctionLength3
- false, // TFunctionLength4
- false, // TFunctionNormalize1
- false, // TFunctionNormalize2
- false, // TFunctionNormalize3
- false, // TFunctionNormalize4
- false, // TFunctionReflect1_1
- false, // TFunctionReflect2_2
- false, // TFunctionReflect3_3
- false, // TFunctionReflect4_4
-#endif
- false // TFunctionUnknown
-};
+namespace
+{
class BuiltInFunctionEmulationMarker : public TIntermTraverser {
public:
@@ -265,16 +83,8 @@
} // anonymous namepsace
-BuiltInFunctionEmulator::BuiltInFunctionEmulator(sh::GLenum shaderType)
-{
- if (shaderType == GL_FRAGMENT_SHADER) {
- mFunctionMask = kFunctionEmulationFragmentMask;
- mFunctionSource = kFunctionEmulationFragmentSource;
- } else {
- mFunctionMask = kFunctionEmulationVertexMask;
- mFunctionSource = kFunctionEmulationVertexSource;
- }
-}
+BuiltInFunctionEmulator::BuiltInFunctionEmulator()
+{}
bool BuiltInFunctionEmulator::SetFunctionCalled(
TOperator op, const TType& param)
@@ -308,15 +118,7 @@
if (mFunctions.size() == 0)
return;
out << "// BEGIN: Generated code for built-in function emulation\n\n";
- if (withPrecision) {
- out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
- << "#define webgl_emu_precision highp\n"
- << "#else\n"
- << "#define webgl_emu_precision mediump\n"
- << "#endif\n\n";
- } else {
- out << "#define webgl_emu_precision\n\n";
- }
+ OutputEmulatedFunctionHeader(out, withPrecision);
for (size_t i = 0; i < mFunctions.size(); ++i) {
out << mFunctionSource[mFunctions[i]] << "\n\n";
}
@@ -340,6 +142,15 @@
case EOpNormalize:
function = TFunctionNormalize1;
break;
+ case EOpAsinh:
+ function = TFunctionAsinh1;
+ break;
+ case EOpAcosh:
+ function = TFunctionAcosh1;
+ break;
+ case EOpAtanh:
+ function = TFunctionAtanh1;
+ break;
default:
break;
}
@@ -403,4 +214,3 @@
ASSERT(name[name.length() - 1] == '(');
return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
}
-
diff --git a/src/compiler/translator/BuiltInFunctionEmulator.h b/src/compiler/translator/BuiltInFunctionEmulator.h
index 66086f7..0261969 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.h
+++ b/src/compiler/translator/BuiltInFunctionEmulator.h
@@ -4,8 +4,8 @@
// found in the LICENSE file.
//
-#ifndef COMPILIER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
-#define COMPILIER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
+#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
+#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
@@ -13,21 +13,21 @@
//
// This class decides which built-in functions need to be replaced with the
// emulated ones.
-// It's only a workaround for OpenGL driver bugs, and isn't needed in general.
+// It can be used to work around driver bugs or implement functions that are
+// not natively implemented on a specific platform.
//
-class BuiltInFunctionEmulator {
-public:
- BuiltInFunctionEmulator(sh::GLenum shaderType);
- // Records that a function is called by the shader and might needs to be
- // emulated. If the function's group is not in mFunctionGroupFilter, this
- // becomes an no-op.
+class BuiltInFunctionEmulator
+{
+ public:
+ // Records that a function is called by the shader and might need to be
+ // emulated. If the function is not in mFunctionMask, this becomes an no-op.
// Returns true if the function call needs to be replaced with an emulated
// one.
bool SetFunctionCalled(TOperator op, const TType& param);
bool SetFunctionCalled(
TOperator op, const TType& param1, const TType& param2);
- // Output function emulation definition. This should be before any other
+ // Output function emulation definition. This should be before any other
// shader source.
void OutputEmulatedFunctionDefinition(TInfoSinkBase& out, bool withPrecision) const;
@@ -38,7 +38,9 @@
// "name(" becomes "webgl_name_emu(".
static TString GetEmulatedFunctionName(const TString& name);
-private:
+ protected:
+ BuiltInFunctionEmulator();
+
//
// Built-in functions.
//
@@ -73,19 +75,38 @@
TFunctionReflect3_3, // vec3 reflect(vec3, vec3);
TFunctionReflect4_4, // vec4 reflect(vec4, vec4);
+ TFunctionAsinh1, // float asinh(float);
+ TFunctionAsinh2, // vec2 asinh(vec2);
+ TFunctionAsinh3, // vec3 asinh(vec3);
+ TFunctionAsinh4, // vec4 asinh(vec4);
+
+ TFunctionAcosh1, // float acosh(float);
+ TFunctionAcosh2, // vec2 acosh(vec2);
+ TFunctionAcosh3, // vec3 acosh(vec3);
+ TFunctionAcosh4, // vec4 acosh(vec4);
+
+ TFunctionAtanh1, // float atanh(float);
+ TFunctionAtanh2, // vec2 atanh(vec2);
+ TFunctionAtanh3, // vec3 atanh(vec3);
+ TFunctionAtanh4, // vec4 atanh(vec4);
+
TFunctionUnknown
};
- TBuiltInFunction IdentifyFunction(TOperator op, const TType& param);
- TBuiltInFunction IdentifyFunction(
- TOperator op, const TType& param1, const TType& param2);
-
- bool SetFunctionCalled(TBuiltInFunction function);
-
std::vector<TBuiltInFunction> mFunctions;
const bool* mFunctionMask; // a boolean flag for each function.
const char** mFunctionSource;
+
+ // Override this to add source before emulated function definitions.
+ virtual void OutputEmulatedFunctionHeader(TInfoSinkBase& out, bool withPrecision) const {}
+
+ private:
+ TBuiltInFunction IdentifyFunction(TOperator op, const TType& param);
+ TBuiltInFunction IdentifyFunction(
+ TOperator op, const TType& param1, const TType& param2);
+
+ bool SetFunctionCalled(TBuiltInFunction function);
};
-#endif // COMPILIER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
+#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
new file mode 100644
index 0000000..ca68542
--- /dev/null
+++ b/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
@@ -0,0 +1,281 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace
+{
+
+// we use macros here instead of function definitions to work around more GLSL
+// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
+// problematic because if the argument has side-effects they will be repeatedly
+// evaluated. This is unlikely to show up in real shaders, but is something to
+// consider.
+const char* kFunctionEmulationVertexSource[] =
+{
+ "#error no emulation for cos(float)",
+ "#error no emulation for cos(vec2)",
+ "#error no emulation for cos(vec3)",
+ "#error no emulation for cos(vec4)",
+
+ "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
+ "#error no emulation for distance(vec2, vec2)",
+ "#error no emulation for distance(vec3, vec3)",
+ "#error no emulation for distance(vec4, vec4)",
+
+ "#define webgl_dot_emu(x, y) ((x) * (y))",
+ "#error no emulation for dot(vec2, vec2)",
+ "#error no emulation for dot(vec3, vec3)",
+ "#error no emulation for dot(vec4, vec4)",
+
+ "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
+ "#error no emulation for length(vec2)",
+ "#error no emulation for length(vec3)",
+ "#error no emulation for length(vec4)",
+
+ "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
+ "#error no emulation for normalize(vec2)",
+ "#error no emulation for normalize(vec3)",
+ "#error no emulation for normalize(vec4)",
+
+ "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
+ "#error no emulation for reflect(vec2, vec2)",
+ "#error no emulation for reflect(vec3, vec3)",
+ "#error no emulation for reflect(vec4, vec4)",
+
+ "#error no emulation for asinh(float)",
+ "#error no emulation for asinh(vec2)",
+ "#error no emulation for asinh(vec3)",
+ "#error no emulation for asinh(vec4)",
+
+ "#error no emulation for acosh(float)",
+ "#error no emulation for acosh(vec2)",
+ "#error no emulation for acosh(vec3)",
+ "#error no emulation for acosh(vec4)",
+
+ "#error no emulation for atanh(float)",
+ "#error no emulation for atanh(vec2)",
+ "#error no emulation for atanh(vec3)",
+ "#error no emulation for atanh(vec4)"
+};
+
+const char* kFunctionEmulationFragmentSource[] =
+{
+ "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
+ "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
+ "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
+ "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
+
+ "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
+ "#error no emulation for distance(vec2, vec2)",
+ "#error no emulation for distance(vec3, vec3)",
+ "#error no emulation for distance(vec4, vec4)",
+
+ "#define webgl_dot_emu(x, y) ((x) * (y))",
+ "#error no emulation for dot(vec2, vec2)",
+ "#error no emulation for dot(vec3, vec3)",
+ "#error no emulation for dot(vec4, vec4)",
+
+ "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
+ "#error no emulation for length(vec2)",
+ "#error no emulation for length(vec3)",
+ "#error no emulation for length(vec4)",
+
+ "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
+ "#error no emulation for normalize(vec2)",
+ "#error no emulation for normalize(vec3)",
+ "#error no emulation for normalize(vec4)",
+
+ "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
+ "#error no emulation for reflect(vec2, vec2)",
+ "#error no emulation for reflect(vec3, vec3)",
+ "#error no emulation for reflect(vec4, vec4)"
+
+ "#error no emulation for asinh(float)",
+ "#error no emulation for asinh(vec2)",
+ "#error no emulation for asinh(vec3)",
+ "#error no emulation for asinh(vec4)",
+
+ "#error no emulation for acosh(float)",
+ "#error no emulation for acosh(vec2)",
+ "#error no emulation for acosh(vec3)",
+ "#error no emulation for acosh(vec4)",
+
+ "#error no emulation for atanh(float)",
+ "#error no emulation for atanh(vec2)",
+ "#error no emulation for atanh(vec3)",
+ "#error no emulation for atanh(vec4)"
+};
+
+const bool kFunctionEmulationVertexMask[] =
+{
+#if defined(__APPLE__)
+ // Work around ATI driver bugs in Mac.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ true, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ true, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ true, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ true, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ true, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#else
+ // Work around D3D driver bug in Win.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ false, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ false, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ false, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ false, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ false, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#endif
+ false, // TFunctionAsinh1
+ false, // TFunctionAsinh2
+ false, // TFunctionAsinh3
+ false, // TFunctionAsinh4
+ false, // TFunctionAcosh1
+ false, // TFunctionAcosh2
+ false, // TFunctionAcosh3
+ false, // TFunctionAcosh4
+ false, // TFunctionAtanh1
+ false, // TFunctionAtanh2
+ false, // TFunctionAtanh3
+ false, // TFunctionAtanh4
+ false // TFunctionUnknown
+};
+
+const bool kFunctionEmulationFragmentMask[] =
+{
+#if defined(__APPLE__)
+ // Work around ATI driver bugs in Mac.
+ true, // TFunctionCos1
+ true, // TFunctionCos2
+ true, // TFunctionCos3
+ true, // TFunctionCos4
+ true, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ true, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ true, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ true, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ true, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#else
+ // Work around D3D driver bug in Win.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ false, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ false, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ false, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ false, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ false, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#endif
+ false, // TFunctionAsinh1
+ false, // TFunctionAsinh2
+ false, // TFunctionAsinh3
+ false, // TFunctionAsinh4
+ false, // TFunctionAcosh1
+ false, // TFunctionAcosh2
+ false, // TFunctionAcosh3
+ false, // TFunctionAcosh4
+ false, // TFunctionAtanh1
+ false, // TFunctionAtanh2
+ false, // TFunctionAtanh3
+ false, // TFunctionAtanh4
+ false // TFunctionUnknown
+};
+
+} // anonymous namepsace
+
+BuiltInFunctionEmulatorGLSL::BuiltInFunctionEmulatorGLSL(sh::GLenum shaderType)
+ : BuiltInFunctionEmulator()
+{
+ if (shaderType == GL_FRAGMENT_SHADER) {
+ mFunctionMask = kFunctionEmulationFragmentMask;
+ mFunctionSource = kFunctionEmulationFragmentSource;
+ } else {
+ mFunctionMask = kFunctionEmulationVertexMask;
+ mFunctionSource = kFunctionEmulationVertexSource;
+ }
+}
+
+void BuiltInFunctionEmulatorGLSL::OutputEmulatedFunctionHeader(
+ TInfoSinkBase& out, bool withPrecision) const
+{
+ if (withPrecision) {
+ out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
+ << "#define webgl_emu_precision highp\n"
+ << "#else\n"
+ << "#define webgl_emu_precision mediump\n"
+ << "#endif\n\n";
+ } else {
+ out << "#define webgl_emu_precision\n\n";
+ }
+}
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h b/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
new file mode 100644
index 0000000..ea67515
--- /dev/null
+++ b/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
+#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
+
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+
+//
+// This class is only a workaround for OpenGL driver bugs, and isn't needed in general.
+//
+class BuiltInFunctionEmulatorGLSL : public BuiltInFunctionEmulator
+{
+ public:
+ BuiltInFunctionEmulatorGLSL(sh::GLenum shaderType);
+
+ protected:
+ // Output function emulation definition header.
+ virtual void OutputEmulatedFunctionHeader(TInfoSinkBase& out, bool withPrecision) const override;
+};
+
+#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
new file mode 100644
index 0000000..28527d1
--- /dev/null
+++ b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
@@ -0,0 +1,111 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "angle_gl.h"
+#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace
+{
+
+const char* kFunctionEmulationSource[] =
+{
+ "#error no emulation for cos(float)",
+ "#error no emulation for cos(vec2)",
+ "#error no emulation for cos(vec3)",
+ "#error no emulation for cos(vec4)",
+
+ "#error no emulation for distance(float, float)",
+ "#error no emulation for distance(vec2, vec2)",
+ "#error no emulation for distance(vec3, vec3)",
+ "#error no emulation for distance(vec4, vec4)",
+
+ "#error no emulation for dot(float, float)",
+ "#error no emulation for dot(vec2, vec2)",
+ "#error no emulation for dot(vec3, vec3)",
+ "#error no emulation for dot(vec4, vec4)",
+
+ "#error no emulation for length(float)",
+ "#error no emulation for length(vec2)",
+ "#error no emulation for length(vec3)",
+ "#error no emulation for length(vec4)",
+
+ "#error no emulation for normalize(float)",
+ "#error no emulation for normalize(vec2)",
+ "#error no emulation for normalize(vec3)",
+ "#error no emulation for normalize(vec4)",
+
+ "#error no emulation for reflect(float, float)",
+ "#error no emulation for reflect(vec2, vec2)",
+ "#error no emulation for reflect(vec3, vec3)",
+ "#error no emulation for reflect(vec4, vec4)",
+
+ "float webgl_asinh_emu(in float x) { return log(x + sqrt(pow(x, 2.0) + 1.0)); }",
+ "float2 webgl_asinh_emu(in float2 x) { return log(x + sqrt(pow(x, 2.0) + 1.0)); }",
+ "float3 webgl_asinh_emu(in float3 x) { return log(x + sqrt(pow(x, 2.0) + 1.0)); }",
+ "float4 webgl_asinh_emu(in float4 x) { return log(x + sqrt(pow(x, 2.0) + 1.0)); }",
+
+ "float webgl_acosh_emu(in float x) { return log(x + sqrt(x + 1.0) * sqrt(x - 1.0)); }",
+ "float2 webgl_acosh_emu(in float2 x) { return log(x + sqrt(x + 1.0) * sqrt(x - 1.0)); }",
+ "float3 webgl_acosh_emu(in float3 x) { return log(x + sqrt(x + 1.0) * sqrt(x - 1.0)); }",
+ "float4 webgl_acosh_emu(in float4 x) { return log(x + sqrt(x + 1.0) * sqrt(x - 1.0)); }",
+
+ "float webgl_atanh_emu(in float x) { return 0.5 * log((1.0 + x) / (1.0 - x)); }",
+ "float2 webgl_atanh_emu(in float2 x) { return 0.5 * log((1.0 + x) / (1.0 - x)); }",
+ "float3 webgl_atanh_emu(in float3 x) { return 0.5 * log((1.0 + x) / (1.0 - x)); }",
+ "float4 webgl_atanh_emu(in float4 x) { return 0.5 * log((1.0 + x) / (1.0 - x)); }"
+};
+
+const bool kFunctionEmulationMask[] =
+{
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ false, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ false, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ false, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ false, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ false, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+ true, // TFunctionAsinh1
+ true, // TFunctionAsinh2
+ true, // TFunctionAsinh3
+ true, // TFunctionAsinh4
+ true, // TFunctionAcosh1
+ true, // TFunctionAcosh2
+ true, // TFunctionAcosh3
+ true, // TFunctionAcosh4
+ true, // TFunctionAtanh1
+ true, // TFunctionAtanh2
+ true, // TFunctionAtanh3
+ true, // TFunctionAtanh4
+ false // TFunctionUnknown
+};
+
+} // anonymous namepsace
+
+BuiltInFunctionEmulatorHLSL::BuiltInFunctionEmulatorHLSL()
+ : BuiltInFunctionEmulator()
+{
+ mFunctionMask = kFunctionEmulationMask;
+ mFunctionSource = kFunctionEmulationSource;
+}
+
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h
new file mode 100644
index 0000000..947ebc2
--- /dev/null
+++ b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
+#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
+
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+
+//
+// This class is needed to emulate GLSL functions that don't exist in HLSL.
+//
+class BuiltInFunctionEmulatorHLSL : public BuiltInFunctionEmulator
+{
+ public:
+ BuiltInFunctionEmulatorHLSL();
+};
+
+#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index ecb8c25..d7d98b5 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -4,7 +4,6 @@
// found in the LICENSE file.
//
-#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/DetectCallDepth.h"
#include "compiler/translator/ForLoopUnroll.h"
@@ -615,7 +614,7 @@
return clampingStrategy;
}
-const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
+const BuiltInFunctionEmulatorGLSL& TCompiler::getBuiltInFunctionEmulator() const
{
return builtInFunctionEmulator;
}
diff --git a/src/compiler/translator/Compiler.h b/src/compiler/translator/Compiler.h
index 2644a7e..21185af 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/BuiltInFunctionEmulator.h"
+#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
#include "compiler/translator/ExtensionBehavior.h"
#include "compiler/translator/HashNames.h"
#include "compiler/translator/InfoSink.h"
@@ -135,7 +135,7 @@
const ArrayBoundsClamper& getArrayBoundsClamper() const;
ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
- const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
+ const BuiltInFunctionEmulatorGLSL& getBuiltInFunctionEmulator() const;
std::vector<sh::Attribute> attributes;
std::vector<sh::Attribute> outputVariables;
@@ -165,7 +165,7 @@
ArrayBoundsClamper arrayBoundsClamper;
ShArrayIndexClampingStrategy clampingStrategy;
- BuiltInFunctionEmulator builtInFunctionEmulator;
+ BuiltInFunctionEmulatorGLSL builtInFunctionEmulator;
// Results of compilation.
int shaderVersion;
diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp
index 93a2483..cd0ef81 100644
--- a/src/compiler/translator/Initialize.cpp
+++ b/src/compiler/translator/Initialize.cpp
@@ -75,6 +75,36 @@
symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "atan", float3);
symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "atan", float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "sinh", float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "sinh", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "sinh", float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "sinh", float4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "cosh", float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "cosh", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "cosh", float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "cosh", float4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "tanh", float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "tanh", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "tanh", float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "tanh", float4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "asinh", float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "asinh", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "asinh", float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "asinh", float4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "acosh", float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "acosh", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "acosh", float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "acosh", float4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "atanh", float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "atanh", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "atanh", float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "atanh", float4);
+
//
// Exponential Functions.
//
@@ -697,6 +727,13 @@
symbolTable.relateToOperator(COMMON_BUILTINS, "acos", EOpAcos);
symbolTable.relateToOperator(COMMON_BUILTINS, "atan", EOpAtan);
+ symbolTable.relateToOperator(ESSL3_BUILTINS, "sinh", EOpSinh);
+ symbolTable.relateToOperator(ESSL3_BUILTINS, "cosh", EOpCosh);
+ symbolTable.relateToOperator(ESSL3_BUILTINS, "tanh", EOpTanh);
+ symbolTable.relateToOperator(ESSL3_BUILTINS, "asinh", EOpAsinh);
+ symbolTable.relateToOperator(ESSL3_BUILTINS, "acosh", EOpAcosh);
+ symbolTable.relateToOperator(ESSL3_BUILTINS, "atanh", EOpAtanh);
+
symbolTable.relateToOperator(COMMON_BUILTINS, "pow", EOpPow);
symbolTable.relateToOperator(COMMON_BUILTINS, "exp2", EOpExp2);
symbolTable.relateToOperator(COMMON_BUILTINS, "log", EOpLog);
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
index 58f676d..fff4969 100644
--- a/src/compiler/translator/IntermNode.h
+++ b/src/compiler/translator/IntermNode.h
@@ -102,6 +102,13 @@
EOpAcos,
EOpAtan,
+ EOpSinh,
+ EOpCosh,
+ EOpTanh,
+ EOpAsinh,
+ EOpAcosh,
+ EOpAtanh,
+
EOpPow,
EOpExp,
EOpLog,
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 256f3e4..e5743d2 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -432,6 +432,25 @@
preString = "atan(";
break;
+ case EOpSinh:
+ preString = "sinh(";
+ break;
+ case EOpCosh:
+ preString = "cosh(";
+ break;
+ case EOpTanh:
+ preString = "tanh(";
+ break;
+ case EOpAsinh:
+ preString = "asinh(";
+ break;
+ case EOpAcosh:
+ preString = "acosh(";
+ break;
+ case EOpAtanh:
+ preString = "atanh(";
+ break;
+
case EOpExp:
preString = "exp(";
break;
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 0df2343..bd391a9 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -9,6 +9,7 @@
#include "common/angleutils.h"
#include "common/utilities.h"
#include "common/blocklayout.h"
+#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
#include "compiler/translator/compilerdebug.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/DetectDiscontinuity.h"
@@ -184,11 +185,17 @@
RewriteElseBlocks(mContext.treeRoot);
}
+ BuiltInFunctionEmulatorHLSL builtInFunctionEmulator;
+ builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(mContext.treeRoot);
mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
header();
+ TInfoSinkBase& sink = mContext.infoSink().obj;
+ // Write emulated built-in functions if needed.
+ builtInFunctionEmulator.OutputEmulatedFunctionDefinition(sink, false);
+ builtInFunctionEmulator.Cleanup();
- mContext.infoSink().obj << mHeader.c_str();
- mContext.infoSink().obj << mBody.c_str();
+ sink << mHeader.c_str();
+ sink << mBody.c_str();
}
void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
@@ -1781,6 +1788,21 @@
case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
+ case EOpSinh: outputTriplet(visit, "sinh(", "", ")"); break;
+ case EOpCosh: outputTriplet(visit, "cosh(", "", ")"); break;
+ case EOpTanh: outputTriplet(visit, "tanh(", "", ")"); break;
+ case EOpAsinh:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(visit, "asinh(");
+ break;
+ case EOpAcosh:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(visit, "acosh(");
+ break;
+ case EOpAtanh:
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(visit, "atanh(");
+ break;
case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
@@ -2925,4 +2947,10 @@
return constUnion;
}
+void OutputHLSL::writeEmulatedFunctionTriplet(Visit visit, const char *preStr)
+{
+ TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
+ outputTriplet(visit, preString.c_str(), ", ", ")");
+}
+
}
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index 92c762e..bbf0ec7 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -64,6 +64,8 @@
void outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters);
const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion);
+ void writeEmulatedFunctionTriplet(Visit visit, const char *preStr);
+
TParseContext &mContext;
const ShShaderOutput mOutputType;
UnfoldShortCircuit *mUnfoldShortCircuit;
diff --git a/src/compiler/translator/ValidateLimitations.cpp b/src/compiler/translator/ValidateLimitations.cpp
index c4dad54..cd6f8aa 100644
--- a/src/compiler/translator/ValidateLimitations.cpp
+++ b/src/compiler/translator/ValidateLimitations.cpp
@@ -111,6 +111,14 @@
case EOpAsin: return "asin";
case EOpAcos: return "acos";
case EOpAtan: return "atan";
+
+ case EOpSinh: return "sinh";
+ case EOpCosh: return "cosh";
+ case EOpTanh: return "tanh";
+ case EOpAsinh: return "asinh";
+ case EOpAcosh: return "acosh";
+ case EOpAtanh: return "atanh";
+
case EOpExp: return "exp";
case EOpLog: return "log";
case EOpExp2: return "exp2";
diff --git a/src/compiler/translator/intermOut.cpp b/src/compiler/translator/intermOut.cpp
index 9677dc8..19d0a75 100644
--- a/src/compiler/translator/intermOut.cpp
+++ b/src/compiler/translator/intermOut.cpp
@@ -277,6 +277,13 @@
case EOpAcos: out << "arc cosine"; break;
case EOpAtan: out << "arc tangent"; break;
+ case EOpSinh: out << "hyperbolic sine"; break;
+ case EOpCosh: out << "hyperbolic cosine"; break;
+ case EOpTanh: out << "hyperbolic tangent"; break;
+ case EOpAsinh: out << "arc hyperbolic sine"; break;
+ case EOpAcosh: out << "arc hyperbolic cosine"; break;
+ case EOpAtanh: out << "arc hyperbolic tangent"; break;
+
case EOpExp: out << "exp"; break;
case EOpLog: out << "log"; break;
case EOpExp2: out << "exp2"; break;