• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "compiler/translator/BuiltInFunctionEmulator.h"
8 #include "angle_gl.h"
9 #include "compiler/translator/Symbol.h"
10 #include "compiler/translator/tree_util/IntermTraverse.h"
11 
12 namespace sh
13 {
14 
15 class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
16 {
17   public:
BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator & emulator)18     BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
19         : TIntermTraverser(true, false, false), mEmulator(emulator)
20     {}
21 
visitUnary(Visit visit,TIntermUnary * node)22     bool visitUnary(Visit visit, TIntermUnary *node) override
23     {
24         if (node->getFunction())
25         {
26             bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction());
27             if (needToEmulate)
28                 node->setUseEmulatedFunction();
29         }
30         return true;
31     }
32 
visitAggregate(Visit visit,TIntermAggregate * node)33     bool visitAggregate(Visit visit, TIntermAggregate *node) override
34     {
35         // Here we handle all the math built-in functions, not just the ones that are currently
36         // identified as problematic.
37         if (!BuiltInGroup::IsMath(node->getOp()))
38         {
39             return true;
40         }
41         bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction());
42         if (needToEmulate)
43             node->setUseEmulatedFunction();
44         return true;
45     }
46 
47   private:
48     BuiltInFunctionEmulator &mEmulator;
49 };
50 
BuiltInFunctionEmulator()51 BuiltInFunctionEmulator::BuiltInFunctionEmulator() {}
52 
addEmulatedFunction(const TSymbolUniqueId & uniqueId,const char * emulatedFunctionDefinition)53 void BuiltInFunctionEmulator::addEmulatedFunction(const TSymbolUniqueId &uniqueId,
54                                                   const char *emulatedFunctionDefinition)
55 {
56     mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition);
57 }
58 
addEmulatedFunctionWithDependency(const TSymbolUniqueId & dependency,const TSymbolUniqueId & uniqueId,const char * emulatedFunctionDefinition)59 void BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
60     const TSymbolUniqueId &dependency,
61     const TSymbolUniqueId &uniqueId,
62     const char *emulatedFunctionDefinition)
63 {
64     mEmulatedFunctions[uniqueId.get()]    = std::string(emulatedFunctionDefinition);
65     mFunctionDependencies[uniqueId.get()] = dependency.get();
66 }
67 
isOutputEmpty() const68 bool BuiltInFunctionEmulator::isOutputEmpty() const
69 {
70     return (mFunctions.size() == 0);
71 }
72 
outputEmulatedFunctions(TInfoSinkBase & out) const73 void BuiltInFunctionEmulator::outputEmulatedFunctions(TInfoSinkBase &out) const
74 {
75     for (const auto &function : mFunctions)
76     {
77         const char *body = findEmulatedFunction(function);
78         ASSERT(body);
79         out << body;
80         out << "\n\n";
81     }
82 }
83 
findEmulatedFunction(int uniqueId) const84 const char *BuiltInFunctionEmulator::findEmulatedFunction(int uniqueId) const
85 {
86     for (const auto &queryFunction : mQueryFunctions)
87     {
88         const char *result = queryFunction(uniqueId);
89         if (result)
90         {
91             return result;
92         }
93     }
94 
95     const auto &result = mEmulatedFunctions.find(uniqueId);
96     if (result != mEmulatedFunctions.end())
97     {
98         return result->second.c_str();
99     }
100 
101     return nullptr;
102 }
103 
setFunctionCalled(const TFunction * function)104 bool BuiltInFunctionEmulator::setFunctionCalled(const TFunction *function)
105 {
106     ASSERT(function != nullptr);
107     return setFunctionCalled(function->uniqueId().get());
108 }
109 
setFunctionCalled(int uniqueId)110 bool BuiltInFunctionEmulator::setFunctionCalled(int uniqueId)
111 {
112     if (!findEmulatedFunction(uniqueId))
113     {
114         return false;
115     }
116 
117     for (size_t i = 0; i < mFunctions.size(); ++i)
118     {
119         if (mFunctions[i] == uniqueId)
120             return true;
121     }
122     // If the function depends on another, mark the dependency as called.
123     auto dependency = mFunctionDependencies.find(uniqueId);
124     if (dependency != mFunctionDependencies.end())
125     {
126         setFunctionCalled((*dependency).second);
127     }
128     mFunctions.push_back(uniqueId);
129     return true;
130 }
131 
markBuiltInFunctionsForEmulation(TIntermNode * root)132 void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root)
133 {
134     ASSERT(root);
135 
136     if (mEmulatedFunctions.empty() && mQueryFunctions.empty())
137         return;
138 
139     BuiltInFunctionEmulationMarker marker(*this);
140     root->traverse(&marker);
141 }
142 
cleanup()143 void BuiltInFunctionEmulator::cleanup()
144 {
145     mFunctions.clear();
146     mFunctionDependencies.clear();
147 }
148 
addFunctionMap(BuiltinQueryFunc queryFunc)149 void BuiltInFunctionEmulator::addFunctionMap(BuiltinQueryFunc queryFunc)
150 {
151     mQueryFunctions.push_back(queryFunc);
152 }
153 
154 // static
WriteEmulatedFunctionName(TInfoSinkBase & out,const char * name)155 void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name)
156 {
157     ASSERT(name[strlen(name) - 1] != '(');
158     out << name << "_emu";
159 }
160 
161 }  // namespace sh
162