summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp161
1 files changed, 161 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp
new file mode 100644
index 0000000000..34b43365cf
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -0,0 +1,161 @@
+//
+// Copyright 2002 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 "compiler/translator/BuiltInFunctionEmulator.h"
+#include "angle_gl.h"
+#include "compiler/translator/Symbol.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
+{
+ public:
+ BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
+ : TIntermTraverser(true, false, false), mEmulator(emulator)
+ {}
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override
+ {
+ if (node->getFunction())
+ {
+ bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ }
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ // Here we handle all the math built-in functions, not just the ones that are currently
+ // identified as problematic.
+ if (!BuiltInGroup::IsMath(node->getOp()))
+ {
+ return true;
+ }
+ bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ return true;
+ }
+
+ private:
+ BuiltInFunctionEmulator &mEmulator;
+};
+
+BuiltInFunctionEmulator::BuiltInFunctionEmulator() {}
+
+void BuiltInFunctionEmulator::addEmulatedFunction(const TSymbolUniqueId &uniqueId,
+ const char *emulatedFunctionDefinition)
+{
+ mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition);
+}
+
+void BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
+ const TSymbolUniqueId &dependency,
+ const TSymbolUniqueId &uniqueId,
+ const char *emulatedFunctionDefinition)
+{
+ mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition);
+ mFunctionDependencies[uniqueId.get()] = dependency.get();
+}
+
+bool BuiltInFunctionEmulator::isOutputEmpty() const
+{
+ return (mFunctions.size() == 0);
+}
+
+void BuiltInFunctionEmulator::outputEmulatedFunctions(TInfoSinkBase &out) const
+{
+ for (const auto &function : mFunctions)
+ {
+ const char *body = findEmulatedFunction(function);
+ ASSERT(body);
+ out << body;
+ out << "\n\n";
+ }
+}
+
+const char *BuiltInFunctionEmulator::findEmulatedFunction(int uniqueId) const
+{
+ for (const auto &queryFunction : mQueryFunctions)
+ {
+ const char *result = queryFunction(uniqueId);
+ if (result)
+ {
+ return result;
+ }
+ }
+
+ const auto &result = mEmulatedFunctions.find(uniqueId);
+ if (result != mEmulatedFunctions.end())
+ {
+ return result->second.c_str();
+ }
+
+ return nullptr;
+}
+
+bool BuiltInFunctionEmulator::setFunctionCalled(const TFunction *function)
+{
+ ASSERT(function != nullptr);
+ return setFunctionCalled(function->uniqueId().get());
+}
+
+bool BuiltInFunctionEmulator::setFunctionCalled(int uniqueId)
+{
+ if (!findEmulatedFunction(uniqueId))
+ {
+ return false;
+ }
+
+ for (size_t i = 0; i < mFunctions.size(); ++i)
+ {
+ if (mFunctions[i] == uniqueId)
+ return true;
+ }
+ // If the function depends on another, mark the dependency as called.
+ auto dependency = mFunctionDependencies.find(uniqueId);
+ if (dependency != mFunctionDependencies.end())
+ {
+ setFunctionCalled((*dependency).second);
+ }
+ mFunctions.push_back(uniqueId);
+ return true;
+}
+
+void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root)
+{
+ ASSERT(root);
+
+ if (mEmulatedFunctions.empty() && mQueryFunctions.empty())
+ return;
+
+ BuiltInFunctionEmulationMarker marker(*this);
+ root->traverse(&marker);
+}
+
+void BuiltInFunctionEmulator::cleanup()
+{
+ mFunctions.clear();
+ mFunctionDependencies.clear();
+}
+
+void BuiltInFunctionEmulator::addFunctionMap(BuiltinQueryFunc queryFunc)
+{
+ mQueryFunctions.push_back(queryFunc);
+}
+
+// static
+void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name)
+{
+ ASSERT(name[strlen(name) - 1] != '(');
+ out << name << "_emu";
+}
+
+} // namespace sh