Commit f6bdb312 by Olli Etuaho

Refactor defining emulated functions in BuiltInFunctionEmulator

This removes the fixed enumeration of emulated functions in favor of a dynamic map. This makes the code more compact and flexible. The main benefit is that maintaining the list emulated functions is a lot simpler now. Change-Id: Ic9951a496b9f021c76ad5b4c3daccd89af5ac093 Reviewed-on: https://chromium-review.googlesource.com/239871Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarNicolas Capens <capn@chromium.org>
parent 0875f85d
......@@ -62,15 +62,32 @@ public:
return true;
};
const TIntermSequence& sequence = *(node->getSequence());
// Right now we only handle built-in functions with two parameters.
if (sequence.size() != 2)
return true;
TIntermTyped* param1 = sequence[0]->getAsTyped();
TIntermTyped* param2 = sequence[1]->getAsTyped();
if (!param1 || !param2)
bool needToEmulate = false;
// Right now we only handle built-in functions with two or three parameters.
if (sequence.size() == 2)
{
TIntermTyped* param1 = sequence[0]->getAsTyped();
TIntermTyped* param2 = sequence[1]->getAsTyped();
if (!param1 || !param2)
return true;
needToEmulate = mEmulator.SetFunctionCalled(
node->getOp(), param1->getType(), param2->getType());
}
else if (sequence.size() == 3)
{
TIntermTyped* param1 = sequence[0]->getAsTyped();
TIntermTyped* param2 = sequence[1]->getAsTyped();
TIntermTyped* param3 = sequence[2]->getAsTyped();
if (!param1 || !param2 || !param3)
return true;
needToEmulate = mEmulator.SetFunctionCalled(
node->getOp(), param1->getType(), param2->getType(), param3->getType());
}
else
{
return true;
bool needToEmulate = mEmulator.SetFunctionCalled(
node->getOp(), param1->getType(), param2->getType());
}
if (needToEmulate)
node->setUseEmulatedFunction();
}
......@@ -86,30 +103,28 @@ private:
BuiltInFunctionEmulator::BuiltInFunctionEmulator()
{}
bool BuiltInFunctionEmulator::SetFunctionCalled(
TOperator op, const TType& param)
void BuiltInFunctionEmulator::AddEmulatedFunction(
TOperator op, const TType& param,
const char* emulatedFunctionDefinition)
{
TBuiltInFunction function = IdentifyFunction(op, param);
return SetFunctionCalled(function);
mEmulatedFunctions[FunctionId(op, param)] =
std::string(emulatedFunctionDefinition);
}
bool BuiltInFunctionEmulator::SetFunctionCalled(
TOperator op, const TType& param1, const TType& param2)
void BuiltInFunctionEmulator::AddEmulatedFunction(
TOperator op, const TType& param1, const TType& param2,
const char* emulatedFunctionDefinition)
{
TBuiltInFunction function = IdentifyFunction(op, param1, param2);
return SetFunctionCalled(function);
mEmulatedFunctions[FunctionId(op, param1, param2)] =
std::string(emulatedFunctionDefinition);
}
bool BuiltInFunctionEmulator::SetFunctionCalled(
BuiltInFunctionEmulator::TBuiltInFunction function) {
if (function == TFunctionUnknown || mFunctionMask[function] == false)
return false;
for (size_t i = 0; i < mFunctions.size(); ++i) {
if (mFunctions[i] == function)
return true;
}
mFunctions.push_back(function);
return true;
void BuiltInFunctionEmulator::AddEmulatedFunction(
TOperator op, const TType& param1, const TType& param2, const TType& param3,
const char* emulatedFunctionDefinition)
{
mEmulatedFunctions[FunctionId(op, param1, param2, param3)] =
std::string(emulatedFunctionDefinition);
}
void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
......@@ -120,77 +135,41 @@ void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
out << "// BEGIN: Generated code for built-in function emulation\n\n";
OutputEmulatedFunctionHeader(out, withPrecision);
for (size_t i = 0; i < mFunctions.size(); ++i) {
out << mFunctionSource[mFunctions[i]] << "\n\n";
out << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n";
}
out << "// END: Generated code for built-in function emulation\n\n";
}
BuiltInFunctionEmulator::TBuiltInFunction
BuiltInFunctionEmulator::IdentifyFunction(
bool BuiltInFunctionEmulator::SetFunctionCalled(
TOperator op, const TType& param)
{
if (param.getNominalSize() > 4 || param.getSecondarySize() > 4)
return TFunctionUnknown;
unsigned int function = TFunctionUnknown;
switch (op) {
case EOpCos:
function = TFunctionCos1;
break;
case EOpLength:
function = TFunctionLength1;
break;
case EOpNormalize:
function = TFunctionNormalize1;
break;
case EOpAsinh:
function = TFunctionAsinh1;
break;
case EOpAcosh:
function = TFunctionAcosh1;
break;
case EOpAtanh:
function = TFunctionAtanh1;
break;
default:
break;
}
if (function == TFunctionUnknown)
return TFunctionUnknown;
if (param.isVector())
function += param.getNominalSize() - 1;
return static_cast<TBuiltInFunction>(function);
return SetFunctionCalled(FunctionId(op, param));
}
BuiltInFunctionEmulator::TBuiltInFunction
BuiltInFunctionEmulator::IdentifyFunction(
bool BuiltInFunctionEmulator::SetFunctionCalled(
TOperator op, const TType& param1, const TType& param2)
{
// Right now for all the emulated functions with two parameters, the two
// parameters have the same type.
if (param1.getNominalSize() != param2.getNominalSize() ||
param1.getSecondarySize() != param2.getSecondarySize() ||
param1.getNominalSize() > 4 || param1.getSecondarySize() > 4)
return TFunctionUnknown;
unsigned int function = TFunctionUnknown;
switch (op) {
case EOpDistance:
function = TFunctionDistance1_1;
break;
case EOpDot:
function = TFunctionDot1_1;
break;
case EOpReflect:
function = TFunctionReflect1_1;
break;
default:
break;
return SetFunctionCalled(FunctionId(op, param1, param2));
}
bool BuiltInFunctionEmulator::SetFunctionCalled(
TOperator op, const TType& param1, const TType& param2, const TType& param3)
{
return SetFunctionCalled(FunctionId(op, param1, param2, param3));
}
bool BuiltInFunctionEmulator::SetFunctionCalled(
const FunctionId& functionId) {
if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end())
{
for (size_t i = 0; i < mFunctions.size(); ++i) {
if (mFunctions[i] == functionId)
return true;
}
mFunctions.push_back(functionId);
return true;
}
if (function == TFunctionUnknown)
return TFunctionUnknown;
if (param1.isVector())
function += param1.getNominalSize() - 1;
return static_cast<TBuiltInFunction>(function);
return false;
}
void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
......@@ -214,3 +193,53 @@ TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
ASSERT(name[name.length() - 1] == '(');
return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
}
BuiltInFunctionEmulator::FunctionId::FunctionId
(TOperator op, const TType& param)
: mOp(op),
mParam1(param),
mParam2(EbtVoid),
mParam3(EbtVoid)
{
}
BuiltInFunctionEmulator::FunctionId::FunctionId
(TOperator op, const TType& param1, const TType& param2)
: mOp(op),
mParam1(param1),
mParam2(param2),
mParam3(EbtVoid)
{
}
BuiltInFunctionEmulator::FunctionId::FunctionId
(TOperator op, const TType& param1, const TType& param2, const TType& param3)
: mOp(op),
mParam1(param1),
mParam2(param2),
mParam3(param3)
{
}
bool BuiltInFunctionEmulator::FunctionId::operator==
(const BuiltInFunctionEmulator::FunctionId& other) const
{
return (mOp == other.mOp &&
mParam1 == other.mParam1 &&
mParam2 == other.mParam2 &&
mParam3 == other.mParam3);
}
bool BuiltInFunctionEmulator::FunctionId::operator<
(const BuiltInFunctionEmulator::FunctionId& other) const
{
if (mOp != other.mOp)
return mOp < other.mOp;
if (mParam1 != other.mParam1)
return mParam1 < other.mParam1;
if (mParam2 != other.mParam2)
return mParam2 < other.mParam2;
if (mParam3 != other.mParam3)
return mParam3 < other.mParam3;
return false; // all fields are equal
}
......@@ -20,12 +20,14 @@ 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.
// emulated. If the function is not in mEmulatedFunctions, this becomes a
// 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);
bool SetFunctionCalled(
TOperator op, const TType& param1, const TType& param2, const TType& param3);
// Output function emulation definition. This should be before any other
// shader source.
......@@ -41,72 +43,36 @@ class BuiltInFunctionEmulator
protected:
BuiltInFunctionEmulator();
//
// Built-in functions.
//
enum TBuiltInFunction {
TFunctionCos1 = 0, // float cos(float);
TFunctionCos2, // vec2 cos(vec2);
TFunctionCos3, // vec3 cos(vec3);
TFunctionCos4, // vec4 cos(vec4);
TFunctionDistance1_1, // float distance(float, float);
TFunctionDistance2_2, // vec2 distance(vec2, vec2);
TFunctionDistance3_3, // vec3 distance(vec3, vec3);
TFunctionDistance4_4, // vec4 distance(vec4, vec4);
TFunctionDot1_1, // float dot(float, float);
TFunctionDot2_2, // vec2 dot(vec2, vec2);
TFunctionDot3_3, // vec3 dot(vec3, vec3);
TFunctionDot4_4, // vec4 dot(vec4, vec4);
TFunctionLength1, // float length(float);
TFunctionLength2, // float length(vec2);
TFunctionLength3, // float length(vec3);
TFunctionLength4, // float length(vec4);
TFunctionNormalize1, // float normalize(float);
TFunctionNormalize2, // vec2 normalize(vec2);
TFunctionNormalize3, // vec3 normalize(vec3);
TFunctionNormalize4, // vec4 normalize(vec4);
TFunctionReflect1_1, // float reflect(float, float);
TFunctionReflect2_2, // vec2 reflect(vec2, vec2);
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;
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);
// 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);
class FunctionId {
public:
FunctionId(TOperator op, const TType& param);
FunctionId(TOperator op, const TType& param1, const TType& param2);
FunctionId(TOperator op, const TType& param1, const TType& param2, const TType& param3);
bool operator==(const FunctionId& other) const;
bool operator<(const FunctionId& other) const;
private:
TOperator mOp;
TType mParam1;
TType mParam2;
TType mParam3;
};
bool SetFunctionCalled(const FunctionId& functionId);
// Map from function id to emulated function definition
std::map<FunctionId, std::string> mEmulatedFunctions;
bool SetFunctionCalled(TBuiltInFunction function);
// Called function ids
std::vector<FunctionId> mFunctions;
};
#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
......@@ -8,104 +8,63 @@
#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
#include "compiler/translator/SymbolTable.h"
namespace
{
const char* kFunctionEmulationSource[] =
BuiltInFunctionEmulatorHLSL::BuiltInFunctionEmulatorHLSL()
: BuiltInFunctionEmulator()
{
"#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)",
TType float1(EbtFloat);
TType float2(EbtFloat, 2);
TType float3(EbtFloat, 3);
TType float4(EbtFloat, 4);
"#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)",
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,
"float2 webgl_asinh_emu(in float2 x) {\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));"
"}\n");
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,
"float4 webgl_asinh_emu(in float4 x) {\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
"}\n");
"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)); }",
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,
"float2 webgl_acosh_emu(in float2 x) {\n"
" return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"}\n");
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,
"float4 webgl_acosh_emu(in float4 x) {\n"
" return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"}\n");
"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;
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,
"float2 webgl_atanh_emu(in float2 x) {\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n");
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,
"float4 webgl_atanh_emu(in float4 x) {\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n");
}
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