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: ...@@ -62,15 +62,32 @@ public:
return true; return true;
}; };
const TIntermSequence& sequence = *(node->getSequence()); const TIntermSequence& sequence = *(node->getSequence());
// Right now we only handle built-in functions with two parameters. bool needToEmulate = false;
if (sequence.size() != 2) // Right now we only handle built-in functions with two or three parameters.
return true; if (sequence.size() == 2)
TIntermTyped* param1 = sequence[0]->getAsTyped(); {
TIntermTyped* param2 = sequence[1]->getAsTyped(); TIntermTyped* param1 = sequence[0]->getAsTyped();
if (!param1 || !param2) 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; return true;
bool needToEmulate = mEmulator.SetFunctionCalled( }
node->getOp(), param1->getType(), param2->getType());
if (needToEmulate) if (needToEmulate)
node->setUseEmulatedFunction(); node->setUseEmulatedFunction();
} }
...@@ -86,30 +103,28 @@ private: ...@@ -86,30 +103,28 @@ private:
BuiltInFunctionEmulator::BuiltInFunctionEmulator() BuiltInFunctionEmulator::BuiltInFunctionEmulator()
{} {}
bool BuiltInFunctionEmulator::SetFunctionCalled( void BuiltInFunctionEmulator::AddEmulatedFunction(
TOperator op, const TType& param) TOperator op, const TType& param,
const char* emulatedFunctionDefinition)
{ {
TBuiltInFunction function = IdentifyFunction(op, param); mEmulatedFunctions[FunctionId(op, param)] =
return SetFunctionCalled(function); std::string(emulatedFunctionDefinition);
} }
bool BuiltInFunctionEmulator::SetFunctionCalled( void BuiltInFunctionEmulator::AddEmulatedFunction(
TOperator op, const TType& param1, const TType& param2) TOperator op, const TType& param1, const TType& param2,
const char* emulatedFunctionDefinition)
{ {
TBuiltInFunction function = IdentifyFunction(op, param1, param2); mEmulatedFunctions[FunctionId(op, param1, param2)] =
return SetFunctionCalled(function); std::string(emulatedFunctionDefinition);
} }
bool BuiltInFunctionEmulator::SetFunctionCalled( void BuiltInFunctionEmulator::AddEmulatedFunction(
BuiltInFunctionEmulator::TBuiltInFunction function) { TOperator op, const TType& param1, const TType& param2, const TType& param3,
if (function == TFunctionUnknown || mFunctionMask[function] == false) const char* emulatedFunctionDefinition)
return false; {
for (size_t i = 0; i < mFunctions.size(); ++i) { mEmulatedFunctions[FunctionId(op, param1, param2, param3)] =
if (mFunctions[i] == function) std::string(emulatedFunctionDefinition);
return true;
}
mFunctions.push_back(function);
return true;
} }
void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition( void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
...@@ -120,77 +135,41 @@ void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition( ...@@ -120,77 +135,41 @@ void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
out << "// BEGIN: Generated code for built-in function emulation\n\n"; out << "// BEGIN: Generated code for built-in function emulation\n\n";
OutputEmulatedFunctionHeader(out, withPrecision); OutputEmulatedFunctionHeader(out, withPrecision);
for (size_t i = 0; i < mFunctions.size(); ++i) { 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"; out << "// END: Generated code for built-in function emulation\n\n";
} }
BuiltInFunctionEmulator::TBuiltInFunction bool BuiltInFunctionEmulator::SetFunctionCalled(
BuiltInFunctionEmulator::IdentifyFunction(
TOperator op, const TType& param) TOperator op, const TType& param)
{ {
if (param.getNominalSize() > 4 || param.getSecondarySize() > 4) return SetFunctionCalled(FunctionId(op, param));
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);
} }
BuiltInFunctionEmulator::TBuiltInFunction bool BuiltInFunctionEmulator::SetFunctionCalled(
BuiltInFunctionEmulator::IdentifyFunction(
TOperator op, const TType& param1, const TType& param2) TOperator op, const TType& param1, const TType& param2)
{ {
// Right now for all the emulated functions with two parameters, the two return SetFunctionCalled(FunctionId(op, param1, param2));
// parameters have the same type. }
if (param1.getNominalSize() != param2.getNominalSize() ||
param1.getSecondarySize() != param2.getSecondarySize() || bool BuiltInFunctionEmulator::SetFunctionCalled(
param1.getNominalSize() > 4 || param1.getSecondarySize() > 4) TOperator op, const TType& param1, const TType& param2, const TType& param3)
return TFunctionUnknown; {
return SetFunctionCalled(FunctionId(op, param1, param2, param3));
unsigned int function = TFunctionUnknown; }
switch (op) {
case EOpDistance: bool BuiltInFunctionEmulator::SetFunctionCalled(
function = TFunctionDistance1_1; const FunctionId& functionId) {
break; if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end())
case EOpDot: {
function = TFunctionDot1_1; for (size_t i = 0; i < mFunctions.size(); ++i) {
break; if (mFunctions[i] == functionId)
case EOpReflect: return true;
function = TFunctionReflect1_1; }
break; mFunctions.push_back(functionId);
default: return true;
break;
} }
if (function == TFunctionUnknown) return false;
return TFunctionUnknown;
if (param1.isVector())
function += param1.getNominalSize() - 1;
return static_cast<TBuiltInFunction>(function);
} }
void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation( void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
...@@ -214,3 +193,53 @@ TString BuiltInFunctionEmulator::GetEmulatedFunctionName( ...@@ -214,3 +193,53 @@ TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
ASSERT(name[name.length() - 1] == '('); ASSERT(name[name.length() - 1] == '(');
return "webgl_" + name.substr(0, name.length() - 1) + "_emu("; 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 ...@@ -20,12 +20,14 @@ class BuiltInFunctionEmulator
{ {
public: public:
// Records that a function is called by the shader and might need to be // 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. // emulated. If the function is not in mEmulatedFunctions, this becomes a
// Returns true if the function call needs to be replaced with an emulated // no-op. Returns true if the function call needs to be replaced with an
// one. // emulated one.
bool SetFunctionCalled(TOperator op, const TType& param); bool SetFunctionCalled(TOperator op, const TType& param);
bool SetFunctionCalled( bool SetFunctionCalled(
TOperator op, const TType& param1, const TType& param2); 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 // Output function emulation definition. This should be before any other
// shader source. // shader source.
...@@ -41,72 +43,36 @@ class BuiltInFunctionEmulator ...@@ -41,72 +43,36 @@ class BuiltInFunctionEmulator
protected: protected:
BuiltInFunctionEmulator(); BuiltInFunctionEmulator();
// void AddEmulatedFunction(TOperator op, const TType& param, const char* emulatedFunctionDefinition);
// Built-in functions. 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);
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;
// Override this to add source before emulated function definitions. // Override this to add source before emulated function definitions.
virtual void OutputEmulatedFunctionHeader(TInfoSinkBase& out, bool withPrecision) const {} virtual void OutputEmulatedFunctionHeader(TInfoSinkBase& out, bool withPrecision) const {}
private: private:
TBuiltInFunction IdentifyFunction(TOperator op, const TType& param); class FunctionId {
TBuiltInFunction IdentifyFunction( public:
TOperator op, const TType& param1, const TType& param2); 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_ #endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
...@@ -8,104 +8,63 @@ ...@@ -8,104 +8,63 @@
#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h" #include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
#include "compiler/translator/SymbolTable.h" #include "compiler/translator/SymbolTable.h"
namespace BuiltInFunctionEmulatorHLSL::BuiltInFunctionEmulatorHLSL()
{ : BuiltInFunctionEmulator()
const char* kFunctionEmulationSource[] =
{ {
"#error no emulation for cos(float)", TType float1(EbtFloat);
"#error no emulation for cos(vec2)", TType float2(EbtFloat, 2);
"#error no emulation for cos(vec3)", TType float3(EbtFloat, 3);
"#error no emulation for cos(vec4)", TType float4(EbtFloat, 4);
"#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)", AddEmulatedFunction(EOpAsinh, float1,
"#error no emulation for reflect(vec2, vec2)", "float webgl_asinh_emu(in float x) {\n"
"#error no emulation for reflect(vec3, vec3)", " return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
"#error no emulation for reflect(vec4, vec4)", "}\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)); }", AddEmulatedFunction(EOpAcosh, float1,
"float2 webgl_asinh_emu(in float2 x) { return log(x + sqrt(pow(x, 2.0) + 1.0)); }", "float webgl_acosh_emu(in float x) {\n"
"float3 webgl_asinh_emu(in float3 x) { return log(x + sqrt(pow(x, 2.0) + 1.0)); }", " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"float4 webgl_asinh_emu(in float4 x) { return log(x + sqrt(pow(x, 2.0) + 1.0)); }", "}\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)); }", AddEmulatedFunction(EOpAtanh, float1,
"float2 webgl_acosh_emu(in float2 x) { return log(x + sqrt(x + 1.0) * sqrt(x - 1.0)); }", "float webgl_atanh_emu(in float x) {\n"
"float3 webgl_acosh_emu(in float3 x) { return log(x + sqrt(x + 1.0) * sqrt(x - 1.0)); }", " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"float4 webgl_acosh_emu(in float4 x) { return log(x + sqrt(x + 1.0) * sqrt(x - 1.0)); }", "}\n");
AddEmulatedFunction(EOpAtanh, float2,
"float webgl_atanh_emu(in float x) { return 0.5 * log((1.0 + x) / (1.0 - x)); }", "float2 webgl_atanh_emu(in float2 x) {\n"
"float2 webgl_atanh_emu(in float2 x) { return 0.5 * log((1.0 + x) / (1.0 - x)); }", " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"float3 webgl_atanh_emu(in float3 x) { return 0.5 * log((1.0 + x) / (1.0 - x)); }", "}\n");
"float4 webgl_atanh_emu(in float4 x) { return 0.5 * log((1.0 + x) / (1.0 - x)); }" AddEmulatedFunction(EOpAtanh, float3,
}; "float3 webgl_atanh_emu(in float3 x) {\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
const bool kFunctionEmulationMask[] = "}\n");
{ AddEmulatedFunction(EOpAtanh, float4,
false, // TFunctionCos1 "float4 webgl_atanh_emu(in float4 x) {\n"
false, // TFunctionCos2 " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
false, // TFunctionCos3 "}\n");
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;
} }
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