Commit 5c9cd3d1 by Olli Etuaho

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/236861Reviewed-by: 's avatarNicolas Capens <capn@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent d4b55a00
......@@ -39,6 +39,10 @@
'compiler/translator/BaseTypes.h',
'compiler/translator/BuiltInFunctionEmulator.cpp',
'compiler/translator/BuiltInFunctionEmulator.h',
'compiler/translator/BuiltInFunctionEmulatorGLSL.cpp',
'compiler/translator/BuiltInFunctionEmulatorGLSL.h',
'compiler/translator/BuiltInFunctionEmulatorHLSL.cpp',
'compiler/translator/BuiltInFunctionEmulatorHLSL.h',
'compiler/translator/CodeGen.cpp',
'compiler/translator/Common.h',
'compiler/translator/Compiler.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 @@ private:
} // 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 @@ void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
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 @@ BuiltInFunctionEmulator::IdentifyFunction(
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 @@ TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
ASSERT(name[name.length() - 1] == '(');
return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
}
......@@ -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 @@ public:
// "name(" becomes "webgl_name_emu(".
static TString GetEmulatedFunctionName(const TString& name);
private:
protected:
BuiltInFunctionEmulator();
//
// Built-in functions.
//
......@@ -73,19 +75,38 @@ private:
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
};
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);
std::vector<TBuiltInFunction> mFunctions;
const bool* mFunctionMask; // a boolean flag for each function.
const char** mFunctionSource;
};
#endif // COMPILIER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
//
// 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";
}
}
//
// 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_
//
// 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;
}
//
// 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_
......@@ -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 @@ ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
return clampingStrategy;
}
const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
const BuiltInFunctionEmulatorGLSL& TCompiler::getBuiltInFunctionEmulator() const
{
return builtInFunctionEmulator;
}
......
......@@ -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 @@ class TCompiler : public TShHandleBase
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 @@ class TCompiler : public TShHandleBase
ArrayBoundsClamper arrayBoundsClamper;
ShArrayIndexClampingStrategy clampingStrategy;
BuiltInFunctionEmulator builtInFunctionEmulator;
BuiltInFunctionEmulatorGLSL builtInFunctionEmulator;
// Results of compilation.
int shaderVersion;
......
......@@ -75,6 +75,36 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
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 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
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);
......
......@@ -102,6 +102,13 @@ enum TOperator
EOpAcos,
EOpAtan,
EOpSinh,
EOpCosh,
EOpTanh,
EOpAsinh,
EOpAcosh,
EOpAtanh,
EOpPow,
EOpExp,
EOpLog,
......
......@@ -432,6 +432,25 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
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;
......
......@@ -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 @@ void OutputHLSL::output()
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 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
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 @@ const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const Con
return constUnion;
}
void OutputHLSL::writeEmulatedFunctionTriplet(Visit visit, const char *preStr)
{
TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
outputTriplet(visit, preString.c_str(), ", ", ")");
}
}
......@@ -64,6 +64,8 @@ class OutputHLSL : public TIntermTraverser
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;
......
......@@ -111,6 +111,14 @@ const char *GetOperatorString(TOperator op)
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";
......
......@@ -277,6 +277,13 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment