Commit dfa75e87 by Olli Etuaho Committed by Commit Bot

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: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 01d0ad08
......@@ -25,7 +25,7 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr
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 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr
{
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 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr
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 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr
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 @@ BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction
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 @@ void BuiltInFunctionEmulator::OutputEmulatedFunctions(TInfoSinkBase &out) const
}
}
bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType &param)
bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op, const TType &param)
{
return SetFunctionCalled(FunctionId(op, &param));
return setFunctionCalled(FunctionId(op, &param));
}
bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op,
bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op,
const TType &param1,
const TType &param2)
{
return SetFunctionCalled(FunctionId(op, &param1, &param2));
return setFunctionCalled(FunctionId(op, &param1, &param2));
}
bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op,
bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op,
const TType &param1,
const TType &param2,
const TType &param3)
{
return SetFunctionCalled(FunctionId(op, &param1, &param2, &param3));
return setFunctionCalled(FunctionId(op, &param1, &param2, &param3));
}
bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op,
const TType &param1,
const TType &param2,
const TType &param3,
const TType &param4)
{
return setFunctionCalled(FunctionId(op, &param1, &param2, &param3, &param4));
}
bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId)
bool BuiltInFunctionEmulator::setFunctionCalled(const FunctionId &functionId)
{
if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end())
{
......@@ -200,7 +224,7 @@ bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId)
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 @@ bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId)
return false;
}
void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(TIntermNode *root)
void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root)
{
ASSERT(root);
......@@ -221,7 +245,7 @@ void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(TIntermNode *root
root->traverse(&marker);
}
void BuiltInFunctionEmulator::Cleanup()
void BuiltInFunctionEmulator::cleanup()
{
mFunctions.clear();
mFunctionDependencies.clear();
......@@ -238,19 +262,28 @@ BuiltInFunctionEmulator::FunctionId::FunctionId()
: 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 @@ BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op,
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 @@ bool BuiltInFunctionEmulator::FunctionId::operator==(
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 @@ bool BuiltInFunctionEmulator::FunctionId::operator<(
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
......@@ -23,17 +23,17 @@ class BuiltInFunctionEmulator
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 @@ class BuiltInFunctionEmulator
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 @@ class BuiltInFunctionEmulator
const TType *mParam1;
const TType *mParam2;
const TType *mParam3;
const TType *mParam4;
};
// Add functions that need to be emulated.
......@@ -75,12 +81,25 @@ class BuiltInFunctionEmulator
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 @@ class BuiltInFunctionEmulator
// 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 &param);
bool SetFunctionCalled(TOperator op, const TType &param1, const TType &param2);
bool SetFunctionCalled(TOperator op,
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);
bool setFunctionCalled(TOperator op,
const TType &param1,
const TType &param2,
const TType &param3,
const TType &param4);
bool SetFunctionCalled(const FunctionId &functionId);
bool setFunctionCalled(const FunctionId &functionId);
// Map from function id to emulated function definition
std::map<FunctionId, std::string> mEmulatedFunctions;
......
......@@ -394,7 +394,7 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
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 @@ void TCompiler::clearResults()
mNumViews = -1;
builtInFunctionEmulator.Cleanup();
builtInFunctionEmulator.cleanup();
nameMap.clear();
......
......@@ -178,7 +178,7 @@ void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
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 @@ void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
objSink << mBody.c_str();
objSink << mFooter.c_str();
builtInFunctionEmulator.Cleanup();
builtInFunctionEmulator.cleanup();
}
void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
......@@ -739,7 +739,7 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
"\n";
}
builtInFunctionEmulator->OutputEmulatedFunctions(out);
builtInFunctionEmulator->outputEmulatedFunctions(out);
}
void OutputHLSL::visitSymbol(TIntermSymbol *node)
......
......@@ -60,7 +60,7 @@ void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOption
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 @@ void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOption
sink << "#define webgl_emu_precision highp\n";
}
getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink);
getBuiltInFunctionEmulator().outputEmulatedFunctions(sink);
sink << "// END: Generated code for built-in function emulation\n\n";
}
......
......@@ -114,11 +114,11 @@ void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOption
}
// 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";
}
......
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