Add support for 4-parameter functions to BuiltInFunctionEmulator
New entry points are needed to support built-ins with more parameters.
Also, now that ops that are not function calls don't use the
TIntermAggregate class any more, it's easier to exclude nodes that are
not candidates for built-in emulation using a simple blacklist rather
than to use a whitelist.
Also includes function name style cleanup in BuiltInFunctionEmulator.
This will make it possible to add necessary emulation for built-ins
from ESSL 3.10.
BUG=angleproject:1730
TEST=angle_unittests
Change-Id: If267fc68f5cb9b2ee6703cbcbbe4d157da44a7e0
Reviewed-on: https://chromium-review.googlesource.com/431297
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/compiler/translator/BuiltInFunctionEmulator.cpp
index 57e5ba2..64f0b86 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -25,7 +25,7 @@
if (visit == PreVisit)
{
bool needToEmulate =
- mEmulator.SetFunctionCalled(node->getOp(), node->getOperand()->getType());
+ mEmulator.setFunctionCalled(node->getOp(), node->getOperand()->getType());
if (needToEmulate)
node->setUseEmulatedFunction();
}
@@ -36,36 +36,11 @@
{
if (visit == PreVisit)
{
- // Here we handle all the built-in functions instead of the ones we
+ // Here we handle all the built-in functions mapped to ops, not just the ones that are
// currently identified as problematic.
- switch (node->getOp())
+ if (node->isConstructor() || node->getOp() == EOpFunctionCall)
{
- case EOpEqualComponentWise:
- case EOpNotEqualComponentWise:
- case EOpLessThanComponentWise:
- case EOpGreaterThanComponentWise:
- case EOpLessThanEqualComponentWise:
- case EOpGreaterThanEqualComponentWise:
- case EOpMod:
- case EOpPow:
- case EOpAtan:
- case EOpMin:
- case EOpMax:
- case EOpClamp:
- case EOpMix:
- case EOpStep:
- case EOpSmoothStep:
- case EOpDistance:
- case EOpDot:
- case EOpCross:
- case EOpFaceForward:
- case EOpReflect:
- case EOpRefract:
- case EOpMulMatrixComponentWise:
- case EOpOuterProduct:
- break;
- default:
- return true;
+ return true;
}
const TIntermSequence &sequence = *(node->getSequence());
bool needToEmulate = false;
@@ -76,7 +51,7 @@
TIntermTyped *param2 = sequence[1]->getAsTyped();
if (!param1 || !param2)
return true;
- needToEmulate = mEmulator.SetFunctionCalled(node->getOp(), param1->getType(),
+ needToEmulate = mEmulator.setFunctionCalled(node->getOp(), param1->getType(),
param2->getType());
}
else if (sequence.size() == 3)
@@ -86,9 +61,21 @@
TIntermTyped *param3 = sequence[2]->getAsTyped();
if (!param1 || !param2 || !param3)
return true;
- needToEmulate = mEmulator.SetFunctionCalled(node->getOp(), param1->getType(),
+ needToEmulate = mEmulator.setFunctionCalled(node->getOp(), param1->getType(),
param2->getType(), param3->getType());
}
+ else if (sequence.size() == 4)
+ {
+ TIntermTyped *param1 = sequence[0]->getAsTyped();
+ TIntermTyped *param2 = sequence[1]->getAsTyped();
+ TIntermTyped *param3 = sequence[2]->getAsTyped();
+ TIntermTyped *param4 = sequence[3]->getAsTyped();
+ if (!param1 || !param2 || !param3 || !param4)
+ return true;
+ needToEmulate =
+ mEmulator.setFunctionCalled(node->getOp(), param1->getType(), param2->getType(),
+ param3->getType(), param4->getType());
+ }
else
{
return true;
@@ -154,12 +141,40 @@
return id;
}
-bool BuiltInFunctionEmulator::IsOutputEmpty() const
+BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction(
+ TOperator op,
+ const TType *param1,
+ const TType *param2,
+ const TType *param3,
+ const TType *param4,
+ const char *emulatedFunctionDefinition)
+{
+ FunctionId id(op, param1, param2, param3, param4);
+ mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
+ return id;
+}
+
+BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
+ FunctionId dependency,
+ TOperator op,
+ const TType *param1,
+ const TType *param2,
+ const TType *param3,
+ const TType *param4,
+ const char *emulatedFunctionDefinition)
+{
+ FunctionId id(op, param1, param2, param3, param4);
+ mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
+ mFunctionDependencies[id] = dependency;
+ return id;
+}
+
+bool BuiltInFunctionEmulator::isOutputEmpty() const
{
return (mFunctions.size() == 0);
}
-void BuiltInFunctionEmulator::OutputEmulatedFunctions(TInfoSinkBase &out) const
+void BuiltInFunctionEmulator::outputEmulatedFunctions(TInfoSinkBase &out) const
{
for (size_t i = 0; i < mFunctions.size(); ++i)
{
@@ -167,27 +182,36 @@
}
}
-bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType ¶m)
+bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op, const TType ¶m)
{
- return SetFunctionCalled(FunctionId(op, ¶m));
+ return setFunctionCalled(FunctionId(op, ¶m));
}
-bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op,
+bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op,
const TType ¶m1,
const TType ¶m2)
{
- return SetFunctionCalled(FunctionId(op, ¶m1, ¶m2));
+ return setFunctionCalled(FunctionId(op, ¶m1, ¶m2));
}
-bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op,
+bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op,
const TType ¶m1,
const TType ¶m2,
const TType ¶m3)
{
- return SetFunctionCalled(FunctionId(op, ¶m1, ¶m2, ¶m3));
+ return setFunctionCalled(FunctionId(op, ¶m1, ¶m2, ¶m3));
}
-bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId)
+bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op,
+ const TType ¶m1,
+ const TType ¶m2,
+ const TType ¶m3,
+ const TType ¶m4)
+{
+ return setFunctionCalled(FunctionId(op, ¶m1, ¶m2, ¶m3, ¶m4));
+}
+
+bool BuiltInFunctionEmulator::setFunctionCalled(const FunctionId &functionId)
{
if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end())
{
@@ -200,7 +224,7 @@
auto dependency = mFunctionDependencies.find(functionId);
if (dependency != mFunctionDependencies.end())
{
- SetFunctionCalled((*dependency).second);
+ setFunctionCalled((*dependency).second);
}
// Copy the functionId if it needs to be stored, to make sure that the TType pointers inside
// remain valid and constant.
@@ -210,7 +234,7 @@
return false;
}
-void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(TIntermNode *root)
+void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root)
{
ASSERT(root);
@@ -221,7 +245,7 @@
root->traverse(&marker);
}
-void BuiltInFunctionEmulator::Cleanup()
+void BuiltInFunctionEmulator::cleanup()
{
mFunctions.clear();
mFunctionDependencies.clear();
@@ -238,19 +262,28 @@
: mOp(EOpNull),
mParam1(TCache::getType(EbtVoid)),
mParam2(TCache::getType(EbtVoid)),
- mParam3(TCache::getType(EbtVoid))
+ mParam3(TCache::getType(EbtVoid)),
+ mParam4(TCache::getType(EbtVoid))
{
}
BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param)
- : mOp(op), mParam1(param), mParam2(TCache::getType(EbtVoid)), mParam3(TCache::getType(EbtVoid))
+ : mOp(op),
+ mParam1(param),
+ mParam2(TCache::getType(EbtVoid)),
+ mParam3(TCache::getType(EbtVoid)),
+ mParam4(TCache::getType(EbtVoid))
{
}
BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op,
const TType *param1,
const TType *param2)
- : mOp(op), mParam1(param1), mParam2(param2), mParam3(TCache::getType(EbtVoid))
+ : mOp(op),
+ mParam1(param1),
+ mParam2(param2),
+ mParam3(TCache::getType(EbtVoid)),
+ mParam4(TCache::getType(EbtVoid))
{
}
@@ -258,7 +291,16 @@
const TType *param1,
const TType *param2,
const TType *param3)
- : mOp(op), mParam1(param1), mParam2(param2), mParam3(param3)
+ : mOp(op), mParam1(param1), mParam2(param2), mParam3(param3), mParam4(TCache::getType(EbtVoid))
+{
+}
+
+BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op,
+ const TType *param1,
+ const TType *param2,
+ const TType *param3,
+ const TType *param4)
+ : mOp(op), mParam1(param1), mParam2(param2), mParam3(param3), mParam4(param4)
{
}
@@ -266,7 +308,7 @@
const BuiltInFunctionEmulator::FunctionId &other) const
{
return (mOp == other.mOp && *mParam1 == *other.mParam1 && *mParam2 == *other.mParam2 &&
- *mParam3 == *other.mParam3);
+ *mParam3 == *other.mParam3 && *mParam4 == *other.mParam4);
}
bool BuiltInFunctionEmulator::FunctionId::operator<(
@@ -280,12 +322,15 @@
return *mParam2 < *other.mParam2;
if (*mParam3 != *other.mParam3)
return *mParam3 < *other.mParam3;
+ if (*mParam4 != *other.mParam4)
+ return *mParam4 < *other.mParam4;
return false; // all fields are equal
}
BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::FunctionId::getCopy() const
{
- return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3));
+ return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3),
+ new TType(*mParam4));
}
} // namespace sh
diff --git a/src/compiler/translator/BuiltInFunctionEmulator.h b/src/compiler/translator/BuiltInFunctionEmulator.h
index 620fd89..cbb1b25 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.h
+++ b/src/compiler/translator/BuiltInFunctionEmulator.h
@@ -23,17 +23,17 @@
public:
BuiltInFunctionEmulator();
- void MarkBuiltInFunctionsForEmulation(TIntermNode *root);
+ void markBuiltInFunctionsForEmulation(TIntermNode *root);
- void Cleanup();
+ void cleanup();
// "name" gets written as "webgl_name_emu".
static void WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name);
- bool IsOutputEmpty() const;
+ bool isOutputEmpty() const;
// Output function emulation definition. This should be before any other shader source.
- void OutputEmulatedFunctions(TInfoSinkBase &out) const;
+ void outputEmulatedFunctions(TInfoSinkBase &out) const;
class FunctionId
{
@@ -42,6 +42,11 @@
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);
+ FunctionId(TOperator op,
+ const TType *param1,
+ const TType *param2,
+ const TType *param3,
+ const TType *param4);
FunctionId(const FunctionId &) = default;
FunctionId &operator=(const FunctionId &) = default;
@@ -60,6 +65,7 @@
const TType *mParam1;
const TType *mParam2;
const TType *mParam3;
+ const TType *mParam4;
};
// Add functions that need to be emulated.
@@ -75,12 +81,25 @@
const TType *param2,
const TType *param3,
const char *emulatedFunctionDefinition);
+ FunctionId addEmulatedFunction(TOperator op,
+ const TType *param1,
+ const TType *param2,
+ const TType *param3,
+ const TType *param4,
+ const char *emulatedFunctionDefinition);
FunctionId addEmulatedFunctionWithDependency(FunctionId dependency,
TOperator op,
const TType *param1,
const TType *param2,
const char *emulatedFunctionDefinition);
+ FunctionId addEmulatedFunctionWithDependency(FunctionId dependency,
+ TOperator op,
+ const TType *param1,
+ const TType *param2,
+ const TType *param3,
+ const TType *param4,
+ const char *emulatedFunctionDefinition);
private:
class BuiltInFunctionEmulationMarker;
@@ -88,14 +107,19 @@
// Records that a function is called by the shader and might need to be 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 ¶m);
- bool SetFunctionCalled(TOperator op, const TType ¶m1, const TType ¶m2);
- bool SetFunctionCalled(TOperator op,
+ bool setFunctionCalled(TOperator op, const TType ¶m);
+ bool setFunctionCalled(TOperator op, const TType ¶m1, const TType ¶m2);
+ bool setFunctionCalled(TOperator op,
const TType ¶m1,
const TType ¶m2,
const TType ¶m3);
+ bool setFunctionCalled(TOperator op,
+ const TType ¶m1,
+ const TType ¶m2,
+ const TType ¶m3,
+ const TType ¶m4);
- bool SetFunctionCalled(const FunctionId &functionId);
+ bool setFunctionCalled(const FunctionId &functionId);
// Map from function id to emulated function definition
std::map<FunctionId, std::string> mEmulatedFunctions;
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 6c3518d..3c2a975 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -394,7 +394,7 @@
GetGlobalPoolAllocator()->lock();
initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions);
GetGlobalPoolAllocator()->unlock();
- builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
+ builtInFunctionEmulator.markBuiltInFunctionsForEmulation(root);
}
// Clamping uniform array bounds needs to happen after validateLimitations pass.
@@ -670,7 +670,7 @@
mNumViews = -1;
- builtInFunctionEmulator.Cleanup();
+ builtInFunctionEmulator.cleanup();
nameMap.clear();
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 1ce25cf..61ea424 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -178,7 +178,7 @@
mShaderVersion);
}
- builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot);
+ builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
// Now that we are done changing the AST, do the analyses need for HLSL generation
CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
@@ -201,7 +201,7 @@
objSink << mBody.c_str();
objSink << mFooter.c_str();
- builtInFunctionEmulator.Cleanup();
+ builtInFunctionEmulator.cleanup();
}
void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
@@ -739,7 +739,7 @@
"\n";
}
- builtInFunctionEmulator->OutputEmulatedFunctions(out);
+ builtInFunctionEmulator->outputEmulatedFunctions(out);
}
void OutputHLSL::visitSymbol(TIntermSymbol *node)
diff --git a/src/compiler/translator/TranslatorESSL.cpp b/src/compiler/translator/TranslatorESSL.cpp
index 5447879..1e95638 100644
--- a/src/compiler/translator/TranslatorESSL.cpp
+++ b/src/compiler/translator/TranslatorESSL.cpp
@@ -60,7 +60,7 @@
RecordConstantPrecision(root, getTemporaryIndex());
// Write emulated built-in functions if needed.
- if (!getBuiltInFunctionEmulator().IsOutputEmpty())
+ if (!getBuiltInFunctionEmulator().isOutputEmpty())
{
sink << "// BEGIN: Generated code for built-in function emulation\n\n";
if (getShaderType() == GL_FRAGMENT_SHADER)
@@ -76,7 +76,7 @@
sink << "#define webgl_emu_precision highp\n";
}
- getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink);
+ getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
sink << "// END: Generated code for built-in function emulation\n\n";
}
diff --git a/src/compiler/translator/TranslatorGLSL.cpp b/src/compiler/translator/TranslatorGLSL.cpp
index 1946149..253a579 100644
--- a/src/compiler/translator/TranslatorGLSL.cpp
+++ b/src/compiler/translator/TranslatorGLSL.cpp
@@ -114,11 +114,11 @@
}
// Write emulated built-in functions if needed.
- if (!getBuiltInFunctionEmulator().IsOutputEmpty())
+ if (!getBuiltInFunctionEmulator().isOutputEmpty())
{
sink << "// BEGIN: Generated code for built-in function emulation\n\n";
sink << "#define webgl_emu_precision\n\n";
- getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink);
+ getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
sink << "// END: Generated code for built-in function emulation\n\n";
}